- WIP on ApiRenderer and Save Form context@

This commit is contained in:
Dave Mc Nicoll 2026-06-19 19:46:32 +00:00
parent 78670c2fcf
commit e51d1ea7a3
4 changed files with 107 additions and 18 deletions

79
src/Entity/Error.php Normal file
View File

@ -0,0 +1,79 @@
<?php
namespace Lean\Api\Entity;
use Lean\Api\Attribute\EntityField;
use Ulmus\EntityTrait,
Ulmus\SearchRequest\SearchableInterface,
Ulmus\SearchRequest\SearchRequestInterface,
Ulmus\Entity\Field\Datetime;
use Ulmus\{Attribute\Obj\Table,
Entity\EntityInterface};
use Ulmus\{Api\Common\MethodEnum,
SearchRequest,
SearchRequest\Attribute\PropertyValueModifier\Split,
SearchRequest\Attribute\PropertyValueSource,
SearchRequest\Attribute\SearchOrderBy,
SearchRequest\Attribute\SearchWhere,
SearchRequest\SearchMethodEnum};
use Ulmus\Attribute\Property\{Field, Filter, FilterJoin, Relation, Join, Virtual, Where};
#[Table(name: "debug_errors", adapter: "lean.api")]
class Error implements EntityInterface, \JsonSerializable {
use EntityTrait;
#[Field\Id]
public int $id;
#[Field]
#[EntityField(description: "URL from which the error occurred")]
public string $url;
#[Field]
#[EntityField(description: "HTTP method", field: "httpMethod")]
public MethodEnum $method;
#[Field]
#[EntityField(description: "Error message")]
public string $message;
#[Field]
#[EntityField(description: "Error code")]
public int $code;
#[Field]
#[EntityField(description: "File from which the error occurred")]
public string $file;
#[Field]
#[EntityField(description: "Line in the file from which the error occurred")]
public int $line;
#[Field]
#[EntityField(description: "Stack trace of the exception")]
public array $trace;
#[Field\CreatedAt(name: "created_at")]
public Datetime $createdAt;
public function __toString() {
return mb_strlen($this->message) > 255 ? mb_substr($this->message, 0, 255) . "[...]" : $this->message;
}
public static function searchRequest(...$arguments) : SearchRequestInterface
{
return new #[SearchRequest\Attribute\SearchRequestParameter(Error::class)] class(...$arguments) extends SearchRequest\SearchRequest {
#[SearchRequest\Attribute\SearchWhere(source: SearchRequest\Attribute\PropertyValueSource::RequestAttribute)]
public int $id;
#[SearchWhere(method: SearchMethodEnum::Like)]
public string $message;
#[SearchOrderBy(parameter: "created_at",)]
public string $createdAt = SearchOrderBy::DESCENDING;
};
}
}

View File

@ -57,16 +57,20 @@ abstract class Save extends Form implements \Picea\Ui\Method\FormInterface {
if ($entity->isLoaded() && ! $this->skipEntityLastModified) { if ($entity->isLoaded() && ! $this->skipEntityLastModified) {
if (property_exists($entity, 'updatedAt') && $entity->repository()->generateDatasetDiff($entity) ) { if (property_exists($entity, 'updatedAt') && $entity->repository()->generateDatasetDiff($entity) ) {
$cls = $entity::resolveEntity()->field('updatedAt')->type->type; if ($field = $entity::resolveEntity()->field('updatedAt')) {
$cls = $field->type->type;
$entity->updatedAt = new $cls(); $entity->updatedAt = new $cls();
} }
} }
}
elseif (! $this->skipEntityCreatedAt) { elseif (! $this->skipEntityCreatedAt) {
if (property_exists($entity, 'createdAt') && empty($entity->createdAt)) { if (property_exists($entity, 'createdAt') && empty($entity->createdAt)) {
$cls = $entity::resolveEntity()->field('createdAt')->type->type; if ($field = $entity::resolveEntity()->field('createdAt')) {
$cls = $field->type->type;
$entity->createdAt = new $cls(); $entity->createdAt = new $cls();
} }
} }
}
try { try {
$this->assignContextToEntity($context); $this->assignContextToEntity($context);

View File

@ -40,7 +40,7 @@ class FormContext extends \Picea\Ui\Method\FormContext {
public function pushErrorMessage($key, $variables = []) { public function pushErrorMessage($key, $variables = []) {
$this->pushMessage($this->message::generateError( $this->pushMessage($this->message::generateError(
$this->lang($key, $variables) $a = $this->lang($key, $variables)
)); ));
} }

View File

@ -5,16 +5,18 @@ namespace Lean\Api\Middleware;
use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\JsonResponse;
use Lean\Factory\HttpFactory; use Lean\Factory\HttpFactory;
use Picea\Ui\Method\FormHandler; use Picea\Ui\Method\FormHandler;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
use Lean\Api\{Factory\DebugFormFactoryInterface, Form, Entity}; use Lean\Api\{Controller\Debug, Factory\DebugFormFactoryInterface, Form, Entity};
class ApiRenderer implements MiddlewareInterface { class ApiRenderer implements MiddlewareInterface {
public function __construct( public function __construct(
protected DebugFormFactoryInterface $debugFormFactory, protected ContainerInterface $container,
# protected DebugFormFactoryInterface $debugFormFactory,
) { ) {
} }
@ -25,6 +27,8 @@ class ApiRenderer implements MiddlewareInterface {
} }
catch(\Throwable $ex) { catch(\Throwable $ex) {
if (static::awaitingJson($request)) { if (static::awaitingJson($request)) {
$this->saveError($request, $ex);
return HttpFactory::createJsonResponse([ return HttpFactory::createJsonResponse([
'status' => 'failed', 'status' => 'failed',
'ts' => time(), 'ts' => time(),
@ -59,9 +63,10 @@ class ApiRenderer implements MiddlewareInterface {
protected function saveError(ServerRequestInterface $request, \Throwable $exception) : Entity\Error protected function saveError(ServerRequestInterface $request, \Throwable $exception) : Entity\Error
{ {
if ($debugFormFactory = $this->container->get(DebugFormFactoryInterface::class)) {
$request = $request->withMethod('PUT')->withParsedBody([]); $request = $request->withMethod('PUT')->withParsedBody([]);
$context = $this->debugFormFactory->errorSaveContext($request); $context = $debugFormFactory->errorSaveContext($request);
$context->sets([ $context->sets([
'message' => $exception->getMessage(), 'message' => $exception->getMessage(),
@ -71,9 +76,10 @@ class ApiRenderer implements MiddlewareInterface {
'trace' => $exception->getTrace(), 'trace' => $exception->getTrace(),
]); ]);
$form = $this->debugFormFactory->errorSave($entity = new Entity\Error()); $form = $debugFormFactory->errorSave($entity = new Entity\Error());
new FormHandler($request, $form, $context); new FormHandler($request, $form, $context);
}
return $entity; return $entity;
} }