1: <?php
2: /*
3: You may not change or alter any portion of this comment or credits
4: of supporting developers from this source code or any supporting source code
5: which is considered copyrighted (c) material of the original comment or credit authors.
6:
7: This program is distributed in the hope that it will be useful,
8: but WITHOUT ANY WARRANTY; without even the implied warranty of
9: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10: */
11:
12: namespace Xoops\Core\Kernel;
13:
14: use Doctrine\DBAL\Query\QueryBuilder;
15:
16: /**
17: * Collection of multiple CriteriaElement objects
18: *
19: * @category Xoops\Core\Kernel\CriteriaCompo
20: * @package Xoops\Core\Kernel
21: * @author Kazumi Ono <onokazu@xoops.org>
22: * @author Nathan Dial <ndial@trillion21.com>
23: * @author Taiwen Jiang <phppp@users.sourceforge.net>
24: * @copyright 2000-2013 XOOPS Project (http://xoops.org)
25: * @license GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
26: * @link http://xoops.org
27: * @since 2.0.0
28: */
29: class CriteriaCompo extends CriteriaElement
30: {
31: /**
32: * The elements of the collection
33: *
34: * @var CriteriaElement[] array of objects
35: */
36: protected $criteriaElements = array();
37:
38: /**
39: * Conditions
40: *
41: * @var array
42: */
43: protected $conditions = array();
44:
45: /**
46: * Constructor
47: *
48: * @param CriteriaElement|null $ele a criteria element to start the compo
49: * @param string $condition joining condition for element, AND or OR
50: */
51: public function __construct(CriteriaElement $ele = null, $condition = 'AND')
52: {
53: if (isset($ele)) {
54: $this->add($ele, $condition);
55: }
56: }
57:
58: /**
59: * add a criteria element
60: *
61: * @param CriteriaElement $criteriaElement a criteria element to add to the compo
62: * @param string $condition joining condition for element, AND or OR
63: *
64: * @return CriteriaCompo
65: */
66: public function add(CriteriaElement $criteriaElement, $condition = 'AND')
67: {
68: $this->criteriaElements[] = $criteriaElement;
69: $this->conditions[] = $condition;
70: return $this;
71: }
72:
73: /**
74: * Make the criteria into a query string
75: *
76: * @return string
77: */
78: public function render()
79: {
80: $ret = '';
81: foreach ($this->criteriaElements as $i => $element) {
82: if (!is_object($element)) {
83: continue;
84: }
85: /* @var $element CriteriaElement */
86: if ($i == 0) {
87: $ret = $element->render();
88: } else {
89: if (!$render = $element->render()) {
90: continue;
91: }
92: $ret .= ' ' . $this->conditions[$i] . ' (' . $render . ')';
93: }
94: $ret = "({$ret})";
95: }
96: $ret = ($ret==='()') ? '(1)' : $ret;
97: return $ret;
98: }
99:
100: /**
101: * Make the criteria into a SQL "WHERE" clause
102: *
103: * @return string
104: */
105: public function renderWhere()
106: {
107: $ret = $this->render();
108: $ret = ($ret != '') ? 'WHERE ' . $ret : $ret;
109: return $ret;
110: }
111:
112: /**
113: * Generate an LDAP filter from criteria
114: *
115: * @return string
116: * @author Nathan Dial ndial@trillion21.com
117: */
118: public function renderLdap()
119: {
120: $ret = '';
121: foreach ($this->criteriaElements as $i => $element) {
122: /* @var $element CriteriaElement */
123: if ($i == 0) {
124: $ret = $element->renderLdap();
125: } else {
126: $cond = strtoupper($this->conditions[$i]);
127: $op = ($cond === "OR") ? "|" : "&";
128: $ret = "({$op}{$ret}" . $element->renderLdap() . ")";
129: }
130: }
131: return $ret;
132: }
133:
134: /**
135: * Render as Doctrine QueryBuilder instructions
136: *
137: * @param QueryBuilder $qb query builder instance
138: * @param string $whereMode how does this fit in the passed in QueryBuilder?
139: * '' = as where,'and'= as andWhere, 'or' = as orWhere
140: *
141: * @return QueryBuilder query builder instance
142: */
143: public function renderQb(QueryBuilder $qb = null, $whereMode = '')
144: {
145: if ($qb==null) {
146: $qb = \Xoops::getInstance()->db()->createXoopsQueryBuilder();
147: $whereMode = ''; // first entry in new instance must be where
148: }
149:
150: $expr = '';
151: foreach ($this->criteriaElements as $i => $element) {
152: $expr_part = $element->buildExpressionQb($qb);
153: if ($expr_part !== false) {
154: if ($i == 0) {
155: $expr = $expr_part;
156: } else {
157: $expr .= ' ' . strtoupper($this->conditions[$i]) . ' ' . $expr_part;
158: }
159: }
160: }
161:
162: if (!empty($expr)) {
163: $expr = '(' . $expr . ')'; // group all conditions in this compo
164:
165: switch (strtolower($whereMode)) {
166: case 'and':
167: $qb->andWhere($expr);
168: break;
169: case 'or':
170: $qb->orWhere($expr);
171: break;
172: case '':
173: $qb->where($expr);
174: break;
175: }
176: }
177:
178: if ($this->limit!=0 || $this->start!=0) {
179: $qb->setFirstResult($this->start)
180: ->setMaxResults($this->limit);
181: }
182:
183: if (!empty($this->groupBy)) {
184: $qb->groupBy($this->groupBy);
185: }
186:
187: if (!empty($this->sort)) {
188: $qb->orderBy($this->sort, $this->order);
189: }
190: return $qb;
191: }
192:
193: /**
194: * Build an expression to be included in a Doctrine QueryBuilder instance.
195: *
196: * This method will build an expression, adding any parameters to the query,
197: * but the caller is responsible for adding the expression to the query, for
198: * example as where() parameter. This allows the caller to handle all context,
199: * such as parenthetical groupings.
200: *
201: * @param QueryBuilder $qb query builder instance
202: *
203: * @return string expression
204: */
205: public function buildExpressionQb(QueryBuilder $qb)
206: {
207: $expr = false;
208: foreach ($this->criteriaElements as $i => $element) {
209: $expr_part = $element->buildExpressionQb($qb);
210: if ($expr_part !== false) {
211: if ($i == 0) {
212: $expr = $expr_part;
213: } else {
214: $expr .= ' ' . strtoupper($this->conditions[$i]) . ' ' . $expr_part;
215: }
216: }
217: }
218:
219: if (!empty($expr)) {
220: $expr = '(' . $expr . ')'; // group all conditions in this compo
221: }
222: return $expr;
223: }
224: }
225: