- Adapter some code to allow more flexibility for the new LDAP adapter from ulmus-ldap. - Insert's fields are now escaped by default. - A new RelationBuilder was added, a lot of code from the EntityTrait was moved into this. Some code from the Repository class will need to be moved there too.
326 lines
7.8 KiB
PHP
326 lines
7.8 KiB
PHP
<?php
|
|
|
|
namespace Ulmus;
|
|
|
|
use Generator;
|
|
|
|
class EntityCollection extends \ArrayObject {
|
|
|
|
public ? string $entityClass = null;
|
|
|
|
public function filters(Callable $callback, bool $yieldValueOnly = false) : Generator
|
|
{
|
|
$idx = 0;
|
|
|
|
foreach($this as $key => $item) {
|
|
if ( $callback($item, $key, $idx) ) {
|
|
$idx++;
|
|
|
|
if ( $yieldValueOnly ) {
|
|
yield $item;
|
|
}
|
|
else {
|
|
yield $key => $item;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function filtersCollection(Callable $callback, bool $replaceCollection = false) : self
|
|
{
|
|
$collection = new static();
|
|
|
|
foreach($this->filters($callback, true) as $item) {
|
|
$collection->append($item);
|
|
}
|
|
|
|
if ($replaceCollection) {
|
|
$this->exchangeArray(array_values($collection->getArrayCopy()));
|
|
|
|
return $this;
|
|
}
|
|
else {
|
|
return $collection;
|
|
}
|
|
}
|
|
|
|
public function iterate(Callable $callback) : self
|
|
{
|
|
foreach($this as $item) {
|
|
$callback($item);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeOne($value, string $field, bool $strict = true) : ? object
|
|
{
|
|
foreach($this->search($value, $field, $strict) as $key => $item) {
|
|
|
|
$this->offsetUnset($key);
|
|
|
|
return $item;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function remove($value, string $field, bool $strict = true) : array
|
|
{
|
|
$removed = [];
|
|
|
|
foreach($this->search($value, $field, $strict) as $key => $item) {
|
|
$this->offsetUnset($key);
|
|
|
|
$removed[] = $item;
|
|
}
|
|
|
|
return $removed;
|
|
}
|
|
|
|
public function clear() : self
|
|
{
|
|
$this->exchangeArray([]);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function search($value, string $field, bool $strict = true) : Generator
|
|
{
|
|
foreach($this->filters(fn($v) => $strict ? $v->$field === $value : $v->$field == $value) as $key => $item) {
|
|
yield $key => $item;
|
|
}
|
|
}
|
|
|
|
public function searchOne($value, string $field, bool $strict = true) : ? object
|
|
{
|
|
# Returning first value only
|
|
foreach($this->search($value, $field, $strict) as $item) {
|
|
return $item;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function searchAll($value, string $field, bool $strict = true) : self
|
|
{
|
|
$obj = new static();
|
|
|
|
foreach($this->search($value, $field, $strict) as $item) {
|
|
$obj->append($item);
|
|
}
|
|
|
|
return $obj;
|
|
}
|
|
|
|
public function searchInstances(string $className) : self
|
|
{
|
|
return $this->filtersCollection(fn($obj) => is_a($obj, $className));
|
|
}
|
|
|
|
public function column($field, bool $unique = false) : array
|
|
{
|
|
$list = [];
|
|
|
|
foreach($this as $item) {
|
|
if ( is_callable($field) ) {
|
|
$value = call_user_func_array($field, [ $item ]);
|
|
}
|
|
else {
|
|
$value = $item->$field;
|
|
}
|
|
|
|
if ($unique && in_array($value, $list, true)) {
|
|
continue;
|
|
}
|
|
|
|
$list[] = $value;
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
public function unique(/*stringable|callable */ $field, bool $strict = false) : self
|
|
{
|
|
$list = [];
|
|
$obj = new static();
|
|
|
|
foreach($this as $item) {
|
|
if ( $field === null) {
|
|
$value = $this;
|
|
}
|
|
if ( is_callable($field) ) {
|
|
$value = call_user_func_array($field, [ $item ]);
|
|
}
|
|
else {
|
|
$value = $item->$field;
|
|
}
|
|
|
|
if ( ! in_array($value, $list, $strict) ) {
|
|
$list[] = $value;
|
|
|
|
$obj->append($item);
|
|
}
|
|
}
|
|
|
|
return $obj;
|
|
}
|
|
|
|
public function first() : ? object
|
|
{
|
|
foreach($this as $item) {
|
|
return $item;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function last() : ? object
|
|
{
|
|
foreach($this as $item) {
|
|
$return = $item;
|
|
}
|
|
|
|
return $return ?? null;
|
|
}
|
|
|
|
public function buildArray(string $keyColumn, /* string|callable|null */ $value = null) : array
|
|
{
|
|
$list = [];
|
|
|
|
foreach($this as $item) {
|
|
switch (true) {
|
|
case is_null($value):
|
|
$list[] = $item->$keyColumn;
|
|
break;
|
|
|
|
case is_callable($value):
|
|
$list[$item->$keyColumn] = $value($item);
|
|
break;
|
|
|
|
case is_object($value):
|
|
case is_string($value):
|
|
$value = (string) $value;
|
|
|
|
$list[$item->$keyColumn] = $item->$value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
public function implode(string $glue, ? Callable $callback = null) : string
|
|
{
|
|
$values = [];
|
|
|
|
foreach($this as $item) {
|
|
$values[] = $callback ? $callback($item) : (string) $item;
|
|
}
|
|
|
|
return implode($glue, $values);
|
|
}
|
|
|
|
public function toArray(bool $includeRelations = false) : array {
|
|
$list = [];
|
|
|
|
foreach($this as $entity) {
|
|
$list[] = $entity->toArray($includeRelations);
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
public function fromArray(array $datasets, ? string /*stringable*/ $entityClass = null) : self
|
|
{
|
|
foreach($datasets as $dataset) {
|
|
$this->append( $this->arrayToEntity($dataset, $entityClass) );
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function arrayToEntity(array $dataset, ? string /*stringable*/ $entityClass = null) : object
|
|
{
|
|
if ( ! ($this->entityClass || $entityClass) ) {
|
|
throw new \Exception("An entity class name must be provided to be instanciated and populated before insertion into this collection.");
|
|
}
|
|
|
|
$className = $entityClass ?: $this->entityClass;
|
|
|
|
return ( new $className() )->fromArray($dataset);
|
|
}
|
|
|
|
public function append($value) : void
|
|
{
|
|
if ( is_array($value) ) {
|
|
$this->append( $this->arrayToEntity($value) );
|
|
}
|
|
else {
|
|
parent::append($value);
|
|
}
|
|
}
|
|
|
|
public function mergeWith(... $datasets) : self
|
|
{
|
|
$list = [];
|
|
|
|
foreach($datasets as $dataset) {
|
|
if ( is_object($dataset) ) {
|
|
$list = array_merge($dataset->getArrayCopy(), $list);
|
|
}
|
|
else {
|
|
$list = array_merge($dataset, $list);
|
|
}
|
|
}
|
|
|
|
$this->exchangeArray( array_merge( $this->getArrayCopy(), $list ) );
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function replaceWith( /*array|EntityCollection*/ $datasets ) : self
|
|
{
|
|
if ( is_object($datasets) ) {
|
|
$datasets = $datasets->getArrayCopy();
|
|
}
|
|
|
|
$this->exchangeArray( $datasets );
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function randomize() : self
|
|
{
|
|
$arr = $this->getArrayCopy();
|
|
shuffle($arr);
|
|
$this->exchangeArray($arr);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function sort(callable $callback, $function = "uasort") : self
|
|
{
|
|
call_user_func_array([ $this, $function ], [ $callback ]);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function rsort(callable $callback, $function = "uasort") : self
|
|
{
|
|
$this->sort(...func_get_args());
|
|
|
|
return $this->reverse();
|
|
}
|
|
|
|
public function reverse() : self
|
|
{
|
|
return $this->replaceWith(array_reverse($this->getArrayCopy()));;
|
|
}
|
|
|
|
public function slice(int $offset, ? int $length = null) : self
|
|
{
|
|
return new self(array_slice($this->getArrayCopy(), $offset, $length));
|
|
}
|
|
}
|