Completed
Pull Request — master (#659)
by
unknown
02:51
created

TaskForEach::setIterable()   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
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
namespace Robo\Collection;
3
4
use Robo\Result;
5
use Robo\TaskInfo;
6
use Robo\Task\BaseTask;
7
use Robo\Contract\BuilderAwareInterface;
8
use Robo\Common\BuilderAwareTrait;
9
10
/**
11
 * Creates a task wrapper that converts any Callable into an
12
 * object that will execute the callback once for each item in the
13
 * provided collection.
14
 *
15
 * It is not necessary to use this class directly; Collection::addIterable
16
 * will automatically create one when it is called.
17
 */
18
class TaskForEach extends BaseTask implements NestedCollectionInterface, BuilderAwareInterface
19
{
20
    use BuilderAwareTrait;
21
22
    /**
23
     * @var callable[]
24
     */
25
    protected $functionStack = [];
26
27
    /**
28
     * @var callable[]
29
     */
30
    protected $countingStack = [];
31
32
    /**
33
     * @var string
34
     */
35
    protected $message;
36
37
    /**
38
     * @var array
39
     */
40
    protected $context = [];
41
42
    /**
43
     * @var array $iterable
44
     */
45
    protected $iterable = [];
46
47
    /**
48
     * @var \Robo\Collection\NestedCollectionInterface
49
     */
50
    protected $parentCollection;
51
52
    /**
53
     * @var array $iterable
54
     */
55
    public function __construct($iterable = [])
56
    {
57
        $this->setIterable($iterable);
58
    }
59
60
    /**
61
     * @param array $iterable
62
     *
63
     * @return $this
64
     */
65
    public function setIterable($iterable)
66
    {
67
        $this->iterable = $iterable;
68
69
        return $this;
70
    }
71
72
    /**
73
     * @param string $message
74
     * @param array $context
75
     *
76
     * @return $this
77
     */
78
    public function iterationMessage($message, $context = [])
79
    {
80
        $this->message = $message;
81
        $this->context = $context + ['name' => 'Progress'];
82
        return $this;
83
    }
84
85
    /**
86
     * @param int|string $key
87
     * @param mixed $value
88
     */
89
    protected function showIterationMessage($key, $value)
90
    {
91
        if ($this->message) {
92
            $context = ['key' => $key, 'value' => $value];
93
            $context += $this->context;
94
            $context += TaskInfo::getTaskContext($this);
95
            $this->printTaskInfo($this->message, $context);
96
        }
97
    }
98
99
    /**
100
     * @param callable $fn
101
     *
102
     * @return $this
103
     */
104
    public function withEachKeyValueCall(callable $fn)
105
    {
106
        $this->functionStack[] = $fn;
107
        return $this;
108
    }
109
110
    /**
111
     * @param callable $fn
112
     *
113
     * @return \Robo\Collection\TaskForEach
114
     */
115
    public function call(callable $fn)
116
    {
117
        return $this->withEachKeyValueCall(
118
            function ($key, $value) use ($fn) {
119
                return call_user_func($fn, $value);
120
            }
121
        );
122
    }
123
124
    /**
125
     * @param callable $fn
126
     *
127
     * @return \Robo\Collection\TaskForEach
128
     */
129
    public function withBuilder(callable $fn)
130
    {
131
        $this->countingStack[] =
132
            function ($key, $value) use ($fn) {
133
                // Create a new builder for every iteration
134
                $builder = $this->collectionBuilder();
135
                // The user function should build task operations using
136
                // the $key / $value parameters; we will call run() on
137
                // the builder thus constructed.
138
                call_user_func($fn, $builder, $key, $value);
139
                return $builder->getCollection()->progressIndicatorSteps();
140
            };
141
        return $this->withEachKeyValueCall(
142
            function ($key, $value) use ($fn) {
143
                // Create a new builder for every iteration
144
                $builder = $this->collectionBuilder()
145
                    ->setParentCollection($this->parentCollection);
146
                // The user function should build task operations using
147
                // the $key / $value parameters; we will call run() on
148
                // the builder thus constructed.
149
                call_user_func($fn, $builder, $key, $value);
150
                return $builder->run();
151
            }
152
        );
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function setParentCollection(NestedCollectionInterface $parentCollection)
159
    {
160
        $this->parentCollection = $parentCollection;
161
        return $this;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function progressIndicatorSteps()
168
    {
169
        $multiplier = count($this->functionStack);
170
        if (!empty($this->countingStack)) {
171
            $value = reset($this->iterable);
172
            $key = key($this->iterable);
173
            foreach ($this->countingStack as $fn) {
174
                $multiplier += call_user_func($fn, $key, $value);
175
            }
176
        }
177
        return count($this->iterable) * $multiplier;
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    public function run()
184
    {
185
        $finalResult = Result::success($this);
186
        $this->startProgressIndicator();
187
        foreach ($this->iterable as $key => $value) {
188
            $this->showIterationMessage($key, $value);
189
            try {
190
                foreach ($this->functionStack as $fn) {
191
                    $result = call_user_func($fn, $key, $value);
192
                    $this->advanceProgressIndicator();
193
                    if (!isset($result)) {
194
                        $result = Result::success($this);
195
                    }
196
                    // If the function returns a result, it must either return
197
                    // a \Robo\Result or an exit code.  In the later case, we
198
                    // convert it to a \Robo\Result.
199
                    if (!$result instanceof Result) {
200
                        $result = new Result($this, $result);
201
                    }
202
                    if (!$result->wasSuccessful()) {
203
                        return $result;
204
                    }
205
                    $finalResult = $result->merge($finalResult);
206
                }
207
            } catch (\Exception $e) {
208
                return Result::fromException($result, $e);
209
            }
210
        }
211
        $this->stopProgressIndicator();
212
        return $finalResult;
213
    }
214
}
215