Passed
Push — master ( 625e7f...d214cd )
by Mathieu
02:09
created

JsonImporter::addParentKeyToChildren()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
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 16
    public function __construct(JsonImportable $importable)
18
    {
19 16
        $this->importable = $importable;
20 16
    }
21
22 16
    public static function importFromJson(JsonImportable $importable, $objects)
23
    {
24 16
        (new static($importable))->import($objects);
25 14
    }
26
27 16
    public function import($objects)
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);
41
        }
42
43 16
        if (json_last_error() !== JSON_ERROR_NONE) {
44 1
            throw new JsonDecodingException('Invalid json format.');
45
        }
46
47 15
        if ($objects instanceof \Illuminate\Contracts\Support\Arrayable) {
48 1
            $objects = $objects->toArray();
49
        }
50
51 15
        return $this->wrap((array) $objects);
52
    }
53
54 15
    protected function wrap(array $objects): array
55
    {
56 15
        return empty($objects) || is_array(reset($objects)) ? $objects : [$objects];
57
    }
58
59 15
    protected function importAttributes($attributes): JsonImportable
60
    {
61 15
        $attributes = array_only($attributes, $this->importable->getJsonImportableAttributes());
62
63 15
        return $this->importable instanceof Model ?  $this->importable->create($attributes) : $this->importable;
64
    }
65
66 14
    protected function importRelations($object, $attributes)
67
    {
68 14
        $relationsNames = array_intersect(array_keys($attributes), $this->importable->getJsonImportableRelations());
69
70 14
        foreach ($relationsNames as $relationName) {
71 14
            $children = $this->convertObjectsToArray($attributes[$relationName]);
72 14
            $relation = $this->getRelationObject($object, $relationName);
73
74 14
            $this->importChildrenIfImportable($relation, $children);
75
        }
76 14
    }
77
78 14
    protected function importChildrenIfImportable(HasOneOrMany $relation, array $children)
79
    {
80 14
        $childClass = $relation->getRelated();
81 14
        if ($childClass instanceof JsonImportable) {
82 13
            $children = $this->addParentKeyToChildren($children, $relation);
83
84 13
            $childClass->importFromJson($children);
85
        }
86 14
    }
87
88
    protected function addParentKeyToChildren(array $children, HasOneOrMany $relation): array
89
    {
90 13
        return array_map(function ($object) use ($relation) {
91 11
            $object[$relation->getForeignKeyName()] = $relation->getParentKey();
92
93 11
            return $object;
94 13
        }, $children);
95
    }
96
97 14
    protected function getRelationObject($object, $relationName): HasOneOrMany
98
    {
99 14
        $relationName = Str::camel($relationName);
100
101
        try {
102 14
            $relation = $object->$relationName();
103
104 14
            if (!$relation instanceof HasOneOrMany) {
105 1
                throw new BadMethodCallException();
106
            }
107
108 14
            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