Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
ConditionBuilder
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
8 / 8
14
100.00% covered (success)
100.00%
1 / 1
 andWith
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 orWith
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addCondition
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
3
 conditions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildConditionSQL
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildPartsSQL
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
5
 getConditionParameters
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasConditions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsdb\Query\Builder;
4
5/**
6 * ConditionBuilder
7 *
8 * Builds up a set of conditions for a query, either used in a WHERE or
9 * HAVING block of SQL.
10 *
11 * @package     BO\Zmsdb\Query\Builder
12 * @author      Alex Gisby<alex@solution10.com>
13 * @license     MIT
14 */
15class ConditionBuilder
16{
17    /**
18     * @var     array   "Parts" as in field, op, value
19     */
20    protected $parts = [];
21
22    /**
23     * @var     array   Params (used as a shortcut for feeding into PDO)
24     */
25    protected $params = [];
26
27    /**
28     * Adds an AND condition into the builder
29     *
30     * @param   string|\Closure     $field              Fieldname|callback for group
31     * @param   string              $operator           Operator (=, !=, <>, <= etc)
32     * @param   mixed               $value              Value to test against
33     * @return  $this
34     */
35    public function andWith($field, $operator = null, $value = null)
36    {
37        $this->addCondition('AND', $field, $operator, $value);
38        return $this;
39    }
40
41    /**
42     * Adds an OR condition into the builder
43     *
44     * @param   string|\Closure     $field              Fieldname|callback for group
45     * @param   string              $operator           Operator (=, !=, <>, <= etc)
46     * @param   mixed               $value              Value to test against
47     * @return  $this
48     */
49    public function orWith($field, $operator = null, $value = null)
50    {
51        $this->addCondition('OR', $field, $operator, $value);
52        return $this;
53    }
54
55    /**
56     * Adds the condition into the family we're building.
57     *
58     * @param   string              $join               AND or OR
59     * @param   string|\Closure     $field              Fieldname|callback for group
60     * @param   string              $operator           Operator (=, !=, <>, <= etc)
61     * @param   mixed               $value              Value to test against
62     * @return  $this               $this on set, array on get
63     */
64    protected function addCondition($join, $field, $operator, $value)
65    {
66        $newParams = [];
67        if ($field instanceof \Closure) {
68            // Return and merge the result of these queries
69            $subQuery = new ConditionBuilder();
70            $field($subQuery);
71            $this->parts[] = [
72                'join' => $join,
73                'sub' => $subQuery->conditions()
74            ];
75            $newParams = $subQuery->getConditionParameters();
76//            $this->params = array_merge($this->params, $subQuery->getConditionParameters());
77        } else {
78            $this->parts[] = [
79                'join' => $join,
80                'field' => $field,
81                'operator' => $operator,
82                'value' => $value
83            ];
84            $newParams = $value;
85        }
86
87        if (!is_array($newParams)) {
88            $newParams = [$newParams];
89        }
90
91        $this->params = array_merge($this->params, $newParams);
92
93        return $this;
94    }
95
96    /**
97     * Returns the conditions that have been set on this builder.
98     *
99     * @return  array
100     */
101    public function conditions()
102    {
103        return $this->parts;
104    }
105
106    /**
107     * Builds up the SQL for this condition.
108     *
109     * @param   DialectInterface    $dialect
110     * @return  string
111     */
112    public function buildConditionSQL(DialectInterface $dialect)
113    {
114        return $this->buildPartsSQL($this->parts, $dialect);
115    }
116
117    /**
118     * Builds up an array of parts into a SQL string. To be used recursively.
119     *
120     * @param   DialectInterface    $dialect
121     * @param   array               $parts
122     * @return  string
123     */
124    protected function buildPartsSQL(array $parts, DialectInterface $dialect)
125    {
126        $where = '';
127        foreach ($parts as $c) {
128            $where .= ' ' . $c['join'] . ' ';
129            if (array_key_exists('sub', $c)) {
130                $where .= '(';
131                $where .= $this->buildPartsSQL($c['sub'], $dialect);
132                $where .= ')';
133            } else {
134                $where .= $dialect->quoteField($c['field']) . ' ' . $c['operator'] . ' ';
135                if (is_array($c['value'])) {
136                    $inParts = [];
137                    for ($i = 0; $i < count($c['value']); $i++) {
138                        $inParts[] = '?';
139                    }
140                    $where .= '(' . implode(', ', $inParts) . ')';
141                } else {
142                    $where .= '?';
143                }
144            }
145        }
146        $where = trim(preg_replace('/^(AND|OR) /', '', trim($where)));
147        return $where;
148    }
149
150    /**
151     * Returns the parameters from this set of conditions ready to throw at a PDO statement
152     *
153     * @return  array
154     */
155    public function getConditionParameters()
156    {
157        return $this->params;
158    }
159
160    /**
161     * Returns whether any conditions have been added to this builder
162     *
163     * @return  bool
164     */
165    public function hasConditions()
166    {
167        return !empty($this->parts);
168    }
169}