http://phing.info/

Source Code Coverage

Designed for use with PHPUnit2, Xdebug and Phing.

Methods: 16 LOC: 312 Statements: 67

Source file Statements Methods Total coverage
Query.php 97.0% 100.0% 97.6%
   
1
<?php
2
/**
3
 * Xyster Framework
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://www.opensource.org/licenses/bsd-license.php
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to xyster@devweblog.org so we can send you a copy immediately.
14
 *
15
 * @category  Xyster
16
 * @package   Xyster_Orm
17
 * @copyright Copyright (c) 2007 Irrational Logic (http://devweblog.org)
18
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
19
 * @version   $Id: Query.php 64 2007-08-12 18:54:56Z doublecompile $
20
 */
21
/**
22
 * @see Xyster_Orm_Query_Parser
23
 */
24 1
require_once 'Xyster/Orm/Query/Parser.php';
25
/**
26
 * A query object
27
 *
28
 * @category  Xyster
29
 * @package   Xyster_Orm
30
 * @copyright Copyright (c) 2007 Irrational Logic (http://devweblog.org)
31
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
32
 */
33
class Xyster_Orm_Query
34
{
35
    const WHERE = 'where';
36
    const ORDER = 'order';
37
    const LIMIT = 'limit';
38
    const OFFSET = 'offset';
39
40
    /**
41
     * The entity being queried
42
     *
43
     * @var string
44
     */
45
    protected $_class = '';
46
47
    /**
48
     * The parts of the query
49
     *
50
     * @var array
51
     */
52
    protected $_parts = array();
53
54
    /**
55
     * The parts of the query that can be used in the backend
56
     *
57
     * @var array
58
     */
59
    protected $_backend = array();
60
61
    /**
62
     * The orm manager
63
     *
64
     * @var Xyster_Orm_Manager
65
     */
66
    protected $_manager;
67
68
    /**
69
     * The query parser
70
     *
71
     * @var Xyster_Orm_Query_Parser
72
     */
73
    protected $_parser;
74
75
    /**
76
     * The parts of the query that must be used at runtime
77
     *
78
     * @var array
79
     */
80
    protected $_runtime = array();
81
82
    /**
83
     * Creates a new query object
84
     *
85
     * @param string $class  The entity to query
86
     */
87
    public function __construct( $class, Xyster_Orm_Manager $manager )
88
    {
89 38
        $this->_class = $class;
90 38
        $this->_manager = $manager;
91 38
        $this->_initParts();
92 38
        $this->_parser = new Xyster_Orm_Query_Parser($manager->getMapperFactory());
93
    }
94
95
    /**
96
     * Executes the query
97
     *
98
     * @return Xyster_Orm_Set
99
     */
100
    public function execute()
101
    {
102 2
        $map = $this->_manager->getMapperFactory()->get($this->_class);
103
104
        // execute the query in the backend
105 2
		$set = $this->_manager->executeQuery($this);
106
107
        // apply any runtime filters to the entity set
108 2
		if ( count($this->_runtime[self::WHERE]) ) {
109 1
    		$set->filter(Xyster_Data_Criterion::fromArray('AND', $this->_runtime[self::WHERE]));
110 1
		}
111
112
		// if the query is runtime, enforce the offset and limit
113 2
		if ( ( $this->_parts[self::LIMIT] || $this->_parts[self::OFFSET] )
114 2
		    && $this->isRuntime() ) {
115 1
			$entities = $map->getSet();
116 1
			$offset = 0;
117 1
			foreach( $set as $entity ) {
118 1
				if ( $offset < $this->_parts[self::OFFSET] ) {
119 1
				    $offset++;
120 1
				} else {
121 1
				    $entities->add($entity);
122
				}
123 1
				if ( $this->_parts[self::LIMIT] && count($entities) == $this->_parts[self::LIMIT] ) {
124 1
				    break;
125 0
				}
126 1
			}
127 1
			$set = $entities;
128 1
		}
129
130
		// apply any runtime sort ordering to the entity set
131 2
		if ( $this->_runtime[self::ORDER] ) {
132 1
			$set->sortBy($this->_parts[self::ORDER]);
133 1
		}
134 2
		return $set;
135
    }
136
137
    /**
138
     * Gets the criteria that can be run in the backend
139
     *
140
     * @return array
141
     */
142
    public function getBackendWhere()
143
    {
144 15
        return $this->_backend[self::WHERE];
145
    }
146
147
    /**
148
     * Gets the entity class being queried
149
     *
150
     * @return string the entity class name
151
     */
152
    public function getFrom()
153
    {
154 13
        return $this->_class;
155
    }
156
157
    /**
158
     * Gets the maximum number of results to be returned
159
     *
160
     * @return int the maximum result count
161
     */
162
    public function getLimit()
163
    {
164 5
        return $this->getPart(self::LIMIT);
165
    }
166
167
    /**
168
     * Gets the starting point in the results
169
     *
170
     * @return int the offset starting point
171
     */
172
    public function getOffset()
173
    {
174 4
        return $this->getPart(self::OFFSET);
175
    }
176
177
    /**
178
     * Gets the order clause (an array of {@link Xyster_Data_Sort} objects)
179
     *
180
     * @return array
181
     */
182
    public function getOrder()
183
    {
184 13
        return $this->getPart(self::ORDER);
185
    }
186
187
    /**
188
     * Gets a part of the query
189
     *
190
     * @param string $part one of the class constants
191
     * @return mixed
192
     */
193
    public function getPart( $part )
194
    {
195 28
        return ( array_key_exists($part, $this->_parts) ) ?
196 28
            $this->_parts[$part] : null;
197
    }
198
199
    /**
200
     * Gets the where clause (an array of {@link Xyster_Data_Criterion} objects)
201
     *
202
     * @return array
203
     */
204
    public function getWhere()
205
    {
206 7
        return $this->getPart(self::WHERE);
207
    }
208
209
    /**
210
     * Gets whether this query has an order clause that evaluates at runtime
211
     *
212
     * @return boolean
213
     */
214
    public function hasRuntimeOrder()
215
    {
216 25
        return (bool) $this->_runtime[self::ORDER];
217
    }
218
219
    /**
220
     * Gets whether this query has a where clause that evaluates at runtime
221
     *
222
     * @return boolean
223
     */
224
    public function hasRuntimeWhere()
225
    {
226 20
        return count($this->_runtime[self::WHERE]) > 0;
227
    }
228
229
    /**
230
     * Gets whether this query has parts that are evaluated at runtime
231
     *
232
     * @return boolean
233
     */
234
    public function isRuntime()
235
    {
236 25
        return $this->hasRuntimeOrder() || $this->hasRuntimeWhere();
237
    }
238
239
    /**
240
     * Impose a maximum number of records to return and a number to skip
241
     *
242
     * @param int $limit The maximum number of records to return
243
     * @param int $offset The number of records to skip
244
     * @return Xyster_Orm_Query provides a fluent interface
245
     */
246
    public function limit( $limit, $offset=0 )
247
    {
248 9
        $this->_parts[self::LIMIT] = intval($limit);
249 9
        $this->_parts[self::OFFSET] = intval($offset);
250 9
        return $this;
251
    }
252
253
    /**
254
     * Adds a sorting to the results
255
     *
256
     * @param Xyster_Data_Sort $order
257
     * @return Xyster_Orm_Query provides a fluent interface
258
     */
259
    public function order( Xyster_Data_Sort $order )
260
    {
261 11
        $this->_parser->assertValidFieldForClass($order->getField(), $this->_class);
262 11
        $this->_runtime[self::ORDER] |= $this->_parser->isRuntime($order, $this->_class);
263
264 11
        $this->_parts[self::ORDER][] = $order;
265
266 11
        return $this;
267
    }
268
269
    /**
270
     * Adds a criterion to the selection
271
     *
272
     * @param Xyster_Data_Criterion $where
273
     * @return Xyster_Orm_Query provides a fluent interface
274
     */
275
    public function where( Xyster_Data_Criterion $where )
276
    {
277 18
        foreach( Xyster_Data_Criterion::getFields($where) as $field ) {
278 18
            if ( $field instanceof Xyster_Data_Field_Aggregate ) {
279 2
                require_once 'Xyster/Orm/Query/Exception.php';
280 2
                throw new Xyster_Orm_Query_Exception('Aggregated fields are not allowed in this query');
281 0
            }
282 16
            $this->_parser->assertValidFieldForClass($field, $this->_class);
283 16
        }
284
285 16
        if ( $this->_parser->isRuntime($where, $this->_class) ) {
286 8
            $this->_runtime[self::WHERE][] = $where;
287 8
        } else {
288 13
            $this->_backend[self::WHERE][] = $where;
289
        }
290
291 16
        $this->_parts[self::WHERE][] = $where;
292
293 16
        return $this;
294
    }
295
296
    /**
297
     * Initializes the parts container
298
     *
299
     */
300
    protected function _initParts()
301
    {
302 38
        $this->_parts[self::LIMIT] = 0;
303 38
        $this->_parts[self::OFFSET] = 0;
304 38
        $this->_parts[self::WHERE] = array();
305 38
        $this->_parts[self::ORDER] = array();
306
307 38
        $this->_runtime[self::WHERE] = array();
308 38
        $this->_runtime[self::ORDER] = false;
309
310 38
        $this->_backend[self::WHERE] = array();
311
    }
312
}


Report generated at 2007-10-08T19:32:23-05:00