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

JsonImporter   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 40
dl 0
loc 100
ccs 51
cts 51
cp 1
rs 10
c 0
b 0
f 0
wmc 21

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getRelationObject() 0 16 3
A import() 0 7 2
A addParentKeyToChildren() 0 7 1
A importChildrenIfImportable() 0 7 2
A importRelations() 0 9 2
A importAttributes() 0 5 2
A wrap() 0 3 3
A __construct() 0 3 1
A importFromJson() 0 3 1
A convertObjectsToArray() 0 15 4
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