1: <?php
2:
3: namespace PHPixie\Database\Driver\Mongo\Parser;
4:
5: use \PHPixie\Database\Type\Document\Conditions\Condition as DocumentCondition;
6:
7: class Conditions extends \PHPixie\Database\Conditions\Logic\Parser
8: {
9: protected $driver;
10: protected $conditions;
11: protected $operatorParser;
12:
13: public function __construct($driver, $conditions, $operatorParser)
14: {
15: $this->driver = $driver;
16: $this->conditions = $conditions;
17: $this->operatorParser = $operatorParser;
18: }
19:
20: protected function normalize($condition, $prefix = null)
21: {
22: if($condition instanceof \PHPixie\Database\Type\Document\Conditions\Condition\Collection\Embedded\SubarrayItem) {
23: $conditions = $condition->conditions();
24: $parsed = $this->parse($conditions, false);
25:
26: $field = $this->prefixField($prefix, $condition->field());
27: $operatorCondition = $this->conditions->operator($field, 'elemMatch', array($parsed));
28: $this->copyLogicAndNegated($condition, $operatorCondition);
29:
30: return $this->normalizeOperatorCondition($operatorCondition);
31: }
32:
33: if($condition instanceof \PHPixie\Database\Conditions\Condition\Collection) {
34: $conditions = $condition->conditions();
35:
36: $collectionPrefix = $prefix;
37:
38: if($condition instanceof \PHPixie\Database\Type\Document\Conditions\Condition\Collection\Embedded\Subdocument) {
39: $collectionPrefix = $this->prefixField($prefix, $condition->field());
40: }
41:
42: $expanded = $this->parseLogic($conditions);
43:
44: foreach ($expanded->operatorConditions() as $operatorCondition) {
45: $operatorCondition->setField($this->prefixField($collectionPrefix, $operatorCondition->field()));
46: }
47:
48: return $this->copyLogicAndNegated($condition, $expanded);
49: }
50:
51: if ($condition instanceof \PHPixie\Database\Conditions\Condition\Field\Operator) {
52: return $this->normalizeOperatorCondition($condition);
53: }
54:
55: $class = get_class($condition);
56: throw new \PHPixie\Database\Exception\Parser("Condition of type '$class' is not supprted");
57:
58: }
59:
60: protected function prefixField($prefix, $field)
61: {
62: if($prefix === null)
63: return $field;
64: return $prefix.'.'.$field;
65: }
66:
67: protected function normalizeOperatorCondition($condition)
68: {
69: $expanded = $this->driver->expandedGroup($condition);
70: $expanded->setLogic($condition->logic());
71:
72: return $expanded;
73: }
74:
75: protected function merge($left, $right)
76: {
77: if ($right->logic() === 'and') {
78: return $left->add($right);
79:
80: } elseif ($right->logic() === 'or') {
81: $p = $left->add($right, 'or');
82: return $p;
83:
84: } else {
85: $merged = $this->driver->expandedGroup();
86: $rightClone = clone $right;
87: $leftClone = clone $left;
88:
89: $merged->add($left);
90: $merged->add($rightClone->negate());
91:
92: $rightPart = $this->driver->expandedGroup();
93: $rightPart->add($leftClone->negate());
94: $rightPart->add($right);
95:
96: $merged->add($rightPart, 'or');
97: $merged->setLogic($left->logic());
98: return $merged;
99: }
100:
101: }
102:
103: protected function parseLogic($conditions)
104: {
105: $expanded = parent::parseLogic($conditions);
106:
107: if ($expanded === null)
108: $expanded = $this->driver->expandedGroup();
109:
110: return $expanded;
111: }
112:
113: public function parse($conditions, $convertMongoId = true)
114: {
115: $expanded = $this->parseLogic($conditions);
116:
117: $andGroups = array();
118: foreach ($expanded->groups() as $group) {
119: $andGroup = array();
120: foreach ($group as $condition) {
121: $condition = $this->operatorParser->parse($condition, $convertMongoId);
122:
123: foreach ($condition as $field => $fieldConditions) {
124: $appended = false;
125: foreach ($andGroup as $key=>$merged) {
126: if (!isset($merged[$field])) {
127: $andGroup[$key][$field] = $fieldConditions;
128: $appended = true;
129: break;
130: }
131: }
132: if (!$appended)
133: $andGroup[] = array($field => $fieldConditions);
134: }
135: }
136:
137: $count = count($andGroup);
138: if ($count === 1) {
139: $andGroup = current($andGroup);
140: } else {
141: $andGroup = array('$and' => $andGroup);
142: }
143: $andGroups[] = $andGroup;
144: }
145:
146: $count = count($andGroups);
147:
148: if ($count === 1) {
149: $andGroups = current($andGroups);
150:
151: } elseif($count > 1) {
152: $andGroups = array('$or' => $andGroups);
153: }
154:
155: return (object) $andGroups;
156:
157: }
158:
159: protected function copyLogicAndNegated($source, $target)
160: {
161: $target->setLogic($source->logic());
162: $target->setIsNegated($source->isNegated());
163:
164: return $target;
165: }
166:
167: }
168: