Completed
Push — development ( d0ebd5...329660 )
by Romain
10s
created

MixedTypesService::checkMixedTypeAnnotationForProperty()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 42
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 8.439
c 0
b 0
f 0
cc 6
eloc 25
nc 6
nop 3
1
<?php
2
/*
3
 * 2017 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 Configuration Object project.
6
 * It is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License, either
8
 * version 3 of the License, or any later version.
9
 *
10
 * For the full copyright and license information, see:
11
 * http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Romm\ConfigurationObject\Service\Items\MixedTypes;
15
16
use Romm\ConfigurationObject\Core\Core;
17
use Romm\ConfigurationObject\Core\Service\ReflectionService;
18
use Romm\ConfigurationObject\Exceptions\ClassNotFoundException;
19
use Romm\ConfigurationObject\Service\AbstractService;
20
use Romm\Formz\Exceptions\InvalidOptionValueException;
21
22
/**
23
 * This service allows the type of a configuration sub-object to be dynamic,
24
 * depending on arbitrary conditions which you can customize by implementing the
25
 * interface `MixedTypesInterface` in the classes which need this feature.
26
 */
27
class MixedTypesService extends AbstractService
28
{
29
    /**
30
     * The tag that can be added to a property (with a `@`).
31
     */
32
    const PROPERTY_ANNOTATION_MIXED_TYPE = 'mixedTypesResolver';
33
34
    /**
35
     * Default resolver which is returned by the function
36
     * `getMixedTypesResolver()` if the given class name does not implement the
37
     * correct interface.
38
     *
39
     * It will prevent potentially thousands of processors created for nothing.
40
     *
41
     * @var MixedTypesResolver
42
     */
43
    protected $defaultResolver;
44
45
    /**
46
     * Initialization: will create the default processor.
47
     */
48
    public function initialize()
49
    {
50
        $this->defaultResolver = new MixedTypesResolver();
51
    }
52
53
    /**
54
     * @param mixed  $data
55
     * @param string $className Valid class name.
56
     * @return MixedTypesResolver
57
     */
58
    public function getMixedTypesResolver($data, $className)
59
    {
60
        if (true === $this->classIsMixedTypeResolver($className)) {
61
            $resolver = new MixedTypesResolver();
62
            $resolver->setData($data);
63
            $resolver->setObjectType($className);
64
65
            /** @var MixedTypesInterface $className */
66
            $className::getInstanceClassName($resolver);
67
        } else {
68
            $resolver = $this->defaultResolver;
69
            $resolver->setData($data);
70
            $resolver->setObjectType($className);
71
        }
72
73
        return $resolver;
74
    }
75
76
    /**
77
     * @param string $className
78
     * @return bool
79
     */
80
    public function classIsMixedTypeResolver($className)
81
    {
82
        return true === array_key_exists(MixedTypesInterface::class, class_implements($className));
83
    }
84
85
    /**
86
     * @param string $targetType
87
     * @param string $propertyName
88
     * @param string $isComposite
89
     * @return null|string
90
     * @throws ClassNotFoundException
91
     * @throws InvalidOptionValueException
92
     */
93
    public function checkMixedTypeAnnotationForProperty($targetType, $propertyName, $isComposite)
94
    {
95
        $result = null;
96
97
        if (Core::get()->classExists($targetType)) {
98
            $classReflection = ReflectionService::get()->getClassReflection($targetType);
99
            $propertyReflection = $classReflection->getProperty($propertyName);
100
101
            if ($propertyReflection->isTaggedWith(self::PROPERTY_ANNOTATION_MIXED_TYPE)) {
102
                $tag = $propertyReflection->getTagValues(self::PROPERTY_ANNOTATION_MIXED_TYPE);
103
                $className = trim(end($tag));
104
105
                if (false === Core::get()->classExists($className)) {
106
                    throw new ClassNotFoundException(
107
                        vsprintf(
108
                            'Class "%s" given as value for the tag "@%s" of the class property "%s::$%s" was not found.',
109
                            [$className, self::PROPERTY_ANNOTATION_MIXED_TYPE, $targetType, $propertyName]
110
                        ),
111
                        1489155862
112
                    );
113
                } else {
114
                    if (false === $this->classIsMixedTypeResolver($className)) {
115
                        throw new InvalidOptionValueException(
116
                            vsprintf(
117
                                'Class "%s" given as value for the tag "@%s" of the class property "%s::$%s" must implement the interface "%s".',
118
                                [$className, self::PROPERTY_ANNOTATION_MIXED_TYPE, $targetType, $propertyName, MixedTypesInterface::class]
119
                            ),
120
                            1489156005
121
                        );
122
                    }
123
124
                    $result = $className;
125
126
                    if (true === $isComposite) {
127
                        $result .= '[]';
128
                    }
129
                }
130
            }
131
        }
132
133
        return $result;
134
    }
135
}
136