Completed
Push — refactor-callback-handler ( 07f6ac...7e93ef )
by Yohan
03:33
created

ArrayLoader::getCallbacksResolver()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 27
ccs 18
cts 18
cp 1
rs 8.8571
cc 1
eloc 17
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Finite\Loader;
4
5
use Finite\Event\Callback\CallbackBuilder;
6
use Finite\Event\Callback\CallbackBuilderFactory;
7
use Finite\Event\Callback\CallbackBuilderFactoryInterface;
8
use Finite\Event\CallbackHandler;
9
use Finite\State\Accessor\PropertyPathStateAccessor;
10
use Finite\StateMachine\StateMachineInterface;
11
use Finite\State\State;
12
use Finite\State\StateInterface;
13
use Finite\Transition\Transition;
14
use Symfony\Component\OptionsResolver\Options;
15
use Symfony\Component\OptionsResolver\OptionsResolver;
16
17
/**
18
 * Loads a StateMachine from an array
19
 *
20
 * @author Yohan Giarelli <[email protected]>
21
 */
22
class ArrayLoader implements LoaderInterface
0 ignored issues
show
Complexity introduced by
The class ArrayLoader has a coupling between objects value of 13. Consider to reduce the number of dependencies under 13.
Loading history...
23
{
24
    /**
25
     * @var array
26
     */
27
    private $config;
28
29
    /**
30
     * @var CallbackHandler
31
     */
32
    private $callbackHandler;
33
34
    /**
35
     * @var CallbackBuilderFactoryInterface
36
     */
37
    private $callbackBuilderFactory;
38
39
    /**
40
     * @param array                           $config
41
     * @param CallbackHandler                 $handler
42
     * @param CallbackBuilderFactoryInterface $callbackBuilderFactory
43
     */
44 30
    public function __construct(array $config, CallbackHandler $handler = null, CallbackBuilderFactoryInterface $callbackBuilderFactory = null)
45
    {
46 30
        $this->callbackHandler        = $handler;
47 30
        $this->callbackBuilderFactory = $callbackBuilderFactory;
48 30
        $this->config = array_merge(
49
            array(
50 30
                'class'         => '',
51 24
                'graph'         => 'default',
52 24
                'property_path' => 'finiteState',
53 24
                'states'        => array(),
54 24
                'transitions'   => array(),
55 24
            ),
56
            $config
57 24
        );
58 30
    }
59
60
    /**
61
     * @{inheritDoc}
62
     */
63 25
    public function load(StateMachineInterface $stateMachine)
64
    {
65 25
        if (null === $this->callbackHandler) {
66 5
            $this->callbackHandler = new CallbackHandler($stateMachine->getDispatcher());
67 4
        }
68
69 25
        if (null === $this->callbackBuilderFactory) {
70 25
            $this->callbackBuilderFactory = new CallbackBuilderFactory;
71 20
        }
72
73 25
        $stateMachine->setStateAccessor(new PropertyPathStateAccessor($this->config['property_path']));
74 25
        $stateMachine->setGraph($this->config['graph']);
75
76 25
        $this->loadStates($stateMachine);
77 25
        $this->loadTransitions($stateMachine);
78 25
        $this->loadCallbacks($stateMachine);
79 25
    }
80
81
    /**
82
     * @{inheritDoc}
83
     */
84 5
    public function supports($object, $graph = 'default')
85 4
    {
86 5
        $reflection = new \ReflectionClass($this->config['class']);
87
88 5
        return $reflection->isInstance($object) && $graph === $this->config['graph'];
89
    }
90
91
    /**
92
     * @param StateMachineInterface $stateMachine
93
     */
94 25
    private function loadStates(StateMachineInterface $stateMachine)
95
    {
96 25
        $resolver = new OptionsResolver;
97 25
        $resolver->setDefaults(array('type' => StateInterface::TYPE_NORMAL, 'properties' => array()));
98 25
        $resolver->setAllowedValues('type', array(
99 25
            StateInterface::TYPE_INITIAL,
100 25
            StateInterface::TYPE_NORMAL,
101 5
            StateInterface::TYPE_FINAL
102 20
        ));
103
104 25
        foreach ($this->config['states'] as $state => $config) {
105 20
            $config = $resolver->resolve($config);
106 20
            $stateMachine->addState(new State($state, $config['type'], array(), $config['properties']));
107 20
        }
108 25
    }
109
110
    /**
111
     * @param StateMachineInterface $stateMachine
112
     */
113 25
    private function loadTransitions(StateMachineInterface $stateMachine)
114
    {
115 25
        $resolver = new OptionsResolver;
116 25
        $resolver->setRequired(array('from', 'to'));
117 25
        $resolver->setDefaults(array('guard' => null));
118
119
        $resolver->setNormalizer('from', function (Options $options, $v) { return (array) $v; });
120
        $resolver->setNormalizer('guard', function (Options $options, $v) { return !isset($v) ? null : $v; });
121
122 25
        foreach ($this->config['transitions'] as $transition => $config) {
123 20
            $config = $resolver->resolve($config);
124 20
            $stateMachine->addTransition(new Transition($transition, $config['from'], $config['to'], $config['guard']));
125 20
        }
126 25
    }
127
128
    /**
129
     * @param StateMachineInterface $stateMachine
130
     */
131 25
    private function loadCallbacks(StateMachineInterface $stateMachine)
132
    {
133 25
        if (!isset($this->config['callbacks'])) {
134 20
            return;
135
        }
136
137 10
        foreach (array('before', 'after') as $position) {
138 10
            $this->loadCallbacksFor($position, $stateMachine);
139 8
        }
140 10
    }
141
142 10
    private function loadCallbacksFor($position, $stateMachine)
143
    {
144 10
        if (!isset($this->config['callbacks'][$position])) {
145 5
            return;
146
        }
147
148 10
        $method   = 'add'.ucfirst($position);
149 10
        $resolver = $this->getCallbacksResolver();
150 10
        foreach ($this->config['callbacks'][$position] as $specs) {
151 10
            $specs = $resolver->resolve($specs);
152
153 10
            $callback = $this->callbackBuilderFactory->createBuilder($stateMachine)
154 10
                ->setFrom($specs['from'])
155 10
                ->setTo($specs['to'])
156 10
                ->setOn($specs['on'])
157 10
                ->setCallable($specs['do'])
158 10
                ->getCallback();
159
160 10
            $this->callbackHandler->$method($callback);
161 8
        }
162 10
    }
163
164 10
    private function getCallbacksResolver()
165
    {
166 10
        $resolver = new OptionsResolver;
167
168 10
        $resolver->setDefaults(
169
            array(
170 10
                'on'   => array(),
171 8
                'from' => array(),
172 8
                'to'   => array(),
173
            )
174 8
        );
175
176 10
        $resolver->setRequired(array('do'));
177
178 10
        $resolver->setAllowedTypes('on',   array('string', 'array'));
179 10
        $resolver->setAllowedTypes('from', array('string', 'array'));
180 10
        $resolver->setAllowedTypes('to',   array('string', 'array'));
181
182 10
        $toArrayNormalizer = function (Options $options, $value) {
183 10
            return (array) $value;
184 10
        };
185 10
        $resolver->setNormalizer('on',  $toArrayNormalizer);
186 10
        $resolver->setNormalizer('from', $toArrayNormalizer);
187 10
        $resolver->setNormalizer('to',   $toArrayNormalizer);
188
189 10
        return $resolver;
190
    }
191
}
192