Skip to content

Improve Identification of Read-Only Field Status in Eloquent Fields #293

Open
@RasmusGodske

Description

@RasmusGodske

Description

The current implementation of read-only status for fields in the LaravelJsonApi\Eloquent\Fields\Concerns\IsReadOnly trait makes it challenging to determine which specific read-only method (readOnly(), readOnlyOnCreate(), or readOnlyOnUpdate()) has been called on a field. This lack of clarity can lead to difficulties in debugging and maintaining code, especially in complex schemas. This also makes it hard to create your own custom endpoints, that makes use of the attribute rules defined within the Schema.

Current Behavior

Currently, the read-only status is stored in a private property $readOnly as either a boolean or a Closure. The isReadOnly() method then evaluates this property to determine if a field is read-only. While functional, this approach doesn't provide an easy way to identify which specific read-only method was used.

/**
 * Whether the field is read-only.
 *
 * @var Closure|bool
 */
private $readOnly = false;

/**
 * Mark the field as read-only.
 *
 * @param Closure|bool $callback
 * @return $this
 */
public function readOnly($callback = true): self
{
    if (!is_bool($callback) && !$callback instanceof Closure) {
        throw new InvalidArgumentException('Expecting a boolean or closure.');
    }

    $this->readOnly = $callback;

    return $this;
}


/**
 * Mark the field as read only when the resource is being created.
 *
 * @return $this
 */
public function readOnlyOnCreate(): self
{
    $this->readOnly(static fn($request) => $request && $request->isMethod('POST'));

    return $this;
}

/**
 * Mark the field as read only when the resource is being updated.
 *
 * @return $this
 */
public function readOnlyOnUpdate(): self
{
    $this->readOnly(static fn($request) => $request && $request->isMethod('PATCH'));

    return $this;
}

Proposed Solution

To improve this, we could introduce a new property that explicitly tracks which read-only method was called. Here's a suggested implementation:

private $readOnlyType = null;

public function readOnly($callback = true): self
{
    // ... existing implementation ...
    $this->readOnlyType = 'always';
    return $this;
}

public function readOnlyOnCreate(): self
{
    // ... existing implementation ...
    $this->readOnlyType = 'onCreate';
    return $this;
}

public function readOnlyOnUpdate(): self
{
    // ... existing implementation ...
    $this->readOnlyType = 'onUpdate';
    return $this;
}

public function getReadOnlyType(): ?string
{
    return $this->readOnlyType;
}

This approach would allow developers to easily check which read-only method was called on a field:

$field = Number::make('target_value')->readOnlyOnUpdate();
echo $field->getReadOnlyType(); // Outputs: 'onUpdate'

Benefits

  1. Improved debugging: Developers can quickly identify which read-only method was applied to a field.
  2. Better introspection: Schemas become more self-documenting, as the read-only behavior of each field is explicitly tracked.
  3. Easier maintenance: Changes to read-only behavior become more transparent and easier to manage.

Potential Impact

This change would be backwards-compatible, as it doesn't alter the existing behavior of the isReadOnly() method. It only adds new functionality to improve developer experience.

(Claude 3.5 Sonnet, has been used to help formulate this)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions