Completed
Pull Request — master (#53)
by Daniel
04:47
created

XmlDriver::extractOptionSet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 3
1
<?php
2
3
namespace Psi\Component\ContentType\Metadata\Driver;
4
5
use Metadata\Driver\AbstractFileDriver;
6
use Psi\Component\ContentType\Metadata\ClassMetadata;
7
use Psi\Component\ContentType\Metadata\PropertyMetadata;
8
9
class XmlDriver extends AbstractFileDriver
10
{
11
    const XML_NAMESPACE = 'http://github.com/psiphp/content-type/mapping';
12
13
    /**
14
     * {@inheritdoc}
15
     */
16
    public function loadMetadataFromFile(\ReflectionClass $class, $path)
17
    {
18
        $classMetadata = new ClassMetadata($class->getName());
19
20
        $use = libxml_use_internal_errors(true);
21
        $dom = new \DOMDocument('1.0');
22
        $dom->load($path);
23
24
        if (!$dom->schemaValidate(__DIR__ . '/../../../schema/mapping.xsd')) {
25
            $message = array_reduce(libxml_get_errors(), function ($foo, $error) {
26
                return $error->message;
27
            });
28
            throw new \InvalidArgumentException(sprintf(
29
                'Could not validate XML mapping at "%s": %s',
30
                $path, $message
31
            ));
32
        }
33
        libxml_use_internal_errors($use);
34
35
        $xpath = new \DOMXpath($dom);
36
        $xpath->registerNamespace('psict', self::XML_NAMESPACE);
37
38
        foreach ($xpath->query('//psict:class') as $classEl) {
39
            $classAttr = $classEl->getAttribute('name');
40
41
            if ($classAttr !== $class->getName()) {
42
                throw new \InvalidArgumentException(sprintf(
43
                    'Expected class name to be "%s" but it is mapped as "%s"',
44
                    $class->getName(), $classAttr
45
                ));
46
            }
47
48
            foreach ($xpath->query('./psict:field', $classEl) as $fieldEl) {
49
50
                $shared = $this->extractOptionSet($xpath, $fieldEl, 'shared-options');
51
                $form = $this->extractOptionSet($xpath, $fieldEl, 'form-options');
52
                $view = $this->extractOptionSet($xpath, $fieldEl, 'view-options');
53
                $storage  = $this->extractOptionSet($xpath, $fieldEl, 'storage-options');
54
55
                $propertyMetadata = new PropertyMetadata(
56
                    $class->getName(),
57
                    $fieldEl->getAttribute('name'),
58
                    $fieldEl->getAttribute('type'),
59
                    $fieldEl->getAttribute('role'),
60
                    $fieldEl->getAttribute('group'),
61
                    [
62
                        'shared' => $shared,
63
                        'form' => $form,
64
                        'view' => $view,
65
                        'storage' => $storage,
66
                    ]
67
                );
68
69
                $classMetadata->addPropertyMetadata($propertyMetadata);
70
            }
71
        }
72
73
        return $classMetadata;
74
    }
75
76
    private function extractOptionSet(\DOMXpath $xpath, \DOMElement $fieldEl, $type)
77
    {
78
        foreach ($xpath->query('./psict:' . $type, $fieldEl) as $setEl) {
79
            return $this->extractOptions($xpath, $setEl);
80
        }
81
    }
82
83
    private function extractOptions(\DOMXPath $xpath, \DOMElement $setEl)
84
    {
85
        $options = [];
86
87
        foreach ($xpath->query('./psict:option', $setEl) as $optionEl) {
88
            if ($optionEl->getAttribute('type') === 'collection') {
89
                $options[$optionEl->getAttribute('name')] = $this->extractOptions($xpath, $optionEl);
90
                continue;
91
            }
92
93
            $options[$optionEl->getAttribute('name')] = $optionEl->nodeValue;
94
        }
95
96
        return $options;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function getExtension()
103
    {
104
        return 'xml';
105
    }
106
}
107