cloudcreativity / laravel-json-api

JSON API (jsonapi.org) package for Laravel applications.
http://laravel-json-api.readthedocs.io/en/latest/
Apache License 2.0
780 stars 109 forks source link

How to make relationships immutable after the resource's initial creation? #491

Closed osteel closed 4 years ago

osteel commented 4 years ago

Hi,

Apologies if that's been asked before but I can't seem to find a similar issue on Github nor the answer in the documentation.

I've got a Comment resource which has a Post relationship. Post must be specified at Comment creation (hence it is present in the adapter's $fillable array), but shouldn't be modifiable when the comment is subsequently updated.

This is the validators' rules method for the Comment resource:


    /**
     * {@inheritDoc}
     *
     * @param  Comment|null $record the record being updated, or null if creating a resource.
     * @return array
     */
    protected function rules($record = null): array
    {
        if ($record) {
            return [
                'content' => 'sometimes|string',
            ];
        }

        return [
            'content' => 'required|string',
            'post'    => ['required', new HasOne('posts')],
        ];
    }

Unfortunately, not setting a rule for post at update doesn't prevent the relationship from being updated.

I also overwrote the dataForUpdate method to strip the relationships altogether:

    /**
     * {@inheritDoc}
     *
     * @param  Comment $record   the record being updated.
     * @param  array   $document the JSON API document to validate.
     * @return array
     */
    protected function dataForUpdate($record, array $document): array
    {
        $document = Arr::except($document, 'data.relationships');

        return parent::dataForUpdate($record, $document);
    }

Relationships are correctly removed from $document, yet the post is still updated.

A couple of questions:

Thanks in advance!

lindyhopchris commented 4 years ago

Yeah, I definitely need to improve this - plan for next version is only to use the validated data for filling, which would mean if you didn't validate the relationships on the update request they wouldn't be filled.

In the meantime overload the getFillable() method on your adapter. It receives the model that is being filled so you can check $model->exists() to decide what list of fillable JSON API fields you should return. That's how we do it!

osteel commented 4 years ago

@lindyhopchris awesome, I'll give that a try on Monday and close the issue if that solves it (which I'm sure it will).

Thanks for your work and reactivity, it's very much appreciated.

osteel commented 4 years ago

All good! 👍