1: <?php
2:
3: namespace PHPixie\Database\Conditions\Builder;
4:
5: abstract class Container implements \PHPixie\Database\Conditions\Builder
6: {
7: protected $groupStack = array();
8: protected $currentGroup;
9: protected $defaultOperator;
10: protected $aliases = array(
11: 'and' => '_and',
12: 'or' => '_or',
13: 'xor' => '_xor',
14: 'not' => '_not',
15: );
16:
17: public function __construct($defaultOperator = '=') {
18: $this->defaultOperator = $defaultOperator;
19:
20: $group = $this->buildGroupCondition();
21: $this->pushGroupToStack($group);
22: }
23:
24: public function startConditionGroup($logic = 'and', $negate = false)
25: {
26: $group = $this->buildGroupCondition();
27: $this->pushGroup($logic, $negate, $group);
28:
29: return $this;
30: }
31:
32: public function pushGroup($logic, $negate, $group)
33: {
34: $this->addCondition($logic, $negate, $group);
35: $this->pushGroupToStack($group);
36:
37: return $this;
38: }
39:
40: protected function pushGroupToStack($group)
41: {
42: $this->groupStack[] = $group;
43: $this->currentGroup = $group;
44: }
45:
46: public function endGroup()
47: {
48: if (count($this->groupStack) === 1)
49: throw new \PHPixie\Database\Exception\Builder("endGroup() was called more times than expected.");
50:
51: array_pop($this->groupStack);
52: $this->currentGroup = end($this->groupStack);
53:
54: return $this;
55: }
56:
57: public function buildCondition($logic, $negate, $args)
58: {
59: $count = count($args);
60: if ($count >= 2) {
61: $field = $args[0];
62:
63: if ($count === 2) {
64: $operator = $this->defaultOperator;
65: $values = array($args[1]);
66: } else {
67: $operator = $args[1];
68: $values = array_slice($args, 2);
69: }
70:
71: $this->addOperatorCondition($logic, $negate, $field, $operator, $values);
72:
73: return $this;
74: }
75:
76: if ($count === 1)
77: if (is_callable($callback = $args[0])) {
78: $this->startConditionGroup($logic, $negate);
79: $callback($this);
80: $this->endGroup();
81:
82: return $this;
83: }else
84: throw new \PHPixie\Database\Exception\Builder("If only one argument is provided it must be a callable");
85:
86: throw new \PHPixie\Database\Exception\Builder("Not enough arguments provided");
87: }
88:
89: public function addOperatorCondition($logic, $negate, $field, $operator, $values)
90: {
91: $condition = $this->buildOperatorCondition($field, $operator, $values);
92: return $this->addCondition($logic, $negate, $condition);
93: }
94:
95: public function addPlaceholder($logic = 'and', $negate = false, $allowEmpty = true)
96: {
97: $placeholder = $this->buildPlaceholderCondition($allowEmpty);
98: $this->addCondition($logic, $negate, $placeholder);
99:
100: return $placeholder->container();
101: }
102:
103: public function getConditions()
104: {
105: return $this->groupStack[0]->conditions();
106: }
107:
108: public function addCondition($logic, $negate, $condition)
109: {
110: $this->addToGroup($this->currentGroup, $logic, $negate, $condition);
111:
112: return $this;
113: }
114:
115: protected function addToGroup($group, $logic, $negate, $condition)
116: {
117: $condition->setLogic($logic);
118: if ($negate)
119: $condition->negate();
120: $group->add($condition);
121: }
122:
123: public function __call($method, $args)
124: {
125: if(!array_key_exists($method, $this->aliases))
126: throw new \PHPixie\Database\Exception\Builder("Method $method does not exist.");
127:
128: return call_user_func_array(array($this, $this->aliases[$method]), $args);
129: }
130:
131: public function _and()
132: {
133: return $this->buildCondition('and', false, func_get_args());
134: }
135:
136: public function _or()
137: {
138: return $this->buildCondition('or', false, func_get_args());
139: }
140:
141: public function _xor()
142: {
143: return $this->buildCondition('xor', false, func_get_args());
144: }
145:
146: public function _not()
147: {
148: return $this->buildCondition('and', true, func_get_args());
149: }
150:
151: public function andNot()
152: {
153: return $this->buildCondition('and', true, func_get_args());
154: }
155:
156: public function orNot()
157: {
158: return $this->buildCondition('or', true, func_get_args());
159: }
160:
161: public function xorNot()
162: {
163: return $this->buildCondition('xor', true, func_get_args());
164: }
165:
166: public function startGroup()
167: {
168: return $this->startConditionGroup('and', false);
169: }
170:
171: public function startAndGroup()
172: {
173: return $this->startConditionGroup('and', false);
174: }
175:
176: public function startOrGroup()
177: {
178: return $this->startConditionGroup('or', false);
179: }
180:
181: public function startXorGroup()
182: {
183: return $this->startConditionGroup('xor', false);
184: }
185:
186: public function startNotGroup()
187: {
188: return $this->startConditionGroup('and', true);
189: }
190:
191: public function startAndNotGroup()
192: {
193: return $this->startConditionGroup('and', true);
194: }
195:
196: public function startOrNotGroup()
197: {
198: return $this->startConditionGroup('or', true);
199: }
200:
201: public function startXorNotGroup()
202: {
203: return $this->startConditionGroup('xor', true);
204: }
205:
206: abstract protected function buildGroupCondition();
207: abstract protected function buildOperatorCondition($field, $operator, $values);
208: abstract protected function buildPlaceholderCondition($allowEmpty);
209: }
210: