$entity->errors(): Get errors per entity


#1

Hi,

I’m saving a hasmany-relation and i want to display possible validation errors WITH the specific (shortened/trimmed) entity data to the user WITHOUT iterating the whole entity.

I want to show the user a small excerpt from the entity that has caused the validation error.

So when I run the following code in my Controller i get the entity and the validation errors as a nested array.

$entity = $this->Foo->newEntity($data);
$validationErrors = $entity->getErrors();

But what I actually want is the error message AND a excerpt of the entity.

I came up with two solutions, which both feel quite hacky:

  1. iterate the whole nested $entity = $this->Foo->newEntity($data), check each field for errors and write them to an array which later on I can pass to the view.
  2. Map the results of $validationErrors = $entity->getErrors() to the entity. This way I don’t have to loop through the whole entity structure.

Is there a better way to implement this? Which solution would you prefer?

Thanks in advance.


#2

Round 2:

The following code is a working example.

    public function getErrounousEntities($entity): array
    {
        $iterateErrors = function(
            $entity,
            array $errors,
            array &$erronous,
            string $path = '/'
        ) use (&$iterateErrors)
        {
            foreach($errors as $k => $v) {
                // https://stackoverflow.com/questions/145337/checking-if-array-is-multidimensional-or-not
                $isLeaf = count($v) == count($v, COUNT_RECURSIVE);
                if($isLeaf) {
                    // add error to erronous list
                    $erronous[] = [
                        'errorMsg' => $this->_parseErrorMsgs($errors[$k]),
                        'path' => $path,
                        'field' => $k,
                        'entity' => $this->_trimEntity($entity)
                    ];
                } else {
                    // start recursion
                    $newPath = $path . $k .'/';
                    $iterateErrors($entity[$k], $errors[$k], $erronous, $newPath);
                }
            }
        };

        // initialize iteration
        $erronous = [];
        $iterateErrors($entity, $entity->errors(), $erronous);

        return $erronous;
    }

    private function _parseErrorMsgs(array $errorMsgs): array
    {
        foreach($errorMsgs as $k => $errorMsg) {
            $msgs[] = $errorMsg;
        }
        return $msgs;
    }



    private function _trimEntity($entity): array
    {
        $primitiveTypes = [];
        $props = $entity->visibleProperties();

        foreach($props as $prop) {
            $v = $entity[$prop];
            // see http://php.net/manual/it/function.gettype.php for return values
            switch(gettype($v)) {
                case "array":  $trimmedValue = '[...]'; break;
                case "object":  $trimmedValue = '{...}'; break;
                case "resource":  $trimmedValue = '... res'; break;
                case "resource (closed)": $trimmedValue = '... res(closed)'; break;
                default: $trimmedValue = $v; break;
            }
            $primitiveTypes[$prop] = $trimmedValue;
        }
        return $primitiveTypes;
    }

Still feels hacky to me.
I get an array of errors containing the trimmed entity in question.
It looks like the follownig sample. This is actually what I’m trying to achieve: an array of all error messages with the trimmed entity and field that is responsible for the errror. This array will then be passed to the view.

...

    [2] => Array
        (
            [errorMsg] => Array
                (
                    [0] => This field cannot be left empty
                    [1] => Custom Error
                )

            [path] => /user/2258/
            [field] => name
            [entity] => Array
                (
                    [tel] => foo
                    [nickname] => bar
                    [some_other_prop] => baz
                )

        )

Any improvements\suggestions?