Passed
Push — master ( 19e483...625e7f )
by Mathieu
04:13
created

JsonImporter::convertObjectsToArray()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 6
nop 1
dl 0
loc 15
ccs 7
cts 8
cp 0.875
crap 4.0312
rs 10
c 0
b 0
f 0
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\Str;
9
use MathieuTu\JsonSyncer\Contracts\JsonImportable;
10
use MathieuTu\JsonSyncer\Exceptions\JsonDecodingException;
11
use MathieuTu\JsonSyncer\Exceptions\UnknownAttributeException;
12
13
class JsonImporter
14
{
15
    private $importable;
16
17 15
    public function __construct(JsonImportable $importable)
18
    {
19 15
        $this->importable = $importable;
20 15
    }
21
22 15
    public static function importFromJson(JsonImportable $importable, $objects)
23
    {
24 15
        (new static($importable))->import($objects);
25 13
    }
26
27 15
    public function import($objects)
28
    {
29 15
        $objects = $this->convertObjectsToArray($objects);
30
31 14
        foreach ($objects as $attributes) {
32 14
            $object = $this->importAttributes($attributes);
33 13
            $this->importRelations($object, $attributes);
34
        }
35 13
    }
36
37 15
    protected function convertObjectsToArray($objects): array
38
    {
39 15
        if (is_string($objects)) {
40 3
            $objects = json_decode($objects, true);
41
        }
42
43 15
        if (json_last_error() !== JSON_ERROR_NONE) {
44 1
            throw new JsonDecodingException('Invalid json format.');
45
        }
46
47 14
        if ($objects instanceof \Illuminate\Contracts\Support\Arrayable) {
48
            $objects = $objects->toArray();
49
        }
50
51 14
        return $this->wrap((array) $objects);
52
    }
53
54 14
    protected function wrap(array $objects): array
55
    {
56 14
        return empty($objects) || is_array(reset($objects)) ? $objects : [$objects];
57
    }
58
59 14
    protected function importAttributes($attributes): JsonImportable
60
    {
61 14
        $attributes = array_only($attributes, $this->importable->getJsonImportableAttributes());
62
63 14
        return $this->importable instanceof Model ? $object = $this->importable->create($attributes) : $this->importable;
0 ignored issues
show
Unused Code introduced by
The assignment to $object is dead and can be removed.
Loading history...
64
    }
65
66 13
    protected function importRelations($object, $attributes)
67
    {
68 13
        $relationsNames = array_intersect(array_keys($attributes), $this->importable->getJsonImportableRelations());
69
70 13
        foreach ($relationsNames as $relationName) {
71 13
            $children = $this->convertObjectsToArray($attributes[$relationName]);
72 13
            $relation = $this->getRelationObject($object, $relationName);
73
74 13
            $this->importChildrenIfImportable($relation, $children);
75
        }
76 13
    }
77
78 13
    protected function importChildrenIfImportable(HasOneOrMany $relation, array $children)
79
    {
80 13
        $childClass = $relation->getRelated();
81 13
        if ($childClass instanceof JsonImportable) {
82 12
            $children = $this->addParentKeyToChildren($children, $relation);
83
84 12
            $childClass->importFromJson($children);
85
        }
86 13
    }
87
88
    protected function addParentKeyToChildren(array $children, HasOneOrMany $relation): array
89
    {
90 12
        return array_map(function ($object) use ($relation) {
91 10
            $object[$relation->getForeignKeyName()] = $relation->getParentKey();
92
93 10
            return $object;
94 12
        }, $children);
95
    }
96
97 13
    protected function getRelationObject($object, $relationName): HasOneOrMany
98
    {
99 13
        $relationName = Str::camel($relationName);
100
101
        try {
102 13
            $relation = $object->$relationName();
103
104 13
            if (!$relation instanceof HasOneOrMany) {
105 1
                throw new BadMethodCallException();
106
            }
107
108 13
            return $relation;
109 2
        } catch (BadMethodCallException $e) {
110 2
            $class = get_class($object);
111
112 2
            throw new UnknownAttributeException("Unknown attribute or HasOneorMany relation '$relationName' in '$class'.");
113
        }
114
    }
115
}
116