Question

In D8 i'm trying to throw custom exceptions for extra validations that i need to do before the content is saved in my custom entity, but when i do the validations in the presave method and throw a normal Exception:

public function preSave(EntityStorageInterface $storage) { 
  throw new \Exception("The content is duplicated", 409);
}

The response of JSONAPI is code 500 Internal Server Error and the response:

{
"jsonapi": {
    "version": "1.0",
    "meta": {
        "links": {
            "self": {
                "href": "http://jsonapi.org/format/1.0/"
            }
        }
    }
},
"errors": [
    {
        "title": "Internal Server Error",
        "status": "500",
        "detail": "The content is duplicated",
        "links": {
            "via": {
                "href": "http://site.docksal/jsonapi/content_entity/content_entity"
            },
            "info": {
                "href": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1"
            }
        }
    }
]

}

how can i control de error Code, title, status and detail.

Was it helpful?

Solution

thanks @4k4, I solved it using customs constraints in my custom entity, JSONAPI mapping well the error and the admin UI works perfectly with that.

like @kiamlaluno said, i try to explain the solution using constraints:

I want to response in the JSONAPI Request that the content is already exists but with a different code, no 500. So when i use constraints i can validate if content already exist or not and response if is a valid request (TRUE / FALSE), this constraints works in the JSONAPI Responses and in the Drupal Admin UI.

So you need to define the constraint in the folder "my_module/src/Plugin/Validation/Constraint" and create 2 files, for my example i need that the content is unique. so my files are:

UniqueProfileContentConstraint.php

<?php

namespace Drupal\my_module\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * Plugin implementation of the 'unique_entry_constraint'.
 *
 * @Constraint(
 *   id = "unique_profile_content_constraint",
 *   label = @Translation("Unique entry constraint", context = "Validation"),
 * )
 */
class UniqueProfileContentConstraint extends Constraint
{

    // The message that will be shown if the value is not unique.
    public $notUnique = 'This content already exists';

}

And the validator:

UniqueProfileContentConstraintValidator.php

<?php

namespace Drupal\ztv_content\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the UniqueInteger constraint.
 */
class UniqueProfileContentConstraintValidator extends ConstraintValidator
{

    /**
     * {@inheritdoc}
     */
    public function validate($entity, Constraint $constraint) {
      // Next check if the value is unique.
      if (!$this->isUnique($entity)) {
          $this->context->addViolation($constraint->notUnique);
      }
    }

    private function isUnique($entity)
    {
      if ($entity->isNew()) {
        $query = \Drupal::entityQuery('profile_content_entity')
          ->condition('profile_id', $entity->get('profile_id')->getString())
          ->condition('video_id', $entity->get('video_id')->value);
        $storageContent = $query->execute();
        if ($storageContent) {
          return FALSE;
        }
        return TRUE;
      }
    }

}

And finally in the Entity annotation you need to add the id of your constraint:

 *   constraints = {
 *      "unique_profile_content_constraint" = {}
 *   }
 * )
 */
Licensed under: CC-BY-SA with attribution
Not affiliated with drupal.stackexchange
scroll top