Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation about validation of relationships object using getResourceObject #2

Closed
mosen opened this issue Oct 21, 2015 · 10 comments
Closed

Comments

@mosen
Copy link

mosen commented Oct 21, 2015

Hey there,
Forgive me if I read incorrectly, but I don't think there's any documentation about validating relationships as part of a new resource creation, such as the request body shown in the example under http://jsonapi.org/format/#document-resource-objects

The current solution I'm using is to manually construct the relationships validator and set it on the main resource validator. eg.

$validator = $this->getResourceObjectValidator(...)
$validator->setRelationshipsValidator(new RelationshipsValidator([
   'relationshipName' => $this->getHasOneValidator('relationship_type')
]);

Although I'm not 100% sure that this is the recommended method.
If you would like me to submit a change to README to that effect under content validation, I'm happy to do that too.

@lindyhopchris
Copy link
Member

@mosen

Thanks for your message. I need to sit down and write some proper documentation at some point but unfortunately the project that I've created this package for is burning all of my time at the moment. Better documentation will come at some point!

What you're currently doing above works, but there's handy helper methods that make it easier to write. What you've written above can be rewritten as:

$validator = $this->getResourceObjectValidator(...)
    ->hasOne('relationshipName', 'relationshipType');

You can also use hasMany() as a helper for adding a hasMany relationship. These helper methods are chainable, so you you call many in a row.

Both hasOne() and hasMany() take the relationship name as the first argument and a relationship type for the second. If your relationship can accept multiple types (i.e. it's polymorphic) then pass in an array of types for the second argument.

Both these helper methods take an optional third argument of options (in an array) that can be set on either the HasOneValidator or HasManyValidator that is created. E.g. you could do the following:

$validator = $this->getResourceObjectValidator(...)
    ->hasOne('relationshipName', 'relationshipType', [
        'required' => true,
        'allowEmpty' => false,
        'callback' => function (ResourceIdentifierInterface $identifier) {
            return Person::where('id', $identifier->getId())->exists();
        }
    ]);

required is whether the client must have provided the relationship in the resource object that was sent. allowEmpty is whether the relationship can be empty (null for has-one, empty array for has-many).

If provided, the callback is invoked by the validator to check that the actual id provided by the client is valid. This callback is only called if all other validation on the relationship passes - i.e. you can trust that $identifier passed in to the callback has the correct resource type on it and there is an id value.

For a has-many validator, the callback is provided with an instance of ResourceIdentifierCollectionInterface.

Let me know if you have any questions! I'm going to leave this issue open as a reminder that I need to add better documentation for validation.

@mosen
Copy link
Author

mosen commented Oct 21, 2015

Thanks a bunch, that really cleared up everything I was missing on validation.

@nickelozz
Copy link

howdy @lindyhopchris

I've been checking out the relationship management with creating/updating a resource and I've stumbled upon this issue...I have a few questions I hope you can help me with:

  1. Could you please give me an example of what would a real life relationshipName and relationshipType look like? I'm having trouble distinguishing them (especially the relationshipType).
  2. When not sending the optional third argument array to the methods hasOne() and hasMany(), what are the default values for required, allowEmpty and callback?
  3. Related to the previous question (third argument array), is it possible to only send a subset of its vaules? e.g. Send only the required and have the rest as default? What would each value default to?

Thank you so much in advance.

@lindyhopchris
Copy link
Member

@nickelozz

No problem...

  1. $relationshipName is the key of the relationship on the resource object that is being validated. $relationshipType is the type of the resource on the inverse side of the relationship (I probably should have called the variable $resourceType). E.g. if you are validating a post resource object that has an author relationship, where the author is a person resource object, then $relationshipName would be author and $relationshipType would be person.
  2. allowEmpty is true, required is false. callback is null, i.e. no callback to execute in the validation. I use the callback to check that the provided id for the relationship actually exists (normally a database query).
  3. Yes. All options arrays are exchanged in a way so that only values that are provided are set over the defaults. E.g.
    https://github.com/cloudcreativity/json-api/blob/master/src/Validator/Relationships/HasOneValidator.php#L199

@nickelozz
Copy link

@lindyhopchris excellent!! tyvm sir 😃

@mandryka
Copy link

mandryka commented Mar 9, 2017

Hi @lindyhopchris !

I have the same question, how can I validate relationships object's data?
I tried to use $relationships->hasOne('key', 'type', true, false) in relationshipRules method, but I think that this method just for checking exist of object.
How can I add some validation rules to this object?

@lindyhopchris
Copy link
Member

Hi @mandryka

The relationship validation checks that the relationship object is correct according to the JSON API spec, and it also checks via the store that the related resource exists. Additionally it checks allowEmpty and required depending on the settings.

If you need to validate the actual relationship identifier that was sent, pass a Closure for the next argument as per here:
https://github.com/cloudcreativity/json-api/blob/master/src/Contracts/Validators/RelationshipsValidatorInterface.php#L55-L56

Alternatively you can pass an instance of AcceptRelatedResourceInterface which would allow you to use dependency injection within that instance if you resolve it out of the container.

If you're still stuck or can't figure out how to do what you're trying to achieve, then create a new issue with an explanation of what you're trying to validate and I'll be able to help.

@mandryka
Copy link

@lindyhopchris thanks a lot!
I created AcceptRelatedEntity class, which implements AcceptRelatedResourceInterface
and added validation for related entity to accept(...). Also I used ErrorCreatorTrait for adding errors.

@mosen
Copy link
Author

mosen commented May 29, 2017

Might be able to close this one, since it seems like everything has been rewritten 😄

@lindyhopchris
Copy link
Member

Yeah, good point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants