ulmus/src/EntityCollection.php

322 lines
7.6 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 = $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()));;
}
}