- WIP on route descriptor

This commit is contained in:
Dave Mc Nicoll 2025-04-15 18:47:58 +00:00
parent 21f315cc22
commit ad310ffee5
7 changed files with 52 additions and 18 deletions

View File

@ -1,4 +1,15 @@
{ {
"descriptor": {
"form": {
"none": "Aucun formulaire existant pour cet API"
},
"entity": {
"none": "Aucune entité trouvée pour cet API"
},
"route": {
"none": "Aucune route trouvée pour cet API"
}
},
"form": { "form": {
"save": { "save": {
"error": { "error": {

View File

@ -13,5 +13,6 @@ class EntityField
public ?string $regexFormat = null, public ?string $regexFormat = null,
public mixed $example = null, public mixed $example = null,
public ?string $field = null, public ?string $field = null,
public ?string $setterMethod = null,
) {} ) {}
} }

View File

@ -33,10 +33,14 @@ abstract class Save implements \Picea\Ui\Method\FormInterface {
$entity = $this->getEntity(); $entity = $this->getEntity();
if ($entity->isLoaded() ) { if ($entity->isLoaded() ) {
$entity->updatedAt = new Datetime(); if (property_exists($entity, 'updatedAt')) {
$entity->updatedAt = new Datetime();
}
} }
else { else {
$entity->createdAt = new Datetime(); if (property_exists($entity, 'createdAt')) {
$entity->createdAt = new Datetime();
}
} }
try { try {
@ -63,18 +67,20 @@ abstract class Save implements \Picea\Ui\Method\FormInterface {
foreach($entity::resolveEntity()->fieldList() as $key => $property) { foreach($entity::resolveEntity()->fieldList() as $key => $property) {
$field = $property->getAttribute(Field::class)->object; $field = $property->getAttribute(Field::class)->object;
if (! $field->readonly) { if (! $field->readonly || ! $entity->isLoaded()) {
$apiField = $property->getAttribute(EntityField::class)->object ?? null; $apiField = $property->getAttribute(EntityField::class)->object ?? null;
if ($apiField) { if ($apiField) {
if ($apiField->field) { $var = $apiField->field ?: $key;
if ( isset($context->{$apiField->field}) ) {
$entity->$key = $context->{$apiField->field}; if ( isset($context->{$var}) ) {
if ($apiField->setterMethod) {
# Use a setter method
call_user_func([ $entity, $apiField->setterMethod ], $context->{$var});
} }
} else {
else { # Direct property set
if ( isset($context->{$key}) ) { $entity->$key = $context->{$var};
$entity->$key = $context->{$key};
} }
} }
} }

View File

@ -1,8 +1,10 @@
{% language.set "lean.api.descriptor.entity" %}
{% function yesOrNo(bool $toggle) : void %} {% function yesOrNo(bool $toggle) : void %}
<span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span> <span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span>
{% endfunction %} {% endfunction %}
{% function length(int|null $length): void %} {% function length(int|null|string $length): void %}
<span style="color:{{ $length ? 'black' : 'gray' }}">{{ $length ?? "non-défini" }}</span> <span style="color:{{ $length ? 'black' : 'gray' }}">{{ $length ?? "non-défini" }}</span>
{% endfunction %} {% endfunction %}
@ -61,5 +63,7 @@
{% endforeach %} {% endforeach %}
</ol> </ol>
</div> </div>
{% or %}
<i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
{% endforeach %} {% endforeach %}
</div> </div>

View File

@ -1,3 +1,5 @@
{% language.set "lean.api.descriptor.form" %}
{% function yesOrNo(bool $toggle) : void %} {% function yesOrNo(bool $toggle) : void %}
<span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span> <span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span>
{% endfunction %} {% endfunction %}
@ -34,5 +36,7 @@
{% endforeach %} {% endforeach %}
</ol> </ol>
</div> </div>
{% or %}
<i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
{% endforeach %} {% endforeach %}
</div> </div>

View File

@ -1,14 +1,21 @@
{% language.set "lean.api.descriptor.route" %}
<ul class="routes-wrapper"> <ul class="routes-wrapper">
{% foreach $routes as $route %} {% foreach $routes as $route %}
{% foreach $route['methods'] as $method %} {% foreach $route['methods'] as $method %}
<li class="method-{{ strtolower($method) }}"> <li class="method-{{ strtolower($method) }}">
<span class="route-method">{{ $method }}</span> <span class="route-method">
<span class="method-name">{{ strtoupper($method) }}</span>
</span>
<span class="route-link"> <span class="route-link">
<a href="{{ $route['route'] }}" title="{{ $route['path'] }}">{{ $route['cleaned'] }}</a> <a href="{{ $route['route'] }}" title="{{ $route['path'] }}">{{ $route['cleaned'] }}</a>
<span>- {{= $route['description'] }}</span> <span>-</span>
<span>{{= $route['description'] }}</span>
</span> </span>
<small class="route-name">{{ $route['name'] }}</small> <small class="route-name">{{ $route['name'] }}</small>
</li> </li>
{% or %}
<i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
{% endforeach %} {% endforeach %}
{% endforeach %} {% endforeach %}
</ul> </ul>

View File

@ -35,12 +35,13 @@
.forms .form-name {background: #9cc5e6;color: #284168;font-size:110%} .forms .form-name {background: #9cc5e6;color: #284168;font-size:110%}
.routes-wrapper {padding:8px} .routes-wrapper {padding:8px}
.routes-wrapper li + li {margin-top: 5px} .routes-wrapper li {display:flex;border: 1px solid #ccc;align-items: stretch;}
.routes-wrapper li {display:flex;align-items:center;border: 1px solid #ccc;} .routes-wrapper li + li {margin-top: 5px;}
.routes-wrapper .route-method {line-height: 1.8rem;padding:6px 5px 0 5px;width:80px;text-align:center;font-weight:bold;color:#fff;} .routes-wrapper .route-method {display:flex;align-items: center; justify-content: center; line-height: 1.8rem;padding:6px 5px 0 5px;min-width:80px;text-align:center;font-weight:bold;color:#fff;}
.routes-wrapper .route-link {line-height: 1.8rem;padding:0 10px} .routes-wrapper .route-link {line-height: 1.8rem;padding:0 10px;display: flex;align-items: center;}
.routes-wrapper .route-link span {margin-left: 7px;}
.routes-wrapper .route-link a {font-family:monospace;font-size:.85em} .routes-wrapper .route-link a {font-family:monospace;font-size:.85em}
.routes-wrapper .route-name {margin-left:auto;font-weight:bold;width: 200px;text-align: right;background:rgba(0, 0, 0, 0.02);line-height: 1.8rem;padding:6px 7px 0 5px;} .routes-wrapper .route-name {margin-left:auto;font-weight:bold;min-width: 20%;text-align: right;background:rgba(0, 0, 0, 0.02);line-height: 1.8rem;padding:6px 7px 0 5px;}
.routes-wrapper li.method-get {background:#e7eff7;border-color: #bfcfdd;} .routes-wrapper li.method-get {background:#e7eff7;border-color: #bfcfdd;}
.routes-wrapper li.method-get .route-method {background:#0f6ab4;} .routes-wrapper li.method-get .route-method {background:#0f6ab4;}
.routes-wrapper li.method-get .route-link a, .routes-wrapper li.method-get .route-name {color: #0f6ab4;} .routes-wrapper li.method-get .route-link a, .routes-wrapper li.method-get .route-name {color: #0f6ab4;}