1 | <?php |
||
2 | |||
3 | namespace MathieuTu\JsonSyncer\Helpers; |
||
4 | |||
5 | use BadMethodCallException; |
||
6 | use Illuminate\Database\Eloquent\Model; |
||
7 | use Illuminate\Database\Eloquent\Relations\HasOneOrMany; |
||
8 | use Illuminate\Support\Arr; |
||
9 | use Illuminate\Support\Str; |
||
10 | use MathieuTu\JsonSyncer\Contracts\JsonImportable; |
||
11 | use MathieuTu\JsonSyncer\Exceptions\UnknownAttributeException; |
||
12 | |||
13 | class JsonImporter |
||
14 | { |
||
15 | private JsonImportable $importable; |
||
16 | |||
17 | 16 | public function __construct(JsonImportable $importable) |
|
18 | { |
||
19 | 16 | $this->importable = $importable; |
|
20 | 16 | } |
|
21 | |||
22 | 16 | public static function importFromJson(JsonImportable $importable, $objects): void |
|
23 | { |
||
24 | 16 | (new static($importable))->import($objects); |
|
25 | 14 | } |
|
26 | |||
27 | 16 | public function import($objects): void |
|
28 | { |
||
29 | 16 | $objects = $this->convertObjectsToArray($objects); |
|
30 | |||
31 | 15 | foreach ($objects as $attributes) { |
|
32 | 15 | $object = $this->importAttributes($attributes); |
|
33 | 14 | $this->importRelations($object, $attributes); |
|
34 | } |
||
35 | 14 | } |
|
36 | |||
37 | 16 | protected function convertObjectsToArray($objects): array |
|
38 | { |
||
39 | 16 | if (is_string($objects)) { |
|
40 | 3 | $objects = json_decode($objects, true, 512, JSON_THROW_ON_ERROR); |
|
41 | } |
||
42 | |||
43 | 15 | if (is_object($objects) && method_exists($objects, 'toArray')) { |
|
44 | 1 | $objects = $objects->toArray(); |
|
45 | } |
||
46 | |||
47 | 15 | return $this->wrap((array)$objects); |
|
48 | } |
||
49 | |||
50 | 15 | protected function wrap(array $objects): array |
|
51 | { |
||
52 | 15 | return (empty($objects) || is_array(reset($objects))) ? $objects : [$objects]; |
|
53 | } |
||
54 | |||
55 | 15 | protected function importAttributes($attributes): JsonImportable |
|
56 | { |
||
57 | 15 | $attributes = Arr::only($attributes, $this->importable->getJsonImportableAttributes()); |
|
58 | |||
59 | 15 | return $this->importable instanceof Model ? $this->importable->create($attributes) : $this->importable; |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
60 | } |
||
61 | |||
62 | 14 | protected function importRelations($object, $attributes): void |
|
63 | { |
||
64 | 14 | $relationsNames = array_intersect(array_keys($attributes), $this->importable->getJsonImportableRelations()); |
|
65 | |||
66 | 14 | foreach ($relationsNames as $relationName) { |
|
67 | 14 | $children = $this->convertObjectsToArray($attributes[$relationName]); |
|
68 | 14 | $relation = $this->getRelationObject($object, $relationName); |
|
69 | |||
70 | 14 | $this->importChildrenIfImportable($relation, $children); |
|
71 | } |
||
72 | 14 | } |
|
73 | |||
74 | 14 | protected function importChildrenIfImportable(HasOneOrMany $relation, array $children): void |
|
75 | { |
||
76 | 14 | $childClass = $relation->getRelated(); |
|
77 | 14 | if ($childClass instanceof JsonImportable) { |
|
78 | 13 | $children = $this->addParentKeyToChildren($children, $relation); |
|
79 | |||
80 | 13 | $childClass->importFromJson($children); |
|
81 | } |
||
82 | 14 | } |
|
83 | |||
84 | 13 | protected function addParentKeyToChildren(array $children, HasOneOrMany $relation): array |
|
85 | { |
||
86 | 13 | return array_map(function ($object) use ($relation) { |
|
87 | 11 | $object[$relation->getForeignKeyName()] = $relation->getParentKey(); |
|
88 | |||
89 | 11 | return $object; |
|
90 | 13 | }, $children); |
|
91 | } |
||
92 | |||
93 | 14 | protected function getRelationObject($object, $relationName): HasOneOrMany |
|
94 | { |
||
95 | 14 | $relationName = Str::camel($relationName); |
|
96 | |||
97 | try { |
||
98 | 14 | $relation = $object->$relationName(); |
|
99 | |||
100 | 14 | if (!$relation instanceof HasOneOrMany) { |
|
101 | 1 | throw new BadMethodCallException(); |
|
102 | } |
||
103 | |||
104 | 14 | return $relation; |
|
105 | 2 | } catch (BadMethodCallException $e) { |
|
106 | 2 | $class = get_class($object); |
|
107 | |||
108 | 2 | throw new UnknownAttributeException("Unknown attribute or HasOneorMany relation '$relationName' in '$class'."); |
|
109 | } |
||
110 | } |
||
111 | } |
||
112 |