YamlLibraryFactory::buildReleases()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gnutix\Library\LibraryFactory;
6
7
use DateTime;
8
use Gnutix\Library\Dumper\YamlLibraryDumper;
9
use Gnutix\Library\LibraryFactoryInterface;
10
use Gnutix\Library\LibraryInterface;
11
use Gnutix\Library\Loader\YamlFileLoader;
12
13
class YamlLibraryFactory implements LibraryFactoryInterface
14
{
15
    protected array $classes;
16
    private LibraryInterface $library;
17
18
    public function __construct(YamlFileLoader $loader, array $classes)
19
    {
20
        $this->classes = $classes;
21
        $this->library = new $this->classes['library']($this->getLibraryDependencies($loader->getData()));
22
    }
23
24
    public function getLibrary(): LibraryInterface
25
    {
26
        return $this->library;
27
    }
28
29
    public function getLibraryDumper(): YamlLibraryDumper
30
    {
31
        return new YamlLibraryDumper();
32
    }
33
34
    protected function getLibraryDependencies(array $data): array
35
    {
36
        return [
37
            'books' => $this->buildBooks($this->get($data, 'books', [])),
38
            'categories' => $this->buildClassInstanceFromArray($this->get($data, 'categories', []), 'category'),
39
            'editors' => $this->buildClassInstanceFromArray($this->get($data, 'editors', []), 'editor'),
40
        ];
41
    }
42
43
    protected function buildClassInstanceFromArray(array $data, string $targetClass, array $renameKeys = []): array
44
    {
45
        $elements = [];
46
        $className = $this->classes[$targetClass];
47
48
        foreach ($data as $element) {
49
            $elements[] = new $className($this->renameArrayKeys($element, $renameKeys));
50
        }
51
52
        return $elements;
53
    }
54
55
    protected function buildBooks(array $books): array
56
    {
57
        $booksObjects = [];
58
59
        foreach ($books as $book) {
60
            $booksObjects[] = new $this->classes['book']($this->getBookDependencies($book));
61
        }
62
63
        return $booksObjects;
64
    }
65
66
    protected function getBookDependencies(array $book): array
67
    {
68
        return [
69
            'category' => new $this->classes['category']($this->get($book, 'category', [])),
70
            'authors' => $this->buildAuthors($book),
71
            'releases' => $this->buildReleases($this->get($book, 'releases', [])),
72
        ];
73
    }
74
75
    protected function buildAuthors(array $book): array
76
    {
77
        $authorsObjects = [];
78
79
        if (null !== $author = $this->get($book, 'author')) {
80
            $book['authors'][] = $author;
81
            unset($book['author']);
82
        }
83
84
        foreach ($this->get($book, 'authors') as $author) {
85
            $authorsObjects[] = new $this->classes['author']($author);
86
        }
87
88
        return $authorsObjects;
89
    }
90
91
    protected function buildReleases(array $releases): array
92
    {
93
        $releasesObjects = [];
94
95
        foreach ($releases as $release) {
96
            $releasesObjects[] = new $this->classes['release']($this->buildReleaseDependencies($release));
97
        }
98
99
        return $releasesObjects;
100
    }
101
102
    protected function buildReleaseDependencies(array $release): array
103
    {
104
        return [
105
            'title' => $this->get($release, 'title'),
106
            'language' => new $this->classes['language']($this->get($release, 'language', [])),
107
            'editor' => new $this->classes['editor']($this->get($release, 'editor', [])),
108
            'format' => new $this->classes['format']($this->get($release, 'format', [])),
109
            'publicationDate' => $this->get(
110
                $release,
111
                'publicationDate',
112
                null,
113
                function ($data) {
114
                    return $this->transformToDateTime($data);
115
                }
116
            ),
117
            'series' => new $this->classes['series'](
118
                $this->get(
119
                    $release,
120
                    'series',
121
                    [],
122
                    function ($data) {
123
                        return $this->renameArrayKeys($data, ['number' => 'bookId']);
124
                    }
125
                )
126
            ),
127
            'owner' => new $this->classes['owner'](
128
                $this->get(
129
                    $release,
130
                    'owner',
131
                    [],
132
                    function ($data) {
133
                        return $this->renameArrayKeys($data, ['copies' => 'nbCopies', 'readings' => 'nbReadings']);
134
                    }
135
                )
136
            ),
137
        ];
138
    }
139
140
    /**
141
     * @param mixed|null $default
142
     *
143
     * @return mixed
144
     */
145
    protected function get(
146
        array $data,
147
        string $index,
148
        $default = null,
149
        ?callable $callback = null,
150
        bool $throwException = false
151
    ) {
152
        if (isset($data[$index])) {
153
            if (is_callable($callback)) {
154
                return $callback($data[$index]);
155
            }
156
157
            return $data[$index];
158
        }
159
160
        if (!$throwException) {
161
            return $default;
162
        }
163
164
        throw new \InvalidArgumentException('Index "'.$index.'" could not be found.');
165
    }
166
167
    protected function transformToDateTime(array $date): DateTime
168
    {
169
        foreach (['day', 'month', 'year'] as $key) {
170
            if (!isset($date[$key])) {
171
                $date[$key] = 0;
172
            }
173
        }
174
175
        $dateTime = new DateTime();
176
177
        return $dateTime->setDate($date['year'], $date['month'], $date['day']);
178
    }
179
180
    protected function renameArrayKeys(array $data, array $keys): array
181
    {
182
        foreach ($keys as $old => $new) {
183
            // PS: do not use isset as the value may be null
184
            if (!array_key_exists($old, $data)) {
185
                continue;
186
            }
187
188
            $data[$new] = $data[$old];
189
            unset($data[$old]);
190
        }
191
192
        return $data;
193
    }
194
}
195