migrate therinaldos.com data
Build & Deploy to DigitalOcean Space / build (push) Failing after 2m38s

This commit is contained in:
2024-05-05 15:50:45 -04:00
commit ef1ff240d4
23182 changed files with 3801898 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2014 Fusonic GmbH (http://www.fusonic.net)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
<?php
/*
* This file is part of Fusonic-linq.
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq;
use Fusonic\Linq\Linq;
/**
* Class GroupedLinq
* Represents a Linq object that groups together other elements with a group key().
* @package Fusonic\Linq
*/
class GroupedLinq extends Linq
{
private $groupKey;
public function __construct($groupKey, $dataSource)
{
parent::__construct($dataSource);
$this->groupKey = $groupKey;
}
public function key()
{
return $this->groupKey;
}
}
@@ -0,0 +1,67 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Helper;
use ArrayIterator;
use InvalidArgumentException;
use UnexpectedValueException;
class LinqHelper
{
const MODE_ASSERT = 'MODE_ASSERT';
const MODE_NULL = 'MODE_NULL';
const LINQ_ORDER_ASC = 'asc';
const LINQ_ORDER_DESC = 'desc';
const LINQ_ORDER_TYPE_NUMERIC = 1;
const LINQ_ORDER_TYPE_ALPHANUMERIC = 2;
const LINQ_ORDER_TYPE_DATETIME = 3;
public static function getBoolOrThrowException($returned)
{
if (!is_bool($returned)) {
throw new UnexpectedValueException("Return type of filter func must be boolean.");
}
return $returned;
}
public static function assertArgumentIsIterable($param, $argumentName)
{
if (!self::isIterable($param)) {
throw new InvalidArgumentException("Argument must be an array, or implement either the \IteratorAggregate or \Iterator interface. ArgumentName = " . $argumentName);
}
}
public static function getIteratorOrThrow($value)
{
if (is_array($value)) {
return new ArrayIterator($value);
}
else if($value instanceof \IteratorAggregate) {
return $value->getIterator();
}
else if($value instanceof \Iterator) {
return $value;
}
throw new \UnexpectedValueException("Value must be an array, or implement either the \IteratorAggregate or \Iterator interface");
}
public static function isIterable($param)
{
return is_array($param)
|| $param instanceof \IteratorAggregate
|| $param instanceof \Iterator;
}
}
@@ -0,0 +1,62 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use Iterator;
class DistinctIterator extends \IteratorIterator
{
private $iterator;
private $distinct;
public function __construct(Iterator $iterator)
{
$this->iterator = $iterator;
}
public function current()
{
return $this->distinct->current();
}
public function next()
{
$this->distinct->next();
}
public function key()
{
return $this->distinct->key();
}
public function valid()
{
return $this->distinct->valid();
}
public function rewind()
{
if ($this->distinct === null) {
$this->getDistincts();
}
$this->distinct->rewind();
}
private function getDistincts()
{
$data = iterator_to_array($this->iterator);
$distinct = array_unique($data);
$this->distinct = new \ArrayIterator($distinct);
}
}
@@ -0,0 +1,65 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use ArrayIterator;
use Iterator;
class ExceptIterator implements Iterator
{
private $first;
private $second;
private $result;
public function __construct(Iterator $first, Iterator $second)
{
$this->first = $first;
$this->second = $second;
}
public function current()
{
return $this->result->current();
}
public function next()
{
$this->result->next();
}
public function key()
{
return $this->result->key();
}
public function valid()
{
return $this->result->valid();
}
public function rewind()
{
if ($this->result === null) {
$this->getResult();
}
$this->result->rewind();
}
private function getResult()
{
$firstArray = iterator_to_array($this->first);
$secondArray = iterator_to_array($this->second);
$this->result = new ArrayIterator(array_diff($firstArray, $secondArray));
}
}
@@ -0,0 +1,74 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use Iterator;
use ArrayIterator;
use Fusonic\Linq\GroupedLinq;
class GroupIterator implements Iterator
{
private $iterator;
private $grouped;
private $keySelector;
public function __construct($iterator, $keySelector)
{
$this->iterator = $iterator;
$this->keySelector = $keySelector;
}
public function current()
{
$current = $this->grouped->current();
return new GroupedLinq($current['key'], new \ArrayIterator($current['values']));
}
public function next()
{
$this->grouped->next();
}
public function key()
{
return $this->grouped->key();
}
public function valid()
{
return $this->grouped->valid();
}
public function rewind()
{
if ($this->grouped === null) {
$this->doGroup();
}
$this->grouped->rewind();
}
private function doGroup()
{
$keySelector = $this->keySelector;
$this->grouped = new \ArrayIterator(array());
foreach ($this->iterator as $value) {
$key = $keySelector($value);
if (!isset($this->grouped[$key])) {
$this->grouped[$key] = array('key' => $key, 'values'=> array());
}
$this->grouped[$key]['values'][] = $value;
}
}
}
@@ -0,0 +1,65 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use ArrayIterator;
use Iterator;
class IntersectIterator implements Iterator
{
private $first;
private $second;
private $intersections;
public function __construct(Iterator $first, Iterator $second)
{
$this->first = $first;
$this->second = $second;
}
public function current()
{
return $this->intersections->current();
}
public function next()
{
$this->intersections->next();
}
public function key()
{
return $this->intersections->key();
}
public function valid()
{
return $this->intersections->valid();
}
public function rewind()
{
if ($this->intersections === null) {
$this->calcIntersections();
}
$this->intersections->rewind();
}
private function calcIntersections()
{
$firstArray = iterator_to_array($this->first);
$secondArray = iterator_to_array($this->second);
$this->intersections = new ArrayIterator(array_intersect($firstArray, $secondArray));
}
}
@@ -0,0 +1,94 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Burgy Benjamin <benjamin.burgy@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use FilterIterator;
use Fusonic\Linq\Helper;
use Iterator;
/**
* Iterator for filtering the Linq query with a specified <b>type</b>.
* @package Fusonic\Linq\Iterator
*/
final class OfTypeIterator
extends
\FilterIterator
{
/**
* @var callable $acceptCallback
*/
private $acceptCallback;
/**
* Initializes an instance of <b>OfTypeIterator</b>.
*
* @param Iterator $iterator
* @param string $type
*/
public function __construct(Iterator $iterator, $type)
{
parent::__construct($iterator);
switch (strtolower($type))
{
case 'int':
case 'integer':
$this->acceptCallback = function ($current)
{
return is_int($current);
};
break;
case 'float':
case 'double':
$this->acceptCallback = function ($current)
{
return is_float($current);
};
break;
case 'string':
$this->acceptCallback = function ($current)
{
return is_string($current);
};
break;
case 'bool':
case 'boolean':
$this->acceptCallback = function ($current)
{
return is_bool($current);
};
break;
default:
$this->acceptCallback = function ($current) use ($type)
{
return $current instanceof $type;
};
}
}
/**
* (PHP 5 &gt;= 5.1.0)<br/>
* Check whether the current element of the iterator is acceptable
* @link http://php.net/manual/en/filteriterator.accept.php
* @return bool true if the current element is acceptable, otherwise false.
*/
public function accept()
{
/** @var mixed $current */
$current = $this->current();
/** @var callable $func */
$func = $this->acceptCallback;
return $func($current);
}
}
@@ -0,0 +1,113 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use Iterator;
use ArrayIterator;
use Fusonic\Linq;
use Fusonic\Linq\Helper;
class OrderIterator implements Iterator
{
private $iterator;
private $direction;
private $orderedIterator;
private $orderKeyFunc;
public function __construct(Iterator $items, $orderKeyFunc, $direction)
{
$this->iterator = $items;
$this->direction = $direction;
$this->orderKeyFunc = $orderKeyFunc;
}
public function current()
{
return $this->orderedIterator->current();
}
public function next()
{
$this->orderedIterator->next();
}
public function key()
{
return $this->orderedIterator->key();
}
public function valid()
{
return $this->orderedIterator->valid();
}
public function rewind()
{
if ($this->orderedIterator == null) {
$this->orderItems();
}
$this->orderedIterator->rewind();
}
public function orderItems()
{
$orderKeyFunc = $this->orderKeyFunc;
$direction = $this->direction;
$itemIterator = $this->iterator;
$itemIterator->rewind();
if (!$itemIterator->valid()) {
$this->orderedIterator = new ArrayIterator();
return;
}
$firstOrderKey = $orderKeyFunc($itemIterator->current());
$sortType = Helper\LinqHelper::LINQ_ORDER_TYPE_NUMERIC;
if ($firstOrderKey instanceof \DateTime) {
$sortType = Helper\LinqHelper::LINQ_ORDER_TYPE_DATETIME;
} elseif (!is_numeric($firstOrderKey)) {
$sortType = Helper\LinqHelper::LINQ_ORDER_TYPE_ALPHANUMERIC;
}
$keyMap = array();
$valueMap = array();
foreach ($itemIterator as $value) {
$orderKey = $orderKeyFunc != null ? $orderKeyFunc($value) : $value;
if ($sortType == Helper\LinqHelper::LINQ_ORDER_TYPE_DATETIME) {
$orderKey = $orderKey->getTimeStamp();
}
$keyMap[] = $orderKey;
$valueMap[] = $value;
}
if ($sortType == Helper\LinqHelper::LINQ_ORDER_TYPE_DATETIME) {
$sortType = Helper\LinqHelper::LINQ_ORDER_TYPE_NUMERIC;
}
if ($direction == Helper\LinqHelper::LINQ_ORDER_ASC) {
asort($keyMap, $sortType == Helper\LinqHelper::LINQ_ORDER_TYPE_NUMERIC ? SORT_NUMERIC : SORT_LOCALE_STRING);
} else {
arsort($keyMap, $sortType == Helper\LinqHelper::LINQ_ORDER_TYPE_NUMERIC ? SORT_NUMERIC : SORT_LOCALE_STRING);
}
$sorted = new ArrayIterator(array());
foreach ($keyMap as $key => $value) {
$sorted[] = $valueMap[$key];
}
$this->orderedIterator = $sorted;
}
}
@@ -0,0 +1,37 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use InvalidArgumentException;
use Iterator;
class SelectIterator extends \IteratorIterator
{
private $selector;
public function __construct(Iterator $iterator, $selector)
{
parent::__construct($iterator);
if ($selector === null) {
throw new InvalidArgumentException("Selector must not be null.");
}
$this->selector = $selector;
}
public function current()
{
$selector = $this->selector;
return $selector(parent::current());
}
}
@@ -0,0 +1,84 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use Iterator;
use Fusonic\Linq\Helper;
class SelectManyIterator implements Iterator
{
private $iterator;
private $currentIterator;
private $key = 0;
public function __construct(Iterator $iterator)
{
$this->iterator = $iterator;
}
public function current()
{
if ($this->currentIterator != null) {
return $this->currentIterator->current();
}
return null;
}
public function next()
{
if ($this->currentIterator != null) {
$this->currentIterator->next();
if (!$this->currentIterator->valid()) {
$this->iterator->next();
if ($this->iterator->valid()) {
$this->currentIterator = Helper\LinqHelper::getIteratorOrThrow($this->iterator->current());
if ($this->currentIterator != null) {
$this->currentIterator->rewind();
$this->key++;
}
}
} else {
$this->key++;
}
}
}
public function key()
{
return $this->key;
}
public function valid()
{
$current = $this->currentIterator;
return $current != null && $current->valid();
}
public function rewind()
{
$this->iterator->rewind();
if ($this->iterator->valid()) {
$current = $this->iterator->current();
$this->currentIterator = Helper\LinqHelper::getIteratorOrThrow($current);
if ($this->currentIterator != null) {
$this->currentIterator->rewind();
}
} else {
$this->currentIterator = null;
}
$this->key = 0;
}
}
@@ -0,0 +1,34 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq\Iterator;
use Iterator;
use Fusonic\Linq\Helper;
class WhereIterator extends \FilterIterator
{
private $func;
public function __construct(Iterator $iterator, $func)
{
parent::__construct($iterator);
$this->func = $func;
}
public function accept()
{
$func = $this->func;
$current = $this->current();
return Helper\LinqHelper::getBoolOrThrowException($func($current));
}
}
@@ -0,0 +1,732 @@
<?php
/*
* This file is part of Fusonic-linq.
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fusonic\Linq;
use Countable;
use Fusonic\Linq\Iterator\ExceptIterator;
use Fusonic\Linq\Iterator\DistinctIterator;
use Fusonic\Linq\Iterator\GroupIterator;
use Fusonic\Linq\Iterator\IntersectIterator;
use Fusonic\Linq\Iterator\OfTypeIterator;
use Fusonic\Linq\Iterator\OrderIterator;
use Fusonic\Linq\Iterator\SelectIterator;
use Fusonic\Linq\Iterator\SelectManyIterator;
use Fusonic\Linq\Iterator\WhereIterator;
use Fusonic\Linq\Helper\LinqHelper;
use IteratorAggregate;
use Traversable;
use UnexpectedValueException;
use InvalidArgumentException;
use OutOfRangeException;
/**
* Linq is a simple, powerful and consistent library for querying, projecting and aggregating data in php.
*
* @author David Roth <david.roth@fusonic.net>.
*/
class Linq implements IteratorAggregate, Countable
{
private $iterator;
/**
* Creates a new Linq object using the provided dataSource.
*
* @param array|\Iterator|IteratorAggregate $dataSource A Traversable sequence as data source.
*/
public function __construct($dataSource)
{
LinqHelper::assertArgumentIsIterable($dataSource, "dataSource");
$dataSource = LinqHelper::getIteratorOrThrow($dataSource);
$this->iterator = $dataSource;
}
/**
* Creates a new Linq object using the provided dataDataSource.
* This is the recommended way for getting a new Linq instance.
*
* @param array|\Iterator|IteratorAggregate $dataSource A Traversable sequence as data source.
* @return Linq
*/
public static function from($dataSource)
{
return new Linq($dataSource);
}
/**
* Generates a sequence of integral numbers within a specified range.
*
* @param $start The value of the first integer in the sequence.
* @param $count The number of sequential integers to generate.
* @return Linq An sequence that contains a range of sequential int numbers.
* @throws \OutOfRangeException
*/
public static function range($start, $count)
{
if ($count < 0) {
throw new OutOfRangeException('$count must be not be negative.');
}
return new Linq(range($start, $start + $count - 1));
}
/**
* Filters the Linq object according to func return result.
*
* @param callback $func A func that returns boolean
* @return Linq Filtered results according to $func
*/
public function where($func)
{
return new Linq(new WhereIterator($this->iterator, $func));
}
/**
* Filters the Linq object according to type.
*
* @param string $type
*
* @return Linq Filtered results according to $func
*/
public function ofType($type)
{
return new Linq(new OfTypeIterator($this->iterator, $type));
}
/**
* Bypasses a specified number of elements and then returns the remaining elements.
*
* @param int $count The number of elements to skip before returning the remaining elements.
* @return Linq A Linq object that contains the elements that occur after the specified index.
*/
public function skip($count)
{
// If its an array iterator we must check the arrays bounds are greater than the skip count.
// This is because the LimitIterator will use the seek() method which will throw an exception if $count > array.bounds.
$innerIterator = $this->iterator;
if ($innerIterator instanceof \ArrayIterator) {
if ($count >= $innerIterator->count()) {
return new Linq(array());
}
}
return new Linq(new \LimitIterator($innerIterator, $count, -1));
}
/**
* Returns a specified number of contiguous elements from the start of a sequence
*
* @param int $count The number of elements to return.
* @return Linq A Linq object that contains the specified number of elements from the start.
*/
public function take($count)
{
if ($count == 0) {
return new Linq(array());
}
return new Linq(new \LimitIterator($this->iterator, 0, $count));
}
/**
* Applies an accumulator function over a sequence.
* The aggregate method makes it simple to perform a calculation over a sequence of values.
* This method works by calling $func one time for each element.
* The first element of source is used as the initial aggregate value if $seed parameter is not specified.
* If $seed is specified, this value will be used as the first value.
*
* @param callback $func An accumulator function to be invoked on each element.
* @param mixed $seed
* @throws \RuntimeException if the input sequence contains no elements.
* @return mixed Returns the final result of $func.
*/
public function aggregate($func, $seed = null)
{
$result = null;
$first = true;
if ($seed !== null) {
$result = $seed;
$first = false;
}
foreach ($this->iterator as $current) {
if (!$first) {
$result = $func($result, $current);
} else {
$result = $current;
$first = false;
}
}
if ($first) {
throw new \RuntimeException("The input sequence contains no elements.");
}
return $result;
}
/**
* Splits the sequence in chunks according to $chunksize.
*
* @param $chunksize Specifies how many elements are grouped together per chunk.
* @throws \InvalidArgumentException
* @return Linq
*/
public function chunk($chunksize)
{
if ($chunksize < 1) {
throw new \InvalidArgumentException("chunksize", $chunksize);
}
$i = -1;
return $this->select(
function ($x) use (&$i) {
$i++;
return array("index" => $i, "value" => $x);
}
)
->groupBy(
function ($pair) use ($chunksize) {
return $pair["index"] / $chunksize;
}
)
->select(
function (GroupedLinq $group) {
return $group->select(
function ($v) {
return $v["value"];
}
);
}
);
}
/**
* Determines whether all elements satisfy a condition.
*
* @param callback $func A function to test each element for a condition.
* @return bool True if every element passes the test in the specified func, or if the sequence is empty; otherwise, false.
*/
public function all($func)
{
foreach ($this->iterator as $current) {
$match = LinqHelper::getBoolOrThrowException($func($current));
if (!$match) {
return false;
}
}
return true;
}
/**
* Determines whether any element exists or satisfies a condition by invoking $func.
*
* @param callback $func A function to test each element for a condition or NULL to determine if any element exists.
* @return bool True if no $func given and the source sequence contains any elements or True if any elements passed the test in the specified func; otherwise, false.
*/
public function any($func = null)
{
foreach ($this->iterator as $current) {
if ($func === null) {
return true;
}
$match = LinqHelper::getBoolOrThrowException($func($current));
if ($match) {
return true;
}
}
return false;
}
/**
* Counts the elements of this Linq sequence.
* @return int
*/
public function count()
{
if ($this->iterator instanceof Countable) {
return $this->iterator->count();
}
return iterator_count($this->iterator);
}
/**
* Computes the average of all numeric values. Uses $func to obtain the value on each element.
*
* @param callback $func A func that returns any numeric type (int, float etc.)
* @throws \UnexpectedValueException if an item of the sequence is not a numeric value.
* @return double Average of items
*/
public function average($func = null)
{
$resultTotal = 0;
$itemCount = 0;
$source = $this->getSelectIteratorOrInnerIterator($func);
foreach ($source as $item) {
if (!is_numeric($item)) {
throw new UnexpectedValueException("Cannot calculate an average on a none numeric value");
}
$resultTotal += $item;
$itemCount++;
}
return $itemCount == 0 ? 0 : ($resultTotal / $itemCount);
}
/**
* Sorts the elements in ascending order according to a key provided by $func.
*
* @param callback $func A function to extract a key from an element.
* @return Linq A new Linq instance whose elements are sorted ascending according to a key.
*/
public function orderBy($func)
{
return $this->order($func, LinqHelper::LINQ_ORDER_ASC);
}
/**
* Sorts the elements in descending order according to a key provided by $func.
*
* @param callback $func A function to extract a key from an element.
* @return Linq A new Linq instance whose elements are sorted descending according to a key.
*/
public function orderByDescending($func)
{
return $this->order($func, LinqHelper::LINQ_ORDER_DESC);
}
private function order($func, $direction = LinqHelper::LINQ_ORDER_ASC)
{
return new Linq(new OrderIterator($this->iterator, $func, $direction));
}
/**
* Gets the sum of all items or by invoking a transform function on each item to get a numeric value.
*
* @param callback $func A func that returns any numeric type (int, float etc.) from the given element, or NULL to use the element itself.
* @throws \UnexpectedValueException if any element is not a numeric value.
* @return double The sum of all items.
*/
public function sum($func = null)
{
$sum = 0;
$iterator = $this->getSelectIteratorOrInnerIterator($func);
foreach ($iterator as $value) {
if (!is_numeric($value)) {
throw new UnexpectedValueException("sum() only works on numeric values.");
}
$sum += $value;
}
return $sum;
}
/**
* Gets the minimum item value of all items or by invoking a transform function on each item to get a numeric value.
*
* @param callback $func A func that returns any numeric type (int, float etc.) from the given element, or NULL to use the element itself.
* @throws \RuntimeException if the sequence contains no elements
* @throws \UnexpectedValueException
* @return double Minimum item value
*/
public function min($func = null)
{
$min = null;
$iterator = $this->getSelectIteratorOrInnerIterator($func);
foreach ($iterator as $value) {
if (!is_numeric($value) && !is_string($value) && !($value instanceof \DateTime)) {
throw new UnexpectedValueException("min() only works on numeric values, strings and DateTime objects.");
}
if (is_null($min)) {
$min = $value;
} elseif ($min > $value) {
$min = $value;
}
}
if ($min === null) {
throw new \RuntimeException("Cannot calculate min() as the Linq sequence contains no elements.");
}
return $min;
}
/**
* Returns the maximum item value according to $func
*
* @param callback $func A func that returns any numeric type (int, float etc.)
* @throws \RuntimeException if the sequence contains no elements
* @throws \UnexpectedValueException if any element is not a numeric value or a string.
* @return double Maximum item value
*/
public function max($func = null)
{
$max = null;
$iterator = $this->getSelectIteratorOrInnerIterator($func);
foreach ($iterator as $value) {
if (!is_numeric($value) && !is_string($value) && !($value instanceof \DateTime)) {
throw new UnexpectedValueException("max() only works on numeric values, strings and DateTime objects.");
}
if (is_null($max)) {
$max = $value;
} elseif ($max < $value) {
$max = $value;
}
}
if ($max === null) {
throw new \RuntimeException("Cannot calculate max() as the Linq sequence contains no elements.");
}
return $max;
}
/**
* Projects each element into a new form by invoking the selector function.
*
* @param callback $func A transform function to apply to each element.
* @return Linq A new Linq object whose elements are the result of invoking the transform function on each element of the original Linq object.
*/
public function select($func)
{
return new Linq(new SelectIterator($this->iterator, $func));
}
/**
* Projects each element of a sequence to a new Linq and flattens the resulting sequences into one sequence.
*
* @param callback $func A func that returns a sequence (array, Linq, Iterator).
* @throws \UnexpectedValueException if an element is not a traversable sequence.
* @return Linq A new Linq object whose elements are the result of invoking the one-to-many transform function on each element of the input sequence.
*/
public function selectMany($func)
{
return new Linq(new SelectManyIterator(new SelectIterator($this->iterator, $func)));
}
/**
* Performs the specified action on each element of the Linq sequence and returns the Linq sequence.
* @param callback $func A func that will be evaluated for each item in the linq sequence.
* @return Linq The original Linq sequence that was used to perform the foreach.
*/
public function each($func)
{
foreach ($this->iterator as $item) {
$func($item);
}
return $this;
}
/**
* Determines whether a sequence contains a specified element.
* This function will use php strict comparison (===). If you need custom comparison use the Linq::any($func) method.
*
* @param mixed $value The value to locate in the sequence.
* @return bool True if $value is found within the sequence; otherwise false.
*/
public function contains($value)
{
return $this->any(
function ($x) use ($value) {
return $x === $value;
}
);
}
/**
* Concatenates this Linq object with the given sequence.
*
* @param array|\Iterator $second A sequence which will be concatenated with this Linq object.
* @throws InvalidArgumentException if the given sequence is not traversable.
* @return Linq A new Linq object that contains the concatenated elements of the input sequence and the original Linq sequence.
*/
public function concat($second)
{
LinqHelper::assertArgumentIsIterable($second, "second");
$allItems = new \ArrayIterator(array($this->iterator, $second));
return new Linq(new SelectManyIterator($allItems));
}
/**
* Returns distinct item values of this
*
* @param callback $func
* @return Linq Distinct item values of this
*/
public function distinct($func = null)
{
return new Linq(new DistinctIterator($this->getSelectIteratorOrInnerIterator($func)));
}
/**
* Intersects the Linq sequence with second Iterable sequence.
*
* @param \Iterator|array An iterator to intersect with:
* @return Linq intersected items
*/
public function intersect($second)
{
LinqHelper::assertArgumentIsIterable($second, "second");
return new Linq(new IntersectIterator($this->iterator, LinqHelper::getIteratorOrThrow($second)));
}
/**
* Returns all elements except the ones of the given sequence.
*
* @param array|\Iterator $second
* @return Linq Returns all items of this not occuring in $second
*/
public function except($second)
{
LinqHelper::assertArgumentIsIterable($second, "second");
return new Linq(new ExceptIterator($this->iterator, LinqHelper::getIteratorOrThrow($second)));
}
/**
* Returns the element at a specified index.
* This method throws an exception if index is out of range.
* To instead return NULL when the specified index is out of range, use the elementAtOrNull method.
*
* @throws \OutOfRangeException if index is less than 0 or greater than or equal to the number of elements in the sequence.
* @param int $index
* @return mixed Item at $index
*/
public function elementAt($index)
{
return $this->getValueAt($index, true);
}
/**
* Returns the element at a specified index or NULL if the index is out of range.
*
* @param $index
* @return mixed Item at $index
*/
public function elementAtOrNull($index)
{
return $this->getValueAt($index, false);
}
private function getValueAt($index, $throwEx)
{
$i = 0;
foreach ($this->iterator as $value) {
if ($i == $index) {
return $value;
}
$i++;
}
if ($throwEx) {
throw new OutOfRangeException("Index is less than 0 or greater than or equal to the number of elements in the sequence.");
}
return null;
}
/**
* Groups the object according to the $func generated key
*
* @param callback $keySelector a func that returns an item as key, item can be any type.
* @return GroupedLinq
*/
public function groupBy($keySelector)
{
return new Linq(new GroupIterator($this->iterator, $keySelector));
}
/**
* Returns the last element that satisfies a specified condition.
* @throws \RuntimeException if no element satisfies the condition in predicate or the source sequence is empty.
*
* @param callback $func a func that returns boolean.
* @return Object Last item in this
*/
public function last($func = null)
{
return $this->getLast($func, true);
}
/**
* Returns the last element that satisfies a condition or NULL if no such element is found.
*
* @param callback $func a func that returns boolean.
* @return mixed
*/
public function lastOrNull($func = null)
{
return $this->getLast($func, false);
}
/**
* Returns the first element that satisfies a specified condition
* @throws \RuntimeException if no element satisfies the condition in predicate -or- the source sequence is empty / does not match any elements.
*
* @param callback $func a func that returns boolean.
* @return mixed
*/
public function first($func = null)
{
return $this->getFirst($func, true);
}
/**
* Returns the first element, or NULL if the sequence contains no elements.
*
* @param callback $func a func that returns boolean.
* @return mixed
*/
public function firstOrNull($func = null)
{
return $this->getFirst($func, false);
}
/**
* Returns the only element that satisfies a specified condition.
*
* @throws \RuntimeException if no element exists or if more than one element exists.
* @param callback $func a func that returns boolean.
* @return mixed
*/
public function single($func = null)
{
return $this->getSingle($func, true);
}
/**
* Returns the only element that satisfies a specified condition or NULL if no such element exists.
*
* @throws \RuntimeException if more than one element satisfies the condition.
* @param callback $func a func that returns boolean.
* @return mixed
*/
public function singleOrNull($func = null)
{
return $this->getSingle($func, false);
}
private function getWhereIteratorOrInnerIterator($func)
{
return $func === null ? $this->iterator : new WhereIterator($this->iterator, $func);
}
private function getSelectIteratorOrInnerIterator($func)
{
return $func === null ? $this->iterator : new SelectIterator($this->iterator, $func);
}
private function getSingle($func, $throw)
{
$source = $this->getWhereIteratorOrInnerIterator($func);
$count = 0;
$single = null;
foreach ($source as $stored) {
$count++;
if ($count > 1) {
throw new \RuntimeException("The input sequence contains more than 1 elements.");
}
$single = $stored;
}
if ($count == 0 && $throw) {
throw new \RuntimeException("The input sequence contains no matching element.");
}
return $single;
}
private function getFirst($func, $throw)
{
$source = $this->getWhereIteratorOrInnerIterator($func);
$count = 0;
$first = null;
foreach ($source as $stored) {
$count++;
$first = $stored;
break;
}
if ($count == 0 && $throw) {
throw new \RuntimeException("The input sequence contains no matching element.");
}
return $first;
}
private function getLast($func, $throw)
{
$source = $this->getWhereIteratorOrInnerIterator($func);
$count = 0;
$last = null;
foreach ($source as $stored) {
$count++;
$last = $stored;
}
if ($count == 0 && $throw) {
throw new \RuntimeException("The input sequence contains no matching element.");
}
return $last;
}
/**
* Creates an Array from this Linq object with key/value selector(s).
*
* @param callback $keySelector a func that returns the array-key for each element.
* @param callback $valueSelector a func that returns the array-value for each element.
*
* @return Array An array with all values.
*/
public function toArray($keySelector = null, $valueSelector = null)
{
if ($keySelector === null && $valueSelector === null) {
return iterator_to_array($this, false);
} elseif ($keySelector == null) {
return iterator_to_array(new SelectIterator($this->getIterator(), $valueSelector), false);
} else {
$array = array();
foreach ($this as $value) {
$key = $keySelector($value);
$array[$key] = $valueSelector == null ? $value : $valueSelector($value);
}
return $array;
}
}
/**
* Retrieves the iterator of this Linq class.
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php
* @return Traversable An instance of an object implementing <b>Iterator</b> or
* <b>Traversable</b>
*/
public function getIterator()
{
return $this->iterator;
}
}