Completed
Push — master ( 78e074...fc63d4 )
by Yohan
03:17
created

ArrayLoader::loadTransitions()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 4

Importance

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