Completed
Push — master ( 866487...6bcace )
by Dorian
04:50
created

YamlLibraryFactory::buildAuthors()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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