Completed
Push — master ( ce7d20...cfa95b )
by Fabrice
01:54
created

FlowMap::flowStart()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of NodalFlow.
5
 *     (c) Fabrice de Stefanis / https://github.com/fab2s/NodalFlow
6
 * This source file is licensed under the MIT license which you will
7
 * find in the LICENSE file or at https://opensource.org/licenses/MIT
8
 */
9
10
namespace fab2s\NodalFlow\Flows;
11
12
use fab2s\NodalFlow\NodalFlowException;
13
use fab2s\NodalFlow\Nodes\AggregateNodeInterface;
14
use fab2s\NodalFlow\Nodes\BranchNodeInterface;
15
use fab2s\NodalFlow\Nodes\NodeInterface;
16
17
/**
18
 * class FlowMap
19
 */
20
class FlowMap implements FlowMapInterface
21
{
22
    /**
23
     * Flow map
24
     *
25
     * @var array
26
     */
27
    protected $nodeMap = [];
28
29
    /**
30
     * @var array
31
     */
32
    protected $reverseMap = [];
33
34
    /**
35
     * The default Node Map values
36
     *
37
     * @var array
38
     */
39
    protected $nodeMapDefault = [
40
        'class'           => null,
41
        'flowId'          => null,
42
        'hash'            => null,
43
        'index'           => null,
44
        'isATraversable'  => null,
45
        'isAReturningVal' => null,
46
        'isAFlow'         => null,
47
        'num_exec'        => 0,
48
        'num_iterate'     => 0,
49
        'num_break'       => 0,
50
        'num_continue'    => 0,
51
    ];
52
53
    /**
54
     * The default Node stats values
55
     *
56
     * @var array
57
     */
58
    protected $incrementStatsDefault = [
59
        'num_exec'     => 0,
60
        'num_iterate'  => 0,
61
        'num_break'    => 0,
62
        'num_continue' => 0,
63
    ];
64
65
    /**
66
     * The Flow stats default values
67
     *
68
     * @var array
69
     */
70
    protected $loadStatsDefault = [
71
        'start'    => null,
72
        'end'      => null,
73
        'duration' => null,
74
        'mib'      => null,
75
    ];
76
77
    /**
78
     * @var array
79
     */
80
    protected $defaultFlowStats;
81
82
    /**
83
     * @var array
84
     */
85
    protected $flowStats;
86
87
    /**
88
     * @var bool
89
     */
90
    protected $resetOnRestart = false;
91
92
    /**
93
     * @var FlowInterface
94
     */
95
    protected $flow;
96
97
    /**
98
     * Instantiate a Flow Status
99
     *
100
     * @param FlowInterface $flow
101
     *
102
     * @throws NodalFlowException
103
     *
104
     * @internal param string $status The flow status
105
     */
106
    public function __construct(FlowInterface $flow)
107
    {
108
        $this->flow             = $flow;
109
        $this->defaultFlowStats = array_replace($this->loadStatsDefault, $this->incrementStatsDefault);
110
        $this->flowStats        = $this->defaultFlowStats;
111
    }
112
113
    /**
114
     * @param NodeInterface $node
115
     * @param int           $index
116
     * @param array         $incrementAliases
117
     *
118
     * @throws NodalFlowException
119
     */
120
    public function register(NodeInterface $node, $index, array $incrementAliases = [])
121
    {
122
        $this->enforceUniqueness($node);
123
        $nodeHash                      = $node->getNodeHash();
124
        $this->nodeMap[$nodeHash]      = array_replace($this->nodeMapDefault, [
125
            'class'           => get_class($node),
126
            'flowId'          => $node->getCarrier()->getId(),
127
            'hash'            => $nodeHash,
128
            'index'           => $index,
129
            'isATraversable'  => $node->isTraversable(),
130
            'isAReturningVal' => $node->isReturningVal(),
131
            'isAFlow'         => $node->isFlow(),
132
        ]);
133
134
        foreach ($incrementAliases as $aliasKey => $incKey) {
135
            if (!isset($this->incrementStatsDefault[$incKey])) {
136
                throw new NodalFlowException('Tried to set an increment alias to an un-registered increment', 1, null, [
137
                    'aliasKey'     => $aliasKey,
138
                    'incrementKey' => $incKey,
139
                ]);
140
            }
141
142
            $this->nodeMap[$nodeHash][$aliasKey] = &$this->nodeMap[$nodeHash][$incKey];
143
        }
144
145
        $this->reverseMap[$index] = $nodeHash;
146
    }
147
148
    /**
149
     * Triggered right before the flow starts
150
     *
151
     * @return $this
152
     */
153
    public function flowStart()
154
    {
155
        $this->flowStats['start'] = microtime(true);
156
157
        return $this;
158
    }
159
160
    /**
161
     * Triggered right after the flow stops
162
     *
163
     * @return $this
164
     */
165
    public function flowEnd()
166
    {
167
        $this->flowStats['end']      = microtime(true);
168
        $this->flowStats['mib']      = memory_get_peak_usage(true) / 1048576;
169
        $this->flowStats['duration'] = $this->flowStats['end'] - $this->flowStats['start'];
170
171
        return $this;
172
    }
173
174
    /**
175
     * Get/Generate Node Map
176
     *
177
     * @param bool $recurse
178
     *
179
     * @return array
180
     */
181
    public function getNodeMap($recurse = true)
182
    {
183
        foreach ($this->flow->getNodes() as $node) {
184
            if ($node instanceof BranchNodeInterface) {
185
                $this->nodeMap[$node->getNodeHash()]['nodes'] = $node->getPayload()->getNodeMap();
186
                continue;
187
            }
188
189
            if ($node instanceof AggregateNodeInterface) {
190
                $flowId = $node->getCarrier()->getId();
191
                foreach ($node->getNodeCollection() as $aggregatedNode) {
192
                    $this->nodeMap[$node->getNodeHash()]['nodes'][$aggregatedNode->getNodeHash()] = array_replace($this->nodeMapDefault, [
193
                        'class'  => get_class($aggregatedNode),
194
                        'flowId' => $flowId,
195
                        'hash'   => $aggregatedNode->getNodeHash(),
196
                    ]);
197
                }
198
                continue;
199
            }
200
        }
201
202
        return $this->nodeMap;
203
    }
204
205
    /**
206
     * Get the latest Node stats
207
     *
208
     * @return array
209
     */
210
    public function getStats()
211
    {
212
        $result = array_intersect_key($this->flowStats, $this->defaultFlowStats);
213
        foreach ($this->flow->getNodes() as $node) {
214
            if ($node instanceof BranchNodeInterface) {
215
                $result['branches'][$node->getPayload()->getId()] = $node->getPayload()->getStats();
216
            }
217
        }
218
219
        return $result;
220
    }
221
222
    /**
223
     * @param string $nodeHash
224
     * @param string $key
225
     *
226
     * @return $this
227
     */
228
    public function increment($nodeHash, $key)
229
    {
230
        ++$this->nodeMap[$nodeHash][$key];
231
232
        return $this;
233
    }
234
235
    /**
236
     * @param string $key
237
     *
238
     * @return $this
239
     */
240
    public function incrementFlow($key)
241
    {
242
        ++$this->flowStats[$key];
243
244
        return $this;
245
    }
246
247
    /**
248
     * Resets Nodes stats, can be used prior to Flow's re-exec
249
     *
250
     * @return $this
251
     */
252
    public function resetNodeStats()
253
    {
254
        foreach ($this->nodeMap as &$nodeStat) {
255
            $nodeStat = array_replace($nodeStat, $this->incrementStatsDefault);
256
        }
257
258
        return $this;
259
    }
260
261
    /**
262
     * @param NodeInterface $node
263
     *
264
     * @throws NodalFlowException
265
     *
266
     * @return $this
267
     */
268
    protected function enforceUniqueness(NodeInterface $node)
269
    {
270
        if (isset($this->nodeMap[$node->getNodeHash()])) {
271
            throw new NodalFlowException('Cannot reuse Node instances within a Flow', 1, null, [
272
                'duplicate_node' => get_class($node),
273
                'hash'           => $node->getNodeHash(),
274
            ]);
275
        }
276
277
        return $this;
278
    }
279
}
280