1<?php
2
3namespace Basho\Riak\Command\Builder\MapReduce;
4
5use Basho\Riak;
6use Basho\Riak\Command;
7
8/**
9 * Builds the command to fetch a collection of objects from Riak using Yokozuna search
10 *
11 * @author Christopher Mancini <cmancini at basho d0t com>
12 */
13class FetchObjects extends Command\Builder implements Command\BuilderInterface
14{
15    /**
16     * MR inputs used by query phase
17     *
18     * @var array|string
19     */
20    protected $inputs = [];
21
22    /**
23     * MR Query phases
24     *  - options include map, reduce or link
25     *
26     * @var array
27     */
28    protected $query = [];
29
30    /**
31     * Timeout for MR query
32     *
33     * @var int
34     */
35    protected $timeout = 0;
36
37    /**
38     * {@inheritdoc}
39     *
40     * @return Command\MapReduce\Fetch;
41     */
42    public function build()
43    {
44        $this->validate();
45
46        if (is_array($this->inputs) && count($this->inputs) == 1) {
47            $this->inputs = $this->inputs[0];
48        }
49
50        return new Command\MapReduce\Fetch($this);
51    }
52
53    /**
54     * {@inheritdoc}
55     */
56    public function validate()
57    {
58        $this->required('Inputs');
59        $this->required('Query');
60    }
61
62    /**
63     * addBucketInput
64     *
65     * @param Riak\Bucket $bucket
66     *
67     * @return $this
68     */
69    public function addBucketInput(Riak\Bucket $bucket)
70    {
71        // default bucket type cannot be passed to the MR api due to a bug
72        if ($bucket->getType() == 'default') {
73            $input = $bucket->getName();
74        } else {
75            $input = [$bucket->getType(), $bucket->getName()];
76        }
77
78        $this->inputs[] = $input;
79
80        return $this;
81    }
82
83    /**
84     * addLocationInput
85     *
86     * @param Riak\Location $location
87     *
88     * @return $this
89     */
90    public function addLocationInput(Riak\Location $location)
91    {
92        // default bucket type cannot be passed to the MR api due to a bug
93        if ($location->getBucket()->getType() == 'default') {
94            $input = [$location->getBucket()->getName(), $location->getKey()];
95        } else {
96            $input = [$location->getBucket()->getName(), $location->getKey(), '', $location->getBucket()->getType()];
97        }
98
99        $this->inputs[] = $input;
100
101        return $this;
102    }
103
104    /**
105     * withInput
106     *
107     * Sets a single input value as a string. Can be:
108     *  - a bucket with the default bucket type
109     *  - a 2i index name
110     *  - a Search/Yokozuna index name
111     *
112     * @param $input
113     *
114     * @return $this
115     */
116    public function withInput($input)
117    {
118        $this->inputs = $input;
119
120        return $this;
121    }
122
123    /**
124     * withInputs
125     *
126     * Sets an array of inputs for the MR request
127     *
128     * @param array $inputs
129     *
130     * @return $this
131     */
132    public function withInputs(array $inputs)
133    {
134        $this->inputs = $inputs;
135
136        return $this;
137    }
138
139    public function getInputs()
140    {
141        return $this->inputs;
142    }
143
144    /**
145     * @return string
146     */
147    public function getQuery()
148    {
149        return $this->query;
150    }
151
152    /**
153     * buildMapPhase
154     *
155     * Allows you to define the Map Query Phase by using parameters
156     *
157     * @param string $bucket
158     * @param string $key
159     * @param string $source
160     * @param string $language
161     * @param bool $keep
162     *
163     * @return $this
164     */
165    public function buildMapPhase($bucket = '', $key = '', $source = '', $language = 'javascript', $keep = false)
166    {
167        $this->setPhase('map', $this->assemblePhaseData($bucket, $key, $source, $language), $keep);
168
169        return $this;
170    }
171
172    /**
173     * setPhase
174     *
175     * @param $type
176     * @param $data
177     * @param bool $keep
178     */
179    protected function setPhase($type, $data, $keep = false)
180    {
181        $data['keep'] = $keep;
182        $object = new \StdClass();
183        $object->{$type} = $data;
184        $this->query[] = $object;
185    }
186
187    /**
188     * assemblePhaseData
189     *
190     * Assembles the parameters into a data structure to define a Query Phase
191     *
192     * @param string $bucket
193     * @param string $key
194     * @param string $source
195     * @param string $language
196     * @param string $tag
197     *
198     * @return array
199     */
200    protected function assemblePhaseData($bucket = '', $key = '', $source = '', $language = '', $tag = '')
201    {
202        $data = [];
203
204        if ($language) {
205            $data['language'] = $language;
206        }
207
208        if ($bucket) {
209            $data['bucket'] = $bucket;
210        }
211
212        if ($key) {
213            $data['key'] = $key;
214        }
215
216        if ($source) {
217            $data['source'] = $source;
218        }
219
220        if ($tag) {
221            $data['tag'] = $tag;
222        }
223
224        return $data;
225    }
226
227    /**
228     * buildReducePhase
229     *
230     * Allows you to define the Reduce Query Phase by using parameters
231     *
232     * @param string $bucket
233     * @param string $key
234     * @param string $source
235     * @param string $language
236     * @param bool $keep
237     *
238     * @return $this
239     */
240    public function buildReducePhase($bucket = '', $key = '', $source = '', $language = 'javascript', $keep = true)
241    {
242        $this->setPhase('reduce', $this->assemblePhaseData($bucket, $key, $source, $language), $keep);
243
244        return $this;
245    }
246
247    /**
248     * buildReducePhase
249     *
250     * Allows you to define the Reduce Query Phase by using parameters
251     *
252     * @param string $bucket
253     * @param string $tag
254     * @param bool $keep
255     *
256     * @internal param string $key
257     * @internal param string $source
258     * @internal param string $language
259     * @return $this
260     */
261    public function buildLinkPhase($bucket = '', $tag = '', $keep = false)
262    {
263        $this->setPhase('link', $this->assemblePhaseData($bucket, '', '', '', $tag), $keep);
264
265        return $this;
266    }
267
268    /**
269     * withQuery
270     *
271     * Sets the Query Phase/s for the MR request. This value gets converted directly into a JSON array and passed to Riak
272     *
273     * @param array $query
274     *
275     * @return $this
276     */
277    public function withQuery(array $query)
278    {
279        $this->query = $query;
280
281        return $this;
282    }
283}
284