Source for file LinqToObjects.php
Documentation is available at LinqToObjects.php
* Copyright (c) 2008 - 2009 PHPLinq
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* @copyright Copyright (c) 2008 - 2009 PHPLinq (http://www.codeplex.com/PHPLinq)
* @license http://www.gnu.org/licenses/lgpl.txt LGPL
* @version 0.4.0, 2009-01-27
require_once('PHPLinq.php');
/** PHPLinq_ILinqProvider */
require_once('PHPLinq/ILinqProvider.php');
/** PHPLinq_Expression */
require_once('PHPLinq/Expression.php');
/** PHPLinq_OrderByExpression */
require_once('PHPLinq/OrderByExpression.php');
require_once('PHPLinq/Initiator.php');
/** Register ILinqProvider */
* @copyright Copyright (c) 2008 - 2009 PHPLinq (http://www.codeplex.com/PHPLinq)
* @var PHPLinq_Expression
* Take while expression is true
* @var PHPLinq_Expression
* Skip while expression is true
* @var PHPLinq_Expression
* @var PHPLinq_Expression[]
* @var PHPLinq_Expression
* @var PHPLinq_Expression
* Parent PHPLinq_ILinqProvider instance, used with join conditions
* @var PHPLinq_ILinqProvider
* Child PHPLinq_ILinqProvider instances, used with join conditions
* @var PHPLinq_ILinqProvider[]
* @var PHPLinq_Expression
* Can this provider type handle data in $source?
public static function handles($source) {
* Create a new class instance
* @param PHPLinq_ILinqProvider $parentProvider Optional parent PHPLinq_ILinqProvider instance, used with join conditions
* @return PHPLinq_ILinqProvider
public function __construct($name, PHPLinq_ILinqProvider $parentProvider = null) {
$parentProvider->addChildProvider($this);
* @return PHPLinq_Expression
* Add child provider, used with joins
* @param PHPLinq_ILinqProvider $provider
* Retrieve data in data source
* @return PHPLinq_ILinqProvider
public function in($source) {
* @param string $expression Expression which creates a resulting element
public function select($expression = null) {
if (is_null($expression) || $expression == '') {
$expression = $this->_from . ' => ' . $this->_from;
// Is there only one OrderBy expression?
$sorter = $this->_orderBy[0]->getFunctionReference();
// Create OrderBy expression
// Compile comparer function
\$result = call_user_func_array(chr(0).'$f', array({$this->_from}A, { $this->_from}B));
$compareCode .= "return \$result;";
$sorter = create_function($this->_from . 'A, ' . $this->_from . 'B', $compareCode);
usort($this->_data, $sorter);
// Build possible join data
foreach ($this->_data as $value) {
$joinedData[$this->_from][] = $value;
// Fetch possible join data
foreach ($provider->select() as $record) {
$joinValid = $provider->getJoinCondition()->execute( array( $this->_from => $value, $provider->getFromName() => $record ) );
$joinedData[$provider->getFromName()][] = $record;
/** BEGIN CARTESIAN JOIN */
$joinedDataKeys = array_keys($joinedData);
// Calculate expected size of $joinable
$size = (count($joinedData) > 0 ? 1 : 0);
foreach ($joinedData as $values) {
$size = $size * count($values);
// Create cartesian array
for ($i = 0; $i < $size; $i++) {
for ($j = 0; $j < count($joinedData); $j++) {
array_push($joinable[$i], current($joinedData[$joinedDataKeys[$j]]));
// Set cursor on next element in the $joinedData, beginning with the last array
for ($j = (count($joinedData)-1); $j >= 0; $j--) {
// If next returns true, then break
if (next($joinedData[$joinedDataKeys[$j]])) {
// If next returns false, then reset and go on with previous $joinedData...
reset($joinedData[$joinedDataKeys[$j]]);
/** END CARTESIAN JOIN */
// Join values using selector expression
foreach ($joinable as $values) {
if (count($dataSource) == 0) {
$dataSource = $this->_data;
// Distinct values storage
$distinctValues = array();
// Create selector expression
$selector = new PHPLinq_Expression($expression, $this->_from);
// Loop trough data source
foreach ($dataSource as $value) {
// Is it a valid element?
// OfType expresion set? Evaluate it!
if ($isValid && !is_null($this->_ofType)) {
$isValid = $this->_ofType->execute($value);
// Where expresion set? Evaluate it!
if ($isValid && !is_null($this->_where)) {
$isValid = $this->_where->execute($value);
// Distinct expression set? Evaluate it!
if ($isValid && !is_null($this->_distinct)) {
$distinctKey = $this->_distinct->execute($value);
if (isset($distinctValues[$distinctKey])) {
$distinctValues[$distinctKey] = 1;
// The element is valid, check if it is our selection range
if (!is_null($this->_skip) && $elementCount < $this->_skip) {
if (!is_null($this->_take) && count($returnValue) >= $this->_take) {
// Add the element to the return value if it is a valid element
$returnValue[] = $selector->execute($value);
* @param string $expression Expression checking if an element should be contained
* @return PHPLinq_ILinqProvider
public function where($expression) {
$this->_where = !is_null($expression) ? new PHPLinq_Expression($expression, $this->_from) : null;
* @return PHPLinq_ILinqProvider
public function take($n) {
* @return PHPLinq_ILinqProvider
public function skip($n) {
* Take elements while $expression evaluates to true
* @param string $expression Expression to evaluate
* @return PHPLinq_ILinqProvider
public function takeWhile($expression) {
$this->_takeWhile = !is_null($expression) ? new PHPLinq_Expression($expression, $this->_from) : null;
* Skip elements while $expression evaluates to true
* @param string $expression Expression to evaluate
* @return PHPLinq_ILinqProvider
public function skipWhile($expression) {
$this->_skipWhile = !is_null($expression) ? new PHPLinq_Expression($expression, $this->_from) : null;
* @param string $expression Expression to order elements by
* @param string $comparer Comparer function (taking 2 arguments, returning -1, 0, 1)
* @return PHPLinq_ILinqProvider
public function orderBy($expression, $comparer = null) {
$this->_orderBy[0] = new PHPLinq_OrderByExpression($expression, $this->_from, false, $comparer);
* @param string $expression Expression to order elements by
* @param string $comparer Comparer function (taking 2 arguments, returning -1, 0, 1)
* @return PHPLinq_ILinqProvider
public function orderByDescending($expression, $comparer = null) {
$this->_orderBy[0] = new PHPLinq_OrderByExpression($expression, $this->_from, true, $comparer);
* @param string $expression Expression to order elements by
* @param string $comparer Comparer function (taking 2 arguments, returning -1, 0, 1)
* @return PHPLinq_ILinqProvider
public function thenBy($expression, $comparer = null) {
$this->_orderBy[] = new PHPLinq_OrderByExpression($expression, $this->_from, false, $comparer);
* @param string $expression Expression to order elements by
* @param string $comparer Comparer function (taking 2 arguments, returning -1, 0, 1)
* @return PHPLinq_ILinqProvider
public function thenByDescending($expression, $comparer = null) {
$this->_orderBy[] = new PHPLinq_OrderByExpression($expression, $this->_from, true, $comparer);
* @param string $expression Expression to retrieve the key value.
* @return PHPLinq_ILinqProvider
public function distinct($expression) {
$this->_distinct = !is_null($expression) ? new PHPLinq_Expression($expression, $this->_from) : null;
* Select the elements of a certain type
* @param string $type Type name
public function ofType($type) {
// Create a new expression
$expression = $this->_from . ' => ';
$expression .= 'is_a(' . $this->_from . ', "' . $type . '")';
$this->_ofType = new <a href="../PHPLinq/PHPLinq_Expression.html">PHPLinq_Expression</a>($expression, $this->_from);
* @param string $expression Expression checking if an element is contained
public function any($expression) {
$originalWhere = $this->_where;
$result = $this->where($expression)->select($this->_from);
$this->_where = $originalWhere;
return count($result) > 0;
* @param string $expression Expression checking if an all elements are contained
public function all($expression) {
$originalWhere = $this->_where;
$result = $this->where($expression)->select($this->_from);
$this->_where = $originalWhere;
* @param mixed $element Is the $element contained?
* @param bool $preserveKeys Preserve keys?
* @return PHPLinq_ILinqProvider
public function reverse($preserveKeys = null) {
* @param mixed $index Index
* @return mixed Element at $index
$originalWhere = $this->_where;
$result = isset($this->_data[$index]) ? $this->_data[$index] : null;
$this->_where = $originalWhere;
if (count($result) > 0) {
* Element at index or default
* @param mixed $index Index
* @param mixed $defaultValue Default value to return if nothing is found
* @return mixed Element at $index
* @return PHPLinq_ILinqProvider
public function concat($source) {
* @param string $expression Expression which creates a resulting element
public function first($expression = null) {
$linqCommand = clone $this;
$result = $linqCommand->skip(0)->take(1)->select($expression);
if (count($result) > 0) {
* @param string $expression Expression which creates a resulting element
* @param mixed $defaultValue Default value to return if nothing is found
public function firstOrDefault ($expression = null, $defaultValue = null) {
$returnValue = $this->first($expression);
* @param string $expression Expression which creates a resulting element
public function last($expression = null) {
$linqCommand = clone $this;
$result = $linqCommand->reverse()->skip(0)->take(1)->select($expression);
if (count($result) > 0) {
* @param string $expression Expression which creates a resulting element
* @param mixed $defaultValue Default value to return if nothing is found
public function lastOrDefault ($expression = null, $defaultValue = null) {
$returnValue = $this->last($expression);
* @param string $expression Expression which creates a resulting element
public function single($expression = null) {
return $this->first($expression);
* @param string $expression Expression which creates a resulting element
* @param mixed $defaultValue Default value to return if nothing is found
public function singleOrDefault ($expression = null, $defaultValue = null) {
* @return PHPLinq_Initiator
public function join($name) {
return new <a href="../PHPLinq/PHPLinq_Initiator.html">PHPLinq_Initiator</a>($name, $this);
* @param string $expression Expression representing join condition
* @return PHPLinq_ILinqProvider
public function on($expression) {
$this->_joinCondition = new <a href="../PHPLinq/PHPLinq_Expression.html">PHPLinq_Expression</a>($expression, $this->_from);
* @return int Element count
public function count() {
* @return mixed Sum of elements
return array_sum($this->_data); // $this->aggregate(0, '$s, $t => $s + $t');
* @return mixed Minimum of elements
* @return mixed Maximum of elements
* @return mixed Average of elements
* Example: Equivalent of count(): $this->aggregate(0, '$s, $t => $s + 1');
* @param string $expression Expression defining the aggregate
* @return mixed aggregate
public function aggregate($seed = 0, $expression) {
$codeExpression = new <a href="../PHPLinq/PHPLinq_Expression.html">PHPLinq_Expression</a>($expression);
foreach ($this->_data as $value) {
$runningValue = $codeExpression->execute( array($runningValue, $value) );
|