FromPropelSchemaXmlAssembler::startsWith()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
/**
3
 * @author stev leibelt <[email protected]>
4
 * @since 2014-05-26 
5
 */
6
7
namespace Net\Bazzline\Component\Locator\Configuration\Assembler;
8
9
use Net\Bazzline\Component\Locator\Configuration\Configuration;
10
use Net\Bazzline\Component\Locator\Configuration\Validator\ReadableFilePath;
11
use XMLReader;
12
13
/**
14
 * Class FromPropelSchemaXmlAssembler
15
 * @package Net\Bazzline\Component\Locator\Configuration\Assembler
16
 */
17
class FromPropelSchemaXmlAssembler extends AbstractAssembler
18
{
19
    /**
20
     * @param mixed $data
21
     * @param Configuration $configuration
22
     * @return Configuration
23
     * @throws RuntimeException
24
     */
25
    protected function map($data, Configuration $configuration)
26
    {
27
        //begin of variable definitions
28
        $columnClassMethodBodyBuilder =
29
            (isset($data['column_class_method_body_builder']))
30
                ? $data['column_class_method_body_builder']
31
                : null;
32
33
        $locatorNamespace =
34
            (isset($data['namespace']))
35
                ? $data['namespace']
36
                : '';
37
38
        $methodNameWithoutNamespace =
39
            (isset($data['method_name_without_namespace']))
40
                ? $data['method_name_without_namespace']
41
                : false;
42
43
        $pathToSchemaXml = realpath($data['path_to_schema_xml']);
44
        $queryClassMethodBodyBuilder =
45
            (isset($data['query_class_method_body_builder']))
46
                ? $data['query_class_method_body_builder']
47
                : null;
48
        //end of variable definitions
49
50
        //@todo inject
51
        $validator = new ReadableFilePath();
52
        $validator->validate($pathToSchemaXml);
53
54
        $configuration = $this->mapBooleanProperties(
55
            $data,
56
            $configuration
57
        );
58
        $configuration = $this->mapStringProperties(
59
            $data,
60
            $configuration
61
        );
62
        $configuration = $this->mapSchemaXmlPropertiesToConfiguration(
63
            $pathToSchemaXml,
64
            $configuration,
65
            $columnClassMethodBodyBuilder,
66
            $locatorNamespace,
67
            $queryClassMethodBodyBuilder,
68
            $methodNameWithoutNamespace
69
        );
70
        $configuration = $this->mapArrayPropertiesToConfiguration(
71
            $data,
72
            $configuration
73
        );
74
75
        return $configuration;
76
    }
77
78
    /**
79
     * @param mixed $data
80
     * @throws InvalidArgumentException
81
     */
82 View Code Duplication
    protected function validateData($data)
83
    {
84
        if (!is_array($data)) {
85
            throw new InvalidArgumentException(
86
                'data must be an array'
87
            );
88
        }
89
90
        if (empty($data)) {
91
            throw new InvalidArgumentException(
92
                'data array must contain content'
93
            );
94
        }
95
96
        $mandatoryKeysToExpectedValueTyp = array(
97
            'class_name'            => 'string',
98
            'file_path'             => 'string'
99
        );
100
101
        $this->validateDataWithMandatoryKeysAndExpectedValueType(
102
            $data,
103
            $mandatoryKeysToExpectedValueTyp
104
        );
105
106
        $optionalKeysToExpectedValueTyp = array(
107
            'extends'                       => 'string',
108
            'implements'                    => 'array',
109
            'method_name_without_namespace' => 'boolean',
110
            'namespace'                     => 'string',
111
            'path_to_schema_xml'            => 'string',
112
            'uses'                          => 'array'
113
        );
114
115
        $this->validateDataWithOptionalKeysAndExpectedValueTypeOrSetExpectedValueAsDefault(
116
            $data,
117
            $optionalKeysToExpectedValueTyp
118
        );
119
    }
120
121
    /**
122
     * @param string $pathToSchemaXml
123
     * @param Configuration $configuration
124
     * @param string $columnClassMethodBodyBuilder
125
     * @param string $locatorNamespace
126
     * @param string $queryClassMethodBodyBuilder
127
     * @param boolean $methodNameWithoutNamespace
128
     * @return Configuration
129
     */
130
    private function mapSchemaXmlPropertiesToConfiguration(
131
        $pathToSchemaXml,
132
        Configuration $configuration,
133
        $columnClassMethodBodyBuilder,
134
        $locatorNamespace,
135
        $queryClassMethodBodyBuilder,
136
        $methodNameWithoutNamespace
137
    )
138
    {
139
        //begin of variable definitions
140
        $hasRootNamespace = false;
141
        //@todo inject XMLReader
142
        $reader = new XMLReader();
143
        $reader->open($pathToSchemaXml);
144
        $rootNamespace = '';
145
        //end of variable definitions
146
147
        //begin of xml parsing
148
        while ($reader->read()) {
149
            if ($reader->nodeType === XMLREADER::ELEMENT) {
150
                $nodeIsADatabase    = ($reader->name === 'database');
151
                $nodeIsATable       = ($reader->name === 'table');
152
153
                if ($nodeIsADatabase) {
154
                    $rootNamespace = $reader->getAttribute('namespace');
155
                    if(strlen($rootNamespace) > 0) {
156
                        $hasRootNamespace = true;
157
                    }
158
                }
159
160
                if ($nodeIsATable) {
161
                    $configuration = $this->addTableToConfiguration(
162
                        $reader,
163
                        $hasRootNamespace,
164
                        $rootNamespace,
165
                        $locatorNamespace,
166
                        $configuration,
167
                        $columnClassMethodBodyBuilder,
168
                        $queryClassMethodBodyBuilder,
169
                        $methodNameWithoutNamespace
170
                    );
171
                }
172
            }
173
        }
174
        $reader->close();
175
        //end of xml parsing
176
177
        return $configuration;
178
    }
179
180
    /**
181
     * @param array $data
182
     * @param Configuration $configuration
183
     * @return Configuration
184
     * @throws RuntimeException
185
     */
186 View Code Duplication
    private function mapArrayPropertiesToConfiguration(array $data, Configuration $configuration)
187
    {
188
        if (isset($data['implements'])) {
189
            foreach($data['implements'] as $interfaceName) {
190
                $configuration->addImplements($interfaceName);
191
            }
192
        }
193
194
        if (isset($data['uses'])) {
195
            foreach ($data['uses'] as $key => $uses) {
196
                if (!isset($uses['class_name'])) {
197
                    throw new RuntimeException(
198
                        'use entry with key "' . $key . '" needs to have a key "class_name"'
199
                    );
200
                }
201
202
                $alias      = (isset($uses['alias'])) ? $uses['alias'] : '';
203
                $className  = str_replace('\\\\', '\\', $uses['class_name']);
204
                $configuration->addUses($className, $alias);
205
            }
206
        }
207
208
        return $configuration;
209
    }
210
211
    /**
212
     * @param XMLReader $reader
213
     * @param boolean $hasRootNamespace
214
     * @param string $rootNamespace
215
     * @param string $locatorNamespace
216
     * @param Configuration $configuration
217
     * @param string $columnClassMethodBodyBuilder
218
     * @param string $queryClassMethodBodyBuilder
219
     * @param boolean $methodNameWithoutNamespace
220
     * @return Configuration
221
     */
222
    private function addTableToConfiguration(
223
        XMLReader $reader,
224
        $hasRootNamespace,
225
        $rootNamespace,
226
        $locatorNamespace,
227
        Configuration $configuration,
228
        $columnClassMethodBodyBuilder,
229
        $queryClassMethodBodyBuilder,
230
        $methodNameWithoutNamespace
231
    )
232
    {
233
        //begin of variable definitions
234
        $namespace              = $reader->getAttribute('namespace');
235
        $phpName                = $reader->getAttribute('phpName');
236
        $tableName              = $reader->getAttribute('name');
237
        $tableNamespace         = '';
238
        $hasPhpName             = (strlen($phpName) > 0);
239
        $hasNamespace           = (strlen($namespace) > 0);
240
        //end of variable definitions
241
242
        //begin of class name building
243
        if ($hasRootNamespace) {
244
            $tableNamespace .= '\\' . $rootNamespace . '\\';
245
        }
246
247
        if ($hasNamespace) {
248
            $tableNamespace .= $namespace . '\\';
249
        }
250
251
        $hasDifferentNamespaceThanLocator   = ($locatorNamespace !== $tableNamespace);
252
        $hasTableNamespace                  = (strlen($tableNamespace) > 0);
253
        $fullQualifiedClassName             = $this->createFullQualifiedClassName(
254
            $hasPhpName,
255
            $phpName,
256
            $tableName,
257
            $hasTableNamespace,
258
            $tableNamespace
259
        );
260
261
        $classNameAlias = ($methodNameWithoutNamespace)
262
            ? $this->createClassNameAlias($hasPhpName, $phpName, $tableName)
263
            : null;
264
265
        $queryClassNameAlias =
266
            (!is_null($classNameAlias))
267
                ? $classNameAlias . 'Query'
268
                : null;
269
270
        $fullQualifiedQueryClassName = $fullQualifiedClassName . 'Query';
271
        //end of class name building
272
273
        //begin of configuration adaptation
274
        $configuration->addInstance(
275
            $fullQualifiedClassName,
276
            false,
277
            false,
278
            $fullQualifiedClassName,
279
            $classNameAlias,
280
            $columnClassMethodBodyBuilder
281
        );
282
        $configuration->addInstance(
283
            $fullQualifiedQueryClassName,
284
            false,
285
            false,
286
            $fullQualifiedClassName,
287
            $queryClassNameAlias,
288
            $queryClassMethodBodyBuilder
289
        );
290
291
        if ($hasDifferentNamespaceThanLocator) {
292
            //we have to remove the first "\" if available
293
            $useClassName = ($this->startsWith($fullQualifiedClassName, '\\'))
294
                ? substr($fullQualifiedClassName, 1)
295
                : $fullQualifiedClassName;
296
297
            $useQueryClassName = ($this->startsWith($fullQualifiedQueryClassName, '\\'))
298
                ? substr($fullQualifiedQueryClassName, 1)
299
                : $fullQualifiedQueryClassName;
300
301
            $configuration->addUses($useClassName);
302
            $configuration->addUses($useQueryClassName);
303
        }
304
        //end of configuration adaptation
305
306
        return $configuration;
307
    }
308
309
    /**
310
     * @param string $haystack
311
     * @param string $needle
312
     * @return bool
313
     */
314
    private function startsWith($haystack, $needle)
315
    {
316
        return (strncmp($haystack, $needle, strlen($needle)) === 0);
317
    }
318
319
    /**
320
     * @param boolean $hasPhpName
321
     * @param string $phpName
322
     * @param string $tableName
323
     * @param boolean $hasTableNamespace
324
     * @param string $tableNamespace
325
     * @return mixed|string
326
     */
327
    private function createFullQualifiedClassName($hasPhpName, $phpName, $tableName, $hasTableNamespace, $tableNamespace)
328
    {
329
        $fullQualifiedClassName = '';
330
331
        if ($hasPhpName) {
332
            $fullQualifiedClassName = $phpName;
333
        } else {
334
            $tableNameAsArray = explode('_', $tableName);
335
            array_walk($tableNameAsArray, function (&$value) {
336
                $value = ucfirst($value);
337
            });
338
            $fullQualifiedClassName .= implode('', $tableNameAsArray);
339
        }
340
341
        if ($hasTableNamespace) {
342
            $fullQualifiedClassName = $tableNamespace . '\\' . $fullQualifiedClassName;
343
        }
344
345
        $fullQualifiedClassName = str_replace('\\\\', '\\', $fullQualifiedClassName);
346
347
        return $fullQualifiedClassName;
348
    }
349
350
    /**
351
     * @param boolean $hasPhpName
352
     * @param string $phpName
353
     * @param string $tableName
354
     * @return string
355
     */
356
    private function createClassNameAlias($hasPhpName, $phpName, $tableName)
357
    {
358
        return ($hasPhpName) ? $phpName : $tableName;
359
    }
360
}
361