Version 1.0.0
This commit is contained in:
54
src/Builder.php
Normal file
54
src/Builder.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Exception\TargetIsNull;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Item;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\ItemsBag;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Target;
|
||||
|
||||
class Builder
|
||||
{
|
||||
private array $items = [];
|
||||
private ?Target $target = null;
|
||||
|
||||
public static function withTarget(string $entity, string $field): static
|
||||
{
|
||||
$builder = new static();
|
||||
$builder->target($entity, $field);
|
||||
|
||||
return $builder;
|
||||
}
|
||||
|
||||
public function item(string $key, string $alias = ''): static
|
||||
{
|
||||
$this->items[] = new Item($key, $alias);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function target(string $entity, string $field): static
|
||||
{
|
||||
$this->target = new Target($entity, $field);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function build(): Request
|
||||
{
|
||||
if (is_null($this->target)) {
|
||||
throw new TargetIsNull();
|
||||
}
|
||||
|
||||
$items = new ItemsBag();
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
$items->push($item);
|
||||
}
|
||||
|
||||
return new Request($items, $this->target);
|
||||
}
|
||||
}
|
||||
20
src/Enricher.php
Normal file
20
src/Enricher.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Enrichment;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Storage\Requests;
|
||||
|
||||
class Enricher
|
||||
{
|
||||
public function __construct(
|
||||
private Enrichment $enrichment,
|
||||
) {}
|
||||
|
||||
public function enrich(array $data, Requests $requests): array
|
||||
{
|
||||
return $this->enrichment->enrich($data, $requests);
|
||||
}
|
||||
}
|
||||
17
src/Exception/InvalidRequest.php
Normal file
17
src/Exception/InvalidRequest.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class InvalidRequest extends RuntimeException
|
||||
{
|
||||
public function __construct(string $value)
|
||||
{
|
||||
return parent::__construct(
|
||||
sprintf('Invalid enrichment request: "%s".', $value)
|
||||
);
|
||||
}
|
||||
}
|
||||
9
src/Exception/PayloadIsNotJson.php
Normal file
9
src/Exception/PayloadIsNotJson.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class PayloadIsNotJson extends RuntimeException {}
|
||||
17
src/Exception/RepositoryNotFound.php
Normal file
17
src/Exception/RepositoryNotFound.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class RepositoryNotFound extends RuntimeException
|
||||
{
|
||||
public function __construct(string $target)
|
||||
{
|
||||
return parent::__construct(
|
||||
sprintf('Repository not found for target "%s".', $target)
|
||||
);
|
||||
}
|
||||
}
|
||||
9
src/Exception/TargetIsNull.php
Normal file
9
src/Exception/TargetIsNull.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Exception;
|
||||
|
||||
use LogicException;
|
||||
|
||||
class TargetIsNull extends LogicException {}
|
||||
10
src/Header.php
Normal file
10
src/Header.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit;
|
||||
|
||||
enum Header: string
|
||||
{
|
||||
case XEnrichmentRequest = 'X-Enrichment-Request';
|
||||
}
|
||||
12
src/Interface/Enrichment.php
Normal file
12
src/Interface/Enrichment.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Interface;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Storage\Requests;
|
||||
|
||||
interface Enrichment
|
||||
{
|
||||
public function enrich(array $data, Requests $requests): array;
|
||||
}
|
||||
10
src/Interface/Entity.php
Normal file
10
src/Interface/Entity.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Interface;
|
||||
|
||||
use ArrayAccess;
|
||||
use JsonSerializable;
|
||||
|
||||
interface Entity extends ArrayAccess, JsonSerializable {}
|
||||
12
src/Interface/Parser.php
Normal file
12
src/Interface/Parser.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Interface;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
|
||||
interface Parser
|
||||
{
|
||||
public function parse(string $value): Request;
|
||||
}
|
||||
16
src/Interface/Repository.php
Normal file
16
src/Interface/Repository.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Interface;
|
||||
|
||||
interface Repository
|
||||
{
|
||||
/**
|
||||
* @param string $field
|
||||
* @param array $values
|
||||
*
|
||||
* @return iterable<int,\Diffhead\PHP\DataEnrichmentKit\Interface\Entity>
|
||||
*/
|
||||
public function getByFieldValues(string $field, array $values): iterable;
|
||||
}
|
||||
12
src/Interface/Serializer.php
Normal file
12
src/Interface/Serializer.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Interface;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
|
||||
interface Serializer
|
||||
{
|
||||
public function toString(Request $request): string;
|
||||
}
|
||||
85
src/Message.php
Normal file
85
src/Message.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit;
|
||||
|
||||
use BackedEnum;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Exception\PayloadIsNotJson;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Parser;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Serializer;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Storage\Requests;
|
||||
use Nyholm\Psr7\Stream;
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
|
||||
class Message
|
||||
{
|
||||
public function __construct(
|
||||
private Serializer $serializer,
|
||||
private Parser $parser,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\MessageInterface $message
|
||||
* @param \BackedEnum $header
|
||||
* @param \Diffhead\PHP\DataEnrichmentKit\Storage\Requests $requests
|
||||
*
|
||||
* @return \Psr\Http\Message\MessageInterface
|
||||
*/
|
||||
public function setRequests(
|
||||
MessageInterface $message,
|
||||
BackedEnum $header,
|
||||
Requests $requests
|
||||
): MessageInterface {
|
||||
if ($requests->count() === 0) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
$header = $header->value;
|
||||
|
||||
foreach ($requests as $request) {
|
||||
$request = $this->serializer->toString($request);
|
||||
$message = $message->withAddedHeader($header, $request);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\MessageInterface $message
|
||||
* @param \BackedEnum $header
|
||||
*
|
||||
* @return \Diffhead\PHP\DataEnrichmentKit\Storage\Requests
|
||||
*/
|
||||
public function getRequests(MessageInterface $message, BackedEnum $header): Requests
|
||||
{
|
||||
$header = $header->value;
|
||||
$requests = $message->getHeader($header);
|
||||
|
||||
$container = new Requests();
|
||||
|
||||
foreach ($requests as $request) {
|
||||
$container->append($this->parser->parse($request));
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
public function getPayload(MessageInterface $message): array
|
||||
{
|
||||
$payload = json_decode($message->getBody()->getContents(), true);
|
||||
|
||||
if (! is_array($payload)) {
|
||||
throw new PayloadIsNotJson();
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
public function setPayload(MessageInterface $message, array $payload): MessageInterface
|
||||
{
|
||||
return $message->withBody(
|
||||
Stream::create(json_encode($payload))
|
||||
);
|
||||
}
|
||||
}
|
||||
23
src/Object/Item.php
Normal file
23
src/Object/Item.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Object;
|
||||
|
||||
class Item
|
||||
{
|
||||
public function __construct(
|
||||
private string $key,
|
||||
private string $alias = ''
|
||||
) {}
|
||||
|
||||
public function key(): string
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
public function alias(): string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
}
|
||||
29
src/Object/ItemsBag.php
Normal file
29
src/Object/ItemsBag.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Object;
|
||||
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
class ItemsBag implements IteratorAggregate
|
||||
{
|
||||
private array $items = [];
|
||||
|
||||
public function push(Item $item): static
|
||||
{
|
||||
$this->items[] = $item;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Traversable<int,\Diffhead\PHP\DataEnrichmentKit\Object\Item>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->items);
|
||||
}
|
||||
}
|
||||
23
src/Object/Request.php
Normal file
23
src/Object/Request.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Object;
|
||||
|
||||
class Request
|
||||
{
|
||||
public function __construct(
|
||||
private ItemsBag $items,
|
||||
private Target $target
|
||||
) {}
|
||||
|
||||
public function items(): ItemsBag
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function target(): Target
|
||||
{
|
||||
return $this->target;
|
||||
}
|
||||
}
|
||||
23
src/Object/Target.php
Normal file
23
src/Object/Target.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Object;
|
||||
|
||||
class Target
|
||||
{
|
||||
public function __construct(
|
||||
private string $entity,
|
||||
private string $field
|
||||
) {}
|
||||
|
||||
public function entity(): string
|
||||
{
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
public function field(): string
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
}
|
||||
153
src/Service/Enrichment.php
Normal file
153
src/Service/Enrichment.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Service;
|
||||
|
||||
use ArrayAccess;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Enrichment as EnrichmentInterface;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Item;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\ItemsBag;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Storage\Repositories;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Storage\Requests;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Utility\Arr;
|
||||
|
||||
class Enrichment implements EnrichmentInterface
|
||||
{
|
||||
public function __construct(
|
||||
private Repositories $repositories,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array $payload
|
||||
* @param \Diffhead\PHP\DataEnrichmentKit\Storage\Requests $requests
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enrich(array $data, Requests $requests): array
|
||||
{
|
||||
foreach ($requests as $request) {
|
||||
$data = $this->enrichSingle($data, $request);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function enrichSingle(array $data, Request $request): array
|
||||
{
|
||||
$targetFieldValues = [];
|
||||
$target = $request->target();
|
||||
|
||||
$items = $request->items();
|
||||
|
||||
$targetFieldValues = $this->getFieldValuesByItems($data, $items);
|
||||
|
||||
$targets = $this->getTargetsByFieldValue(
|
||||
$target->entity(),
|
||||
$target->field(),
|
||||
$targetFieldValues
|
||||
);
|
||||
|
||||
return $this->enrichUsingTargets($data, $items, $targets);
|
||||
}
|
||||
|
||||
private function getFieldValuesByItems(array $data, ItemsBag $items): array
|
||||
{
|
||||
$targetFieldValues = [];
|
||||
|
||||
/**
|
||||
* @var \Diffhead\PHP\DataEnrichmentKit\Object\Item $item
|
||||
*/
|
||||
foreach ($items as $item) {
|
||||
$valueOrValues = Arr::get($item->key(), $data);
|
||||
|
||||
if (is_array($valueOrValues)) {
|
||||
$targetFieldValues = array_merge($targetFieldValues, $valueOrValues);
|
||||
} else {
|
||||
$targetFieldValues[] = $valueOrValues;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($targetFieldValues);
|
||||
}
|
||||
|
||||
private function getTargetsByFieldValue(string $entity, string $field, array $values): array
|
||||
{
|
||||
$targets = $this->repositories->get($entity)
|
||||
->getByFieldValues($field, $values);
|
||||
|
||||
$targetsHaveArrayAccess = is_array($targets) || $targets instanceof ArrayAccess;
|
||||
$targetsByFieldValue = [];
|
||||
|
||||
foreach ($targets as $index => $target) {
|
||||
$fieldValue = $target[$field];
|
||||
$targetsByFieldValue[$fieldValue] = $target;
|
||||
|
||||
if ($targetsHaveArrayAccess) {
|
||||
unset($targets[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
return $targetsByFieldValue;
|
||||
}
|
||||
|
||||
private function enrichUsingTargets(array $data, ItemsBag $items, array $targets): array
|
||||
{
|
||||
foreach ($items as $item) {
|
||||
$data = $this->enrichByItem($data, $item, $targets);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function enrichByItem(array $data, Item $item, array &$targets): array
|
||||
{
|
||||
$keyFirstItemIsWildcard = strpos($item->key(), '*.') === 0;
|
||||
|
||||
if (array_is_list($data) && $keyFirstItemIsWildcard) {
|
||||
/**
|
||||
* If passed *.user_id key as example then
|
||||
* we need to remove first wildcard part
|
||||
*/
|
||||
$parts = explode('.', $item->key());
|
||||
$nextKey = implode('.', array_slice($parts, 1));
|
||||
|
||||
$item = new Item($nextKey, $item->alias());
|
||||
|
||||
foreach ($data as $index => $entry) {
|
||||
$data[$index] = $this->enrichByItem($entry, $item, $targets);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$keyIsWildcard = is_numeric(strpos($item->key(), '*.'));
|
||||
|
||||
if ($keyIsWildcard) {
|
||||
$parts = explode('.', $item->key());
|
||||
$first = $parts[0];
|
||||
|
||||
$temporary = Arr::get($first, $data, []);
|
||||
|
||||
$nextKey = implode('.', array_slice($parts, 1));
|
||||
$nextItem = new Item($nextKey, $item->alias());
|
||||
|
||||
$data[$first] = $this->enrichByItem($temporary, $nextItem, $targets);
|
||||
} else {
|
||||
$value = Arr::get($item->key(), $data);
|
||||
$parts = explode('.', $item->key());
|
||||
|
||||
$alias = $item->alias()
|
||||
? $item->alias()
|
||||
: $parts[count($parts) - 1];
|
||||
|
||||
$parts[count($parts) - 1] = $alias;
|
||||
$nextKey = implode('.', $parts);
|
||||
|
||||
$data = Arr::set($nextKey, $data, $targets[$value] ?? null);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
57
src/Service/Parser.php
Normal file
57
src/Service/Parser.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Service;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Exception\InvalidRequest;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Parser as ParserInterface;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Item;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\ItemsBag;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Target;
|
||||
|
||||
class Parser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return \Diffhead\PHP\DataEnrichmentKit\Object\Request
|
||||
*
|
||||
* @throws \Diffhead\PHP\DataEnrichmentKit\Exception\InvalidRequest
|
||||
*/
|
||||
public function parse(string $value): Request
|
||||
{
|
||||
$referenceWithTarget = explode('@', $value);
|
||||
|
||||
if (! isset($referenceWithTarget[1])) {
|
||||
throw new InvalidRequest($value);
|
||||
}
|
||||
|
||||
$entityWithField = explode(',', $referenceWithTarget[1]);
|
||||
|
||||
if (! isset($entityWithField[0]) || ! isset($entityWithField[1])) {
|
||||
throw new InvalidRequest($value);
|
||||
}
|
||||
|
||||
$entity = $entityWithField[0];
|
||||
$field = $entityWithField[1];
|
||||
|
||||
$target = new Target($entity, $field);
|
||||
|
||||
$references = $referenceWithTarget[0];
|
||||
$references = explode(',', $references);
|
||||
|
||||
$items = new ItemsBag();
|
||||
|
||||
foreach ($references as $reference) {
|
||||
$referenceWithAlias = explode('+', $reference);
|
||||
|
||||
$items->push(
|
||||
new Item($referenceWithAlias[0], $referenceWithAlias[1] ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
return new Request($items, $target);
|
||||
}
|
||||
}
|
||||
40
src/Service/Serializer.php
Normal file
40
src/Service/Serializer.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Service;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Serializer as SerializerInterface;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
|
||||
class Serializer implements SerializerInterface
|
||||
{
|
||||
public function toString(Request $request): string
|
||||
{
|
||||
$targetParts = [
|
||||
$request->target()->entity(),
|
||||
$request->target()->field(),
|
||||
];
|
||||
|
||||
$target = implode(',', $targetParts);
|
||||
|
||||
$itemsParts = [];
|
||||
|
||||
/**
|
||||
* @var \Diffhead\PHP\DataEnrichmentKit\Object\Item $item
|
||||
*/
|
||||
foreach ($request->items() as $item) {
|
||||
$itemParts = [$item->key()];
|
||||
|
||||
if ($alias = $item->alias()) {
|
||||
$itemParts[] = $alias;
|
||||
}
|
||||
|
||||
$itemsParts[] = implode('+', $itemParts);
|
||||
}
|
||||
|
||||
$items = implode(',', $itemsParts);
|
||||
|
||||
return sprintf('%s@%s', $items, $target);
|
||||
}
|
||||
}
|
||||
45
src/Storage/Repositories.php
Normal file
45
src/Storage/Repositories.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Storage;
|
||||
|
||||
use Diffhead\PHP\DataEnrichmentKit\Exception\RepositoryNotFound;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Interface\Repository;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Repositories
|
||||
{
|
||||
/**
|
||||
* @param array<string,\Diffhead\PHP\DataEnrichmentKit\Interface\Repository> $map
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(
|
||||
private array $map = []
|
||||
) {
|
||||
foreach ($this->map as $target => $repository) {
|
||||
if (! $repository instanceof Repository) {
|
||||
throw new InvalidArgumentException(
|
||||
'Map should contains only Repository instances as values'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function set(string $target, Repository $repository): static
|
||||
{
|
||||
$this->map[$target] = $repository;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function get(string $target): Repository
|
||||
{
|
||||
if (! isset($this->map[$target])) {
|
||||
throw new RepositoryNotFound($target);
|
||||
}
|
||||
|
||||
return $this->map[$target];
|
||||
}
|
||||
}
|
||||
54
src/Storage/Requests.php
Normal file
54
src/Storage/Requests.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Storage;
|
||||
|
||||
use ArrayIterator;
|
||||
use Diffhead\PHP\DataEnrichmentKit\Object\Request;
|
||||
use InvalidArgumentException;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
class Requests implements IteratorAggregate
|
||||
{
|
||||
private int $count = 0;
|
||||
|
||||
/**
|
||||
* @param array<int,\Diffhead\PHP\DataEnrichmentKit\Object\Request> $requests
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(
|
||||
private array $requests = []
|
||||
) {
|
||||
foreach ($this->requests as $request) {
|
||||
if (! $request instanceof Request) {
|
||||
throw new InvalidArgumentException(
|
||||
'Requests should be an array of Request instances'
|
||||
);
|
||||
}
|
||||
|
||||
$this->count++;
|
||||
}
|
||||
}
|
||||
|
||||
public function append(Request $request): void
|
||||
{
|
||||
$this->count++;
|
||||
$this->requests[] = $request;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Traversable<int,\Diffhead\PHP\DataEnrichmentKit\Object\Request>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->requests);
|
||||
}
|
||||
}
|
||||
174
src/Utility/Arr.php
Normal file
174
src/Utility/Arr.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Diffhead\PHP\DataEnrichmentKit\Utility;
|
||||
|
||||
class Arr
|
||||
{
|
||||
/**
|
||||
* Get value inside array using key dot notation is supported
|
||||
* also supported wildcard keys as "users.*.name" and alike.
|
||||
*
|
||||
* Returns empty array when passed wildcard key but no values found.
|
||||
* This mode will never return the default value and values strictly
|
||||
* equal to default are skipping.
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $data
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed|array<int,mixed>
|
||||
*/
|
||||
public static function get(string $key, array $data, mixed $default = null): mixed
|
||||
{
|
||||
$parts = explode('.', $key);
|
||||
|
||||
$temporary = $data;
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if ($part === '*') {
|
||||
$values = [];
|
||||
|
||||
foreach ($temporary as $item) {
|
||||
if (! is_array($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = implode('.', array_slice($parts, $index + 1));
|
||||
$extracted = self::get((string) $key, $item, $default);
|
||||
|
||||
if (is_array($extracted)) {
|
||||
$values = array_merge($values, $extracted);
|
||||
} else if ($extracted === $default) {
|
||||
continue;
|
||||
} else {
|
||||
$values[] = $extracted;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
$isNotArray = ! is_array($temporary);
|
||||
$isNotExisting = $isNotArray || ! array_key_exists($part, $temporary);
|
||||
|
||||
if ($isNotExisting) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$temporary = $temporary[$part];
|
||||
}
|
||||
|
||||
return $temporary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test array having value inside using key dot notation is supported.
|
||||
*
|
||||
* If passed strict as true then will return true if any of the wildcard
|
||||
* paths exist else will return true only if all wildcard paths exist.
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $data
|
||||
* @param bool $strict
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has(string $key, array $data, bool $strict = false): bool
|
||||
{
|
||||
$parts = explode('.', $key);
|
||||
$any = ! $strict;
|
||||
|
||||
$temporary = $data;
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if ($part === '*') {
|
||||
if (! is_array($temporary)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$test = null;
|
||||
|
||||
foreach ($temporary as $item) {
|
||||
$key = implode('.', array_slice($parts, $index + 1));
|
||||
$has = self::has($key, $item, $strict);
|
||||
|
||||
if ($strict) {
|
||||
$test = $has && (is_null($test) ? true : $test);
|
||||
}
|
||||
|
||||
if ($any && $has) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return is_null($test) ? false : $test;
|
||||
}
|
||||
|
||||
$isNotArray = ! is_array($temporary);
|
||||
$isNotExisting = $isNotArray || ! array_key_exists($part, $temporary);
|
||||
|
||||
if ($isNotExisting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$temporary = $temporary[$part];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value inside array using key dot notation support
|
||||
* Also supported wildcard keys as "users.*.name" and alike
|
||||
*
|
||||
* @param string $key Includes dot notation support
|
||||
* @param array $data
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function set(string $key, array $data, mixed $value): array
|
||||
{
|
||||
$parts = explode('.', $key);
|
||||
$last = array_pop($parts);
|
||||
|
||||
$temporary = &$data;
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if ($part === '*') {
|
||||
$isNotArray = ! is_array($temporary);
|
||||
$isEmptyArray = is_array($temporary) && ! count($temporary);
|
||||
|
||||
if ($isNotArray || $isEmptyArray) {
|
||||
$temporary[] = [];
|
||||
}
|
||||
|
||||
foreach ($temporary as $i => $item) {
|
||||
$actuallyParts = array_slice($parts, $index + 1);
|
||||
$actuallyParts[] = $last;
|
||||
|
||||
$key = implode('.', $actuallyParts);
|
||||
|
||||
$temporary[$i] = self::set($key, $item, $value);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$isNotExisting = ! array_key_exists($part, $temporary);
|
||||
$isNotArray = $isNotExisting || ! is_array($temporary[$part]);
|
||||
|
||||
if ($isNotExisting && $isNotArray) {
|
||||
$temporary[$part] = [];
|
||||
}
|
||||
|
||||
$temporary = &$temporary[$part];
|
||||
}
|
||||
|
||||
$temporary[$last] = $value;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user