Completed
Push — master ( 654c5d...c6e087 )
by Dorian
02:15
created

XmlLibraryFactory::transformToDateTime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
3
namespace Gnutix\Library\LibraryFactory;
4
5
use Gnutix\Library\Dumper\YamlLibraryDumper;
6
use Gnutix\Library\Loader\XmlFileLoader;
7
use Gnutix\Library\LibraryFactoryInterface;
8
9
/**
10
 * Library Factory for the XML data
11
 */
12
class XmlLibraryFactory implements LibraryFactoryInterface
13
{
14
    /** @var array */
15
    protected $classes;
16
17
    /** @var \Gnutix\Library\LibraryInterface */
18
    protected $library;
19
20
    /**
21
     * @param \Gnutix\Library\Loader\XmlFileLoader $loader
22
     * @param array                                $classes
23
     */
24
    public function __construct(XmlFileLoader $loader, $classes)
25
    {
26
        $this->classes = $classes;
27
        $this->library = new $this->classes['library']($this->getLibraryDependencies($loader->getData()));
28
    }
29
30
    /**
31
     * {@inheritDoc}
32
     */
33
    public function getLibrary()
34
    {
35
        return $this->library;
36
    }
37
38
    /**
39
     * @param \SimpleXMLElement $data
40
     *
41
     * @return array
42
     */
43
    protected function getLibraryDependencies(\SimpleXMLElement $data)
44
    {
45
        return array(
46
            'books' => $this->buildBooks($data),
47
            'categories' => $this->buildClassInstanceFromNodeAttributes(
48
                $data,
49
                '//information/types/type',
50
                'category',
51
                array('code' => 'id')
52
            ),
53
            'editors' => $this->buildClassInstanceFromNodeAttributes(
54
                $data,
55
                '//information/editors/editor',
56
                'editor',
57
                array('code' => 'id', 'lang' => 'preferredLanguage')
58
            ),
59
        );
60
    }
61
62
    /**
63
     * @return \Gnutix\Library\Dumper\YamlLibraryDumper
64
     */
65
    public function getLibraryDumper()
66
    {
67
        return new YamlLibraryDumper();
68
    }
69
70
    /**
71
     * @param array $data
72
     * @param array $keys
73
     *
74
     * @return array
75
     */
76
    protected function renameArrayKeys(array $data, array $keys)
77
    {
78
        foreach ($keys as $old => $new) {
79
            if (!isset($data[$old])) {
80
                continue;
81
            }
82
83
            $data[$new] = $data[$old];
84
            unset($data[$old]);
85
        }
86
87
        return $data;
88
    }
89
90
    /**
91
     * @param \SimpleXMLElement $data          The XML data
92
     * @param string            $xpathSelector The XPath selector
93
     * @param string            $targetClass   The target for the class
94
     * @param array             $renameKeys    The rename keys array
95
     *
96
     * @return array
97
     */
98
    protected function buildClassInstanceFromNodeAttributes(
99
        \SimpleXMLElement $data,
100
        $xpathSelector,
101
        $targetClass,
102
        array $renameKeys = array()
103
    ) {
104
        $editors = array();
105
        $className = $this->classes[$targetClass];
106
107
        foreach ($data->xpath($xpathSelector) as $element) {
108
            $dependencies = $this->getSimpleXmlElementAttributesAsArray($element);
109
110
            if (!empty($renameKeys)) {
111
                $dependencies = $this->renameArrayKeys($dependencies, $renameKeys);
112
            }
113
114
            $editors[] = new $className($dependencies);
115
        }
116
117
        return $editors;
118
    }
119
120
    /**
121
     * @param \SimpleXMLElement|null $xmlElement
122
     *
123
     * @return array
124
     */
125
    protected function getSimpleXmlElementAttributesAsArray(\SimpleXMLElement $xmlElement = null)
126
    {
127
        if (null === $xmlElement) {
128
            return array();
129
        }
130
131
        $attributes = (array) $xmlElement->attributes();
132
133
        return isset($attributes['@attributes']) ? $attributes['@attributes'] : array();
134
    }
135
136
    /**
137
     * @param \SimpleXMLElement $data
138
     *
139
     * @return array
140
     */
141
    protected function buildBooks(\SimpleXMLElement $data)
142
    {
143
        $books = array();
144
145
        foreach ($data->xpath('//books/era/book') as $book) {
146
            $books[] = new $this->classes['book']($this->getBooksDependencies($data, $book));
147
        }
148
149
        return $books;
150
    }
151
152
    /**
153
     * @param \SimpleXMLElement $data
154
     * @param \SimpleXMLElement $book
155
     *
156
     * @return array
157
     */
158
    protected function getBooksDependencies(\SimpleXMLElement $data, \SimpleXMLElement $book)
159
    {
160
        // Book attributes
161
        $bookAttributes = $this->getSimpleXmlElementAttributesAsArray($book);
162
163
        // Series attributes
164
        $series = $book->{'series'}[0];
165
        $seriesAttributes = $this->getSimpleXmlElementAttributesAsArray($series);
166
167
        // Publish attributes
168
        $publish = $book->{'publish'}[0];
169
        $publishAttributes = $this->getSimpleXmlElementAttributesAsArray($publish);
170
171
        // Editor attributes
172
        $releaseEditor = $book->{'editor'}[0];
173
        $releaseEditorAttributes = $this->getSimpleXmlElementAttributesAsArray($releaseEditor);
174
175
        // Categories data
176
        $categories = $data->xpath('//information/types/type[@code="'.$bookAttributes['type'].'"]');
177
        $categoryAttributes = $this->getSimpleXmlElementAttributesAsArray(reset($categories));
178
179
        // Releases data
180
        $releases = array();
181
        foreach (array_keys($releaseEditorAttributes) as $release) {
182
            $releaseNode = $book->$release;
183
184
            // Categories data
185
            $editor = $data->xpath('//information/editors/editor[@code="'.$releaseEditorAttributes[$release].'"]');
186
            $editorAttributes = $this->getSimpleXmlElementAttributesAsArray(reset($editor));
187
188
            $releases[] = new $this->classes['release'](
189
                array(
190
                    'title' => (string) $book->{'title'},
191
                    'editor' => new $this->classes['editor'](
192
                        $this->renameArrayKeys(
193
                            $editorAttributes,
194
                            array('code' => 'id', 'lang' => 'preferredLanguage')
195
                        )
196
                    ),
197
                    'publicationDate' => isset($publishAttributes[$release])
198
                        ? $this->transformToDateTime($publishAttributes[$release])
199
                        : null,
200
                    'language' => new $this->classes['language'](
201
                        array(
202
                            'id' => $editorAttributes['lang'],
203
                            'name' => $editorAttributes['lang'],
204
                        )
205
                    ),
206
                    'owner' => new $this->classes['owner'](
207
                        array(
208
                            'nbCopies' => isset($releaseNode['copies']) ? (int) $releaseNode['copies'] : null,
209
                            'nbReadings' => isset($releaseNode['readings']) ? (int) $releaseNode['readings'] : null,
210
                        )
211
                    ),
212
                    'format' => new $this->classes['format'](),
213
                    'series' => new $this->classes['series'](
214
                        null !== $series
215
                            ? array(
216
                                'title' => (string) $series,
217
                                'bookId' => isset($seriesAttributes['number']) ? $seriesAttributes['number'] : null,
218
                            )
219
                            : array()
220
                    ),
221
                )
222
            );
223
        }
224
225
        $authors = array();
226
        foreach (explode(',', (string) $book->{'author'}) as $author) {
227
            $authors[] = new $this->classes['author'](array('name' => trim($author)));
228
        }
229
230
        return array(
231
            'category' => new $this->classes['category'](
232
                array(
233
                    'id' => $bookAttributes['type'],
234
                    'name' => $categoryAttributes['name'],
235
                )
236
            ),
237
            'authors' => $authors,
238
            'releases' => $releases,
239
        );
240
    }
241
242
    /**
243
     * @param string $date
244
     *
245
     * @return \DateTime
246
     */
247
    protected function transformToDateTime($date)
248
    {
249
        $explodedDate = explode('.', $date);
250
        $dateTime = new \DateTime();
251
252
        return $dateTime->setDate($explodedDate[2], $explodedDate[1], $explodedDate[0]);
253
    }
254
}
255