Passed
Push — develop ( 4debb7...f03c1d )
by Sander
01:35
created

PosttypeBuilder   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Test Coverage

Coverage 76.83%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 269
ccs 63
cts 82
cp 0.7683
rs 8.3999
c 1
b 0
f 0
wmc 38

21 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 17 3
A applyDefaultConfiguration() 0 3 1
A setConfig() 0 7 2
A type() 0 11 2
A updateConfiguration() 0 5 1
A __construct() 0 5 2
A requiresConfiguration() 0 3 1
B where() 0 46 4
A invalidOperator() 0 3 1
B extractWhereValuesFromArray() 0 7 5
A getGrammar() 0 3 1
A setBinding() 0 3 1
B prepareValueAndOperator() 0 11 5
A getCompiler() 0 3 1
A getBinding() 0 3 1
A addArrayOfWheres() 0 8 2
A getBindings() 0 3 1
A limit() 0 4 1
A appendBinding() 0 3 1
A offset() 0 4 1
A getConfiguration() 0 3 1
1
<?php
2
3
namespace Sanderdekroon\Parlant\Builder;
4
5
use InvalidArgumentException;
6
use Sanderdekroon\Parlant\Container;
7
use Sanderdekroon\Parlant\Grammar\PosttypeGrammar;
8
use Sanderdekroon\Parlant\Compiler\PosttypeCompiler;
9
use Sanderdekroon\Parlant\Configurator\ParlantConfigurator;
10
use Sanderdekroon\Parlant\Configurator\ConfiguratorInterface;
11
12
class PosttypeBuilder implements BuilderInterface
13
{
14
    use BuildsQueries, QueriesMeta, QueriesTaxonomies;
15
16
17
    protected $grammar;
18
    
19
    protected $compiler;
20
    protected $bindings;
21
22
    protected $configuration;
23
24
25 32
    public function __construct(Container $container = null)
26
    {
27 32
        $this->grammar = new PosttypeGrammar; // Replace via DI
28 32
        $this->compiler = new PosttypeCompiler($this->getGrammar()); // Replace via DI
29 32
        $this->bindings = $container ?: new Container;
30 32
    }
31
32
33
    public function configure($configuration)
34
    {
35
        // If the supplied configuration is an instance of the ConfiguratorInterface
36
        // we can add it directly to the PosttypeBuilder. This way a developer
37
        // can supply their own configurator implementation.
38
        if ($configuration instanceof ConfiguratorInterface) {
39
            return $this->configuration = $configuration;
40
        }
41
42
        // If the developer wants to add additional configuration but has not
43
        // supplied an instance of the ConfiguratorInterface, we'll create
44
        // a new instance of our own implementation of the configurator.
45
        if (is_null($this->getConfiguration())) {
46
            $this->configuration = new ParlantConfigurator;
47
        }
48
49
        return $this->configuration->add($configuration);
50
    }
51
52
53 3
    public function setConfig($key, $value)
54
    {
55 3
        if ($this->requiresConfiguration()) {
56
            $this->applyDefaultConfiguration();
57
        }
58
59 3
        return $this->updateConfiguration($key, $value);
60
    }
61
62
63 3
    protected function updateConfiguration($key, $value)
64
    {
65 3
        $this->getConfiguration()->add($key, $value);
66
67 3
        return $this;
68
    }
69
70
    /**
71
     * Determine if the builder requires additional configuration.
72
     * @return bool
73
     */
74 32
    protected function requiresConfiguration()
75
    {
76 32
        return is_null($this->getConfiguration());
77
    }
78
79
    /**
80
     * Fill the configuration property with an instance of our ParlantConfigurator.
81
     * @return ParlantConfigurator
82
     */
83 32
    protected function applyDefaultConfiguration()
84
    {
85 32
        return $this->configuration = new ParlantConfigurator;
86
    }
87
88
    /**
89
     * Set the posttype the developer is querying.
90
     * @param  string $posttype
91
     * @return $this
92
     */
93 32
    public function type($posttype)
94
    {
95
        // Since this is the entry method (for now), we'll assume the developer allready
96
        // has supplied some form of configuration. If nothing is found, we'll create a
97
        // new instance of our ParlantConfigurator which sets some default settings.
98 32
        if ($this->requiresConfiguration()) {
99 32
            $this->applyDefaultConfiguration();
100
        }
101
102 32
        $this->setBinding('post_type', $posttype);
103 32
        return $this;
104
    }
105
106
107 4
    public function where($column, $operator = null, $value = null, $boolean = 'and')
108
    {
109
        // If the column is an array, we will assume it is an array of key-value pairs
110
        // and can add them each as a where clause.
111 4
        if (is_array($column)) {
112
            return $this->addArrayOfWheres($column);
113
        }
114
115
        // Here we will make some assumptions about the operator. If only 2 values are
116
        // passed to the method, we will assume that the operator is an equals sign
117
        // and keep going. Otherwise, we'll require the operator to be passed in.
118 4
        list($value, $operator) = $this->prepareValueAndOperator(
119 4
            $value,
120 4
            $operator,
121 4
            (func_num_args() == 2 || is_null($value)) //Is this the best solution?
122
        );
123
124
        // If the given operator is not found in the list of valid operators we will
125
        // assume that the developer is just short-cutting the '=' operators and
126
        // we will set the operators to '=' and set the values appropriately.
127 3
        if ($this->invalidOperator($operator)) {
128
            list($value, $operator) = [$operator, '='];
129
        }
130
131
132
        // If the value is "null", we will just assume the developer wants to add a
133
        // where null clause to the query. So, we will allow a short-cut here to
134
        // that method for convenience so the developer doesn't have to check.
135
        // if (is_null($value)) {
136
        //     return $this->whereNull($column, $boolean, $operator != '=');
137
        // }
138
139
        // Now that we are working with just a simple query we can put the elements
140
        // in our array and add the query binding to our array of bindings that
141
        // will be bound to each SQL statements when it is finally executed.
142 3
        $type = 'Basic';
143
144 3
        $this->appendBinding('wheres', compact(
145 3
            'type',
146 3
            'column',
147 3
            'operator',
148 3
            'value',
149 3
            'boolean'
150
        ));
151
152 3
        return $this;
153
    }
154
155
    /**
156
     * Add an array of where statements. The array should contain a numeric array
157
     * where the values can be used as arguments for the where() method.
158
     * @param array $wheres
159
     */
160
    protected function addArrayOfWheres($wheres)
161
    {
162
        foreach ($wheres as $where) {
163
            list($column, $operator, $value, $boolean) = $this->extractWhereValuesFromArray($where);
164
            $this->where($column, $operator, $value, $boolean);
165
        }
166
167
        return $this;
168
    }
169
170
    
171
    protected function extractWhereValuesFromArray($array)
172
    {
173
        return [
174
            isset($array[0]) ? $array[0] : null,
175
            isset($array[1]) ? $array[1] : null,
176
            isset($array[2]) ? $array[2] : null,
177
            isset($array[3]) ? $array[3] : null,
178
        ];
179
    }
180
181
    /**
182
     * Limit the number of posts to return to the $number
183
     * @param  int $number
184
     * @return $this
185
     */
186 1
    public function limit($number)
187
    {
188 1
        $this->setBinding('limit', (int)$number);
189 1
        return $this;
190
    }
191
192
    /**
193
     * Set the post offset.
194
     * @param  int $number
195
     * @return $this
196
     */
197 1
    public function offset($number)
198
    {
199 1
        $this->setBinding('offset', (int)$number);
200 1
        return $this;
201
    }
202
203
    /**
204
     * Prepare the value and operator. If $useDefault is true, return the default operator (=)
205
     * Throws an exception if the operator is not supported with the current grammer.
206
     * @param  mixed        $value
207
     * @param  string       $operator
208
     * @param  boolean      $useDefault
209
     * @throws InvalidArgumentException
210
     * @return array
211
     */
212 16
    protected function prepareValueAndOperator($value, $operator, $useDefault = false, $termDefault = false)
213
    {
214 16
        if ($useDefault) {
215 8
            return [$operator, $termDefault ? 'IN' : '='];
216
        }
217
218 9
        if ($this->invalidOperator($operator) && !is_null($value)) {
219 2
            throw new InvalidArgumentException('Illegal operator and value combination.');
220
        }
221
222 7
        return [$value, $operator];
223
    }
224
225 32
    protected function getGrammar()
226
    {
227 32
        return $this->grammar;
228
    }
229
230 25
    protected function getCompiler()
231
    {
232 25
        return $this->compiler;
233
    }
234
235 32
    protected function getBindings()
236
    {
237 32
        return $this->bindings;
238
    }
239
240 32
    protected function getConfiguration()
241
    {
242 32
        return $this->configuration;
243
    }
244
245
    /**
246
     * Determine if an operator is invalid or unsupported
247
     * @param  string $operator
248
     * @return bool
249
     */
250 16
    private function invalidOperator($operator)
251
    {
252 16
        return !in_array($operator, $this->getGrammar()->getOperators());
253
    }
254
255
    /**
256
     * Set an query binding
257
     * @param  string    $key   @todo validate if the $key is valid with the grammar
258
     * @param  mixed     $data
259
     * @return bool
260
     */
261 32
    private function setBinding($key, $data)
262
    {
263 32
        return $this->getBindings()->bind($key, $data);
264
    }
265
266
    /**
267
     * Append an query binding
268
     * @param  string   $key  @todo validate if the $key is valid with the grammar
269
     * @param  mixed    $data
270
     * @return bool
271
     */
272 14
    private function appendBinding($key, $data)
273
    {
274 14
        return $this->getBindings()->append($key, $data);
275
    }
276
277
278 2
    private function getBinding($key)
0 ignored issues
show
Unused Code introduced by
The method getBinding() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
279
    {
280 2
        return $this->getBindings()->get($key);
281
    }
282
}
283