mirror of
https://devops.lemonos.cn/lawson/FendxPHP.git
synced 2026-06-15 23:12:49 +08:00
441 lines
8.5 KiB
PHP
441 lines
8.5 KiB
PHP
|
|
<?php
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace App\Dto;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 数据集合传输对象
|
||
|
|
*/
|
||
|
|
class CollectionDto extends BaseDto
|
||
|
|
{
|
||
|
|
private array $items = [];
|
||
|
|
|
||
|
|
private int $count = 0;
|
||
|
|
|
||
|
|
private array $meta = [];
|
||
|
|
|
||
|
|
public function __construct(array $items = [])
|
||
|
|
{
|
||
|
|
$this->items = $items;
|
||
|
|
$this->count = count($items);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getItems(): array
|
||
|
|
{
|
||
|
|
return $this->items;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setItems(array $items): self
|
||
|
|
{
|
||
|
|
$this->items = $items;
|
||
|
|
$this->count = count($items);
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getCount(): int
|
||
|
|
{
|
||
|
|
return $this->count;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getMeta(): array
|
||
|
|
{
|
||
|
|
return $this->meta;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setMeta(array $meta): self
|
||
|
|
{
|
||
|
|
$this->meta = $meta;
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 添加项目
|
||
|
|
*/
|
||
|
|
public function add(mixed $item): self
|
||
|
|
{
|
||
|
|
$this->items[] = $item;
|
||
|
|
$this->count++;
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 添加元数据
|
||
|
|
*/
|
||
|
|
public function addMeta(string $key, mixed $value): self
|
||
|
|
{
|
||
|
|
$this->meta[$key] = $value;
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 检查是否为空
|
||
|
|
*/
|
||
|
|
public function isEmpty(): bool
|
||
|
|
{
|
||
|
|
return $this->count === 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 检查是否不为空
|
||
|
|
*/
|
||
|
|
public function isNotEmpty(): bool
|
||
|
|
{
|
||
|
|
return $this->count > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取第一个项目
|
||
|
|
*/
|
||
|
|
public function first(): mixed
|
||
|
|
{
|
||
|
|
return $this->items[0] ?? null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取最后一个项目
|
||
|
|
*/
|
||
|
|
public function last(): mixed
|
||
|
|
{
|
||
|
|
return $this->items[$this->count - 1] ?? null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取指定索引的项目
|
||
|
|
*/
|
||
|
|
public function get(int $index): mixed
|
||
|
|
{
|
||
|
|
return $this->items[$index] ?? null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 映射集合
|
||
|
|
*/
|
||
|
|
public function map(callable $callback): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$new->items = array_map($callback, $this->items);
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 过滤集合
|
||
|
|
*/
|
||
|
|
public function filter(callable $callback): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$new->items = array_filter($this->items, $callback);
|
||
|
|
$new->count = count($new->items);
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 排序集合
|
||
|
|
*/
|
||
|
|
public function sort(callable $callback): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$items = $this->items;
|
||
|
|
usort($items, $callback);
|
||
|
|
$new->items = $items;
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 反转集合
|
||
|
|
*/
|
||
|
|
public function reverse(): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$new->items = array_reverse($this->items);
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取唯一的集合
|
||
|
|
*/
|
||
|
|
public function unique(): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$new->items = array_unique($this->items);
|
||
|
|
$new->count = count($new->items);
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 切片集合
|
||
|
|
*/
|
||
|
|
public function slice(int $offset, ?int $length = null): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$new->items = array_slice($this->items, $offset, $length);
|
||
|
|
$new->count = count($new->items);
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 限制集合大小
|
||
|
|
*/
|
||
|
|
public function take(int $limit): self
|
||
|
|
{
|
||
|
|
return $this->slice(0, $limit);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 跳过指定数量
|
||
|
|
*/
|
||
|
|
public function skip(int $count): self
|
||
|
|
{
|
||
|
|
return $this->slice($count);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 分块集合
|
||
|
|
*/
|
||
|
|
public function chunk(int $size): array
|
||
|
|
{
|
||
|
|
return array_chunk($this->items, $size);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 求和
|
||
|
|
*/
|
||
|
|
public function sum(callable|string $key = null): float
|
||
|
|
{
|
||
|
|
if ($key === null) {
|
||
|
|
return array_sum($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_callable($key)) {
|
||
|
|
return array_sum(array_map($key, $this->items));
|
||
|
|
}
|
||
|
|
|
||
|
|
return array_sum(array_column($this->items, $key));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 求平均值
|
||
|
|
*/
|
||
|
|
public function avg(callable|string $key = null): float
|
||
|
|
{
|
||
|
|
if ($this->isEmpty()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->sum($key) / $this->count;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 求最大值
|
||
|
|
*/
|
||
|
|
public function max(callable|string $key = null): mixed
|
||
|
|
{
|
||
|
|
if ($this->isEmpty()) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($key === null) {
|
||
|
|
return max($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_callable($key)) {
|
||
|
|
$values = array_map($key, $this->items);
|
||
|
|
return max($values);
|
||
|
|
}
|
||
|
|
|
||
|
|
return max(array_column($this->items, $key));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 求最小值
|
||
|
|
*/
|
||
|
|
public function min(callable|string $key = null): mixed
|
||
|
|
{
|
||
|
|
if ($this->isEmpty()) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($key === null) {
|
||
|
|
return min($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_callable($key)) {
|
||
|
|
$values = array_map($key, $this->items);
|
||
|
|
return min($values);
|
||
|
|
}
|
||
|
|
|
||
|
|
return min(array_column($this->items, $key));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 查找项目
|
||
|
|
*/
|
||
|
|
public function find(callable $callback): mixed
|
||
|
|
{
|
||
|
|
foreach ($this->items as $item) {
|
||
|
|
if ($callback($item)) {
|
||
|
|
return $item;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 检查是否存在项目
|
||
|
|
*/
|
||
|
|
public function contains(mixed $item): bool
|
||
|
|
{
|
||
|
|
return in_array($item, $this->items, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 检查是否包含满足条件的项目
|
||
|
|
*/
|
||
|
|
public function containsWhere(callable $callback): bool
|
||
|
|
{
|
||
|
|
return $this->find($callback) !== null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取所有键
|
||
|
|
*/
|
||
|
|
public function keys(): array
|
||
|
|
{
|
||
|
|
return array_keys($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取所有值
|
||
|
|
*/
|
||
|
|
public function values(): array
|
||
|
|
{
|
||
|
|
return array_values($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 合并其他集合
|
||
|
|
*/
|
||
|
|
public function merge(self $other): self
|
||
|
|
{
|
||
|
|
$new = clone $this;
|
||
|
|
$new->items = array_merge($this->items, $other->getItems());
|
||
|
|
$new->count = count($new->items);
|
||
|
|
return $new;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 转换为分页对象
|
||
|
|
*/
|
||
|
|
public function toPagination(int $page = 1, int $pageSize = 10): PaginationDto
|
||
|
|
{
|
||
|
|
$offset = ($page - 1) * $pageSize;
|
||
|
|
$items = array_slice($this->items, $offset, $pageSize);
|
||
|
|
|
||
|
|
return PaginationDto::create($items, $this->count, $page, $pageSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建空集合
|
||
|
|
*/
|
||
|
|
public static function empty(): self
|
||
|
|
{
|
||
|
|
return new self([]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 从数组创建集合
|
||
|
|
*/
|
||
|
|
public static function fromArray(array $items): self
|
||
|
|
{
|
||
|
|
return new self($items);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建包含单个项目的集合
|
||
|
|
*/
|
||
|
|
public static function of(mixed $item): self
|
||
|
|
{
|
||
|
|
return new self([$item]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建范围集合
|
||
|
|
*/
|
||
|
|
public static function range(int $start, int $end): self
|
||
|
|
{
|
||
|
|
return new self(range($start, $end));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 转换为数组
|
||
|
|
*/
|
||
|
|
public function toArray(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'items' => $this->items,
|
||
|
|
'count' => $this->count,
|
||
|
|
'meta' => empty($this->meta) ? null : $this->meta,
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 转换为JSON
|
||
|
|
*/
|
||
|
|
public function toJson(): string
|
||
|
|
{
|
||
|
|
return json_encode($this->toArray(), JSON_UNESCAPED_UNICODE);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 实现ArrayAccess接口
|
||
|
|
*/
|
||
|
|
public function offsetExists(mixed $offset): bool
|
||
|
|
{
|
||
|
|
return isset($this->items[$offset]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function offsetGet(mixed $offset): mixed
|
||
|
|
{
|
||
|
|
return $this->items[$offset] ?? null;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function offsetSet(mixed $offset, mixed $value): void
|
||
|
|
{
|
||
|
|
if ($offset === null) {
|
||
|
|
$this->items[] = $value;
|
||
|
|
} else {
|
||
|
|
$this->items[$offset] = $value;
|
||
|
|
}
|
||
|
|
$this->count = count($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function offsetUnset(mixed $offset): void
|
||
|
|
{
|
||
|
|
unset($this->items[$offset]);
|
||
|
|
$this->count = count($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 实现Countable接口
|
||
|
|
*/
|
||
|
|
public function count(): int
|
||
|
|
{
|
||
|
|
return $this->count;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 实现IteratorAggregate接口
|
||
|
|
*/
|
||
|
|
public function getIterator(): \ArrayIterator
|
||
|
|
{
|
||
|
|
return new \ArrayIterator($this->items);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 实现JsonSerializable接口
|
||
|
|
*/
|
||
|
|
public function jsonSerialize(): array
|
||
|
|
{
|
||
|
|
return $this->toArray();
|
||
|
|
}
|
||
|
|
}
|