1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6declare(strict_types=1);
7
8namespace App\Models\Store;
9
10use Illuminate\Contracts\Database\Eloquent\Castable;
11use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
12use InvalidArgumentException;
13use JsonSerializable;
14
15abstract class ExtraDataBase implements Castable, JsonSerializable
16{
17 const TYPE = '';
18
19 public static function castUsing(array $arguments)
20 {
21 return new class implements CastsAttributes
22 {
23 public function get($model, $key, $value, $attributes)
24 {
25 if (!($model instanceof OrderItem)) {
26 throw new InvalidArgumentException('model must be OrderItem');
27 }
28
29 $dataJson = json_decode($value ?? '', true) ?? [];
30
31 return ExtraDataBase::toExtraDataClass($dataJson);
32 }
33
34 public function set($model, $key, $value, $attributes)
35 {
36 if (!($model instanceof OrderItem)) {
37 throw new InvalidArgumentException('model must be OrderItem');
38 }
39
40 if ($value !== null && !($value instanceof ExtraDataBase)) {
41 $value = ExtraDataBase::toExtraDataClass($value);
42 }
43
44 return [$key => $value !== null ? json_encode($value) : null];
45 }
46 };
47 }
48
49 public static function toExtraDataClass(array $data)
50 {
51 // avoid using data from the model, they might not be set when this is called.
52 $type = $data['type'] ?? static::guessType($data);
53
54 return match ($type) {
55 ExtraDataSupporterTag::TYPE => new ExtraDataSupporterTag($data),
56 ExtraDataTournamentBanner::TYPE => new ExtraDataTournamentBanner($data),
57 default => null,
58 };
59 }
60
61 private static function guessType(array $data)
62 {
63 if (isset($data['target_id']) && isset($data['duration'])) {
64 return ExtraDataSupporterTag::TYPE;
65 }
66
67 // we know it's some kind of tournament...just not which one
68 if (isset($data['tournament_id']) && isset($data['cc'])) {
69 return ExtraDataTournamentBanner::TYPE;
70 }
71
72 return null;
73 }
74
75 public function jsonSerialize(): array
76 {
77 return ['type' => static::TYPE];
78 }
79}