Completed
Push — master ( 31d69b...c656e0 )
by Marcus
09:48
created

ConsoleOptionLoader::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
3
/**
4
 * TechDivision\Import\Configuration\Jms\ConsoleOptionLoader
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2019 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/techdivision/import-configuration-jms
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Configuration\Jms;
22
23
use JMS\Serializer\Annotation\Accessor;
24
use JMS\Serializer\Annotation\SerializedName;
25
use TechDivision\Import\Configuration\ConfigurationInterface;
26
use Doctrine\Common\Annotations\AnnotationReader;
27
use Symfony\Component\Console\Input\InputInterface;
28
use TechDivision\Import\ConsoleOptionLoaderInterface;
29
use TechDivision\Import\Utils\InputOptionKeysInterface;
30
31
/**
32
 * A dynamic console option loader implementation.
33
 *
34
 * @author    Tim Wagner <[email protected]>
35
 * @copyright 2019 TechDivision GmbH <[email protected]>
36
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
37
 * @link      https://github.com/techdivision/import-configuration-jms
38
 * @link      http://www.techdivision.com
39
 */
40
class ConsoleOptionLoader implements ConsoleOptionLoaderInterface
41
{
42
43
    /**
44
     * Array with options values that should NOT override the one from the configuration, if they already have values.
45
     *
46
     * @var array
47
     */
48
    protected $overrideIfEmpty = array();
49
50
    /**
51
     * The array with the blacklisted options that should be ignored.
52
     *
53
     * @var array
54
     */
55
    protected $blacklist = array();
56
57
    /**
58
     * The input interface.
59
     *
60
     * @var \Symfony\Component\Console\Input\InputInterface
61
     */
62
    protected $input;
63
64
    /**
65
     * The input option keys.
66
     *
67
     * @var \TechDivision\Import\Utils\InputOptionKeysInterface
68
     */
69
    protected $inputOptionKeys;
70
71
    /**
72
     * Initializes the console options loader.
73
     *
74
     * @param \Symfony\Component\Console\Input\InputInterface     $input           The input interface
75
     * @param \TechDivision\Import\Utils\InputOptionKeysInterface $inputOptionKeys The interface for the input option keys
76
     * @param array                                               $overrideIfEmpty The input options to parse
77
     * @param array                                               $blacklist       The array with the blacklisted options
78
     */
79
    public function __construct(
80
        InputInterface $input,
81
        InputOptionKeysInterface $inputOptionKeys,
82
        array $overrideIfEmpty = array(),
83
        array $blacklist = array()
84
    ) {
85
        $this->input = $input;
86
        $this->blacklist = $blacklist;
87
        $this->inputOptionKeys = $inputOptionKeys;
88
        $this->overrideIfEmpty = $overrideIfEmpty;
89
    }
90
91
    /**
92
     * Load's the input options ans try's to initialize the configuration with the values found.
93
     *
94
     * @param \TechDivision\Import\Configuration\ConfigurationInterface $instance The configuration instance to load the values for
95
     *
96
     * @return void
97
     */
98
    public function load(ConfigurationInterface $instance)
99
    {
100
101
        // we need the reflection properties of the configuration
102
        $reflectionClass = new \ReflectionClass($instance);
103
        $reflectionProperties = $reflectionClass->getProperties();
104
105
        // load the annoation reader
106
        $reader = new AnnotationReader();
107
108
        // iterate over the properties to initialize the configuration
109
        /** @var \ReflectionProperty $reflectionProperty */
110
        foreach ($reflectionProperties as $reflectionProperty) {
111
            // try to load the annotations of the properties
112
            /** @var \JMS\Serializer\Annotation\SerializedName $serializedName */
113
            $serializedName = $reader->getPropertyAnnotation($reflectionProperty, SerializedName::class);
114
            /** @var \JMS\Serializer\Annotation\SerializedName $accessors */
115
            $accessor = $reader->getPropertyAnnotation($reflectionProperty, Accessor::class);
116
117
            // intialize the option value (which equals the property name by default)
118
            $name = $reflectionProperty->getName();
119
120
            // if we've an JMS serializer annotation, we use the configured name instead
121
            if ($serializedName instanceof SerializedName) {
122
                $name = $serializedName->name;
123
            }
124
125
            // query whether or not the name matches an input option and is NOT on the blacklist
126
            if ($this->inputOptionKeys->isInputOption($name) && in_array($name, $this->blacklist) === false) {
127
                // query whether or not the @Accessor annotion with a setter has been specified
128
                if ($accessor instanceof Accessor && isset($accessor->getter) && isset($accessor->setter)) {
129
                    // initialize the value
130
                    $newValue = null;
131
132
                    // try to load the new value from the command line
133
                    if ($this->input->hasOption($name)) {
134
                        $newValue = $this->input->getOption($name);
135
                    }
136
137
                    // query whether or not we've a new value
138
                    if ($newValue === null) {
139
                        continue;
140
                    }
141
142
                    // this is the case where we may have a value from the configuration
143
                    // which may collate with the default value one from the command line
144
                    if (in_array($name, $this->overrideIfEmpty)) {
145
                        // first we try load the existing value from the configuration
146
                        $val = call_user_func(array($instance, $accessor->getter));
147
                        // query whether or not the command line option has REALLY been specified otherwise it'll
148
                        // be the default value and in that case the one from the configuration has precedence
149
                        if ($val === null || $this->input->hasOptionSpecified($name)) {
0 ignored issues
show
Bug introduced by
The method hasOptionSpecified() does not exist on Symfony\Component\Console\Input\InputInterface. Did you maybe mean hasOption()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
150
                            call_user_func(array($instance, $accessor->setter), $newValue);
151
                        }
152
                    } else {
153
                        call_user_func(array($instance, $accessor->setter), $newValue);
154
                    }
155
                }
156
            }
157
        }
158
    }
159
}
160