ulmus/src/SearchRequest/SearchRequestFromRequestTrait.php
Dave Mc Nicoll 411992c7a8 - Added a new Field Mapper to SQLs Adapters.
- Defined missing MySQL fields attributes
- WIP on lean-console's migration methods
2024-10-21 18:12:24 +00:00

196 lines
7.0 KiB
PHP

<?php
namespace Ulmus\SearchRequest;
use Notes\ObjectReflection;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\SearchRequest\Attribute\{PropertyValueSource,
SearchManual,
SearchParameter,
SearchWhere,
SearchLike,
SearchOrderBy,
SearchGroupBy,
SearchRequestParameter};
trait SearchRequestFromRequestTrait
{
protected array $wheres = [];
protected array $likes = [];
protected array $groups = [];
protected array $orders = [];
public function fromRequest(ServerRequestInterface $request)
{
if (method_exists($this, 'prepare')) {
$this->prepare($request);
}
$queryParams = new \ArrayObject(array_filter($request->getQueryParams(), function($i) { return ! is_null($i) && $i !== ""; }));
$this->page = $queryParams->offsetExists('page') ? $queryParams['page'] : 1;
$classReflection = ObjectReflection::fromClass(static::class)->reflectClass();
foreach($classReflection->getProperties() as $propertyName => $property) {
$attributeList = $property->getAttributes(Attribute\SearchParameter::class);
if ($attributeList) {
$attribute = $attributeList[0]->object;
$fieldName = $attribute->field ?? $propertyName;
# Field could be defined for another entity class
if (is_array($fieldName)) {
$field = \Ulmus\Attribute\Attribute::handleArrayField($fieldName, false);
}
# Default class using it, if SearchRequestParameter is defined
elseif ($classAttributes = $classReflection->getAttributes(SearchRequestParameter::class)) {
$searchRequestAttribute = $classAttributes[0]->object;
$className = $searchRequestAttribute->class;
$field = $className::field($fieldName, $searchRequestAttribute->alias);
}
# Untouched string from the attribute
else {
$field = $fieldName;
}
$value = $this->getValueFromSource($request, $propertyName, $attribute);
if ($value !== null) {
$value = $this->transformValue($property->getAttributes(Attribute\PropertyValueModifier::class), $value);
}
switch(true) {
case $attribute instanceof SearchGroupBy:
$this->parseAttributeGroupBy($attribute, $field, $propertyName);
break;
case $attribute instanceof SearchWhere:
case $attribute instanceof SearchLike:
case $attribute instanceof SearchManual:
if ($attribute->toggle) {
$this->$propertyName = !empty($value);
} elseif ($value !== null) {
foreach ($property->getTypes() as $type) {
$enum = $type->type;
if (enum_exists($enum)) {
try {
$this->$propertyName = $value instanceof \UnitEnum ? $value : $type->type::from($value);
} catch (\ValueError $ex) {
$cases = implode(', ', array_map(fn($e) => $e->name, $enum::cases()));
throw new \ValueError(
sprintf("Given value '%s' do not exists within enum '%s'. Try one of those values instead : %s", $value, $enum, $cases)
);
}
} elseif ($type->builtIn) {
$this->$propertyName = $value;
}
}
}
$this->parseAttributeMethod($attribute, $field, $propertyName);
break;
case $attribute instanceof SearchOrderBy:
if ($value !== null) {
$this->$propertyName = $value;
}
$this->parseAttributeOrderBy($attribute, $field, $propertyName);
break;
}
}
}
return $this;
}
protected function getValueFromSource(RequestInterface $request, string $propertyName, SearchParameter $attribute) : mixed
{
$queryParamName = $attribute->getParameters() ?: [ $propertyName ];
foreach($attribute->getSources() as $source) {
switch($source) {
case PropertyValueSource::QueryParams:
$queryParams = new \ArrayObject(array_filter($request->getQueryParams(), function($i) { return ! is_null($i) && $i !== ""; }));
foreach($queryParamName as $param) {
if ($queryParams->offsetExists($param)) {
return $queryParams[$param];
}
}
break;
case PropertyValueSource::RequestAttribute:
foreach($queryParamName as $param) {
$fromAttribute = $request->getAttribute($param, null);
if ($fromAttribute !== null) {
return $fromAttribute;
}
}
break;
}
}
return null;
}
protected function transformValue(array $valueModifierAttributes, mixed $value, ) : mixed
{
foreach($valueModifierAttributes as $transform) {
$value = $transform->object->run($value);
}
return $value;
}
protected function parseAttributeMethod(object $attribute, string $field, string $propertyName,) : void
{
if (! isset($this->$propertyName)) {
return;
}
switch ($attribute->method) {
case SearchMethodEnum::Where:
$this->wheres[$field] = $this->$propertyName;
break;
case SearchMethodEnum::Like:
$this->likes[$field] = "%{$this->$propertyName}%";
break;
case SearchMethodEnum::LikeLeft:
$this->likes[$field] = "%{$this->$propertyName}";
break;
case SearchMethodEnum::LikeRight:
$this->likes[$field] = "{$this->$propertyName}%";
break;
}
}
protected function parseAttributeOrderBy(object $attribute, string $field, mixed $propertyName,) : void
{
if ( ! empty($this->$propertyName) ) {
$this->orders[$field] = $this->$propertyName;
}
}
protected function parseAttributeGroupBy(object $attribute, string $field, mixed $propertyName,) : void
{
if (! empty($this->$propertyName)) {
$this->groups[] = $field;
}
}
}