neomerx / json-api

Framework agnostic JSON API (jsonapi.org) implementation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Parser potential problem

opened this issue · comments

Regarding: https://github.com/neomerx/json-api/blob/master/src/Encoder/Parser/Parser.php

One model suddenly stopped working with using SELF::DATA output from the schema class.
The relevant error in laravel log was: *[2018-02-20 08:48:18] local.ERROR: data {"exception":"[object] (InvalidArgumentException(code: 0): data at D:\Frameworks\XAMPP\htdocs\projectx\vendor*

The relevant code that throws the exception is:
$isOk = (is_array($data) === true || is_object($data) === true || $data === null); $isOk ?: Exceptions::throwInvalidArgument('data', $data);

Upon closer examination the $data is sometimes populated by an Integer value (number 1) which triggers the exception.

The data is coming from:
/** * @return array|null|object */ protected function getCurrentData() { $relationship = $this->stack->end()->getRelationship(); $data = $relationship->isShowData() === true ? $relationship->getData() : null; return $data; }

and

/** * @return array */ protected function analyzeCurrentData() { $data = $this->getCurrentData(); $result = $this->analyzeData($data); return $result; }

Is this somekind of bug ?

Probably the source of that invalid number is your schema. However, we have to find the source and make it easier to diagnose such errors in the future.

Can you please update \Neomerx\JsonApi\Schema\RelationshipObject with the code below and see what is the source of that integer?

I would also appreciate if you fork the project and add some testing sample that shows the error.

<?php namespace Neomerx\JsonApi\Schema;

/**
 * Copyright 2015-2017 info@neomerx.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use \Closure;
use \Neomerx\JsonApi\Factories\Exceptions;
use \Neomerx\JsonApi\Contracts\Schema\RelationshipObjectInterface;

/**
 * @package Neomerx\JsonApi
 */
class RelationshipObject implements RelationshipObjectInterface
{
    /**
     * @var string
     */
    private $name;

    /**
     * @var object|array|null
     */
    private $data;

    /**
     * @var array<string,\Neomerx\JsonApi\Contracts\Schema\LinkInterface>
     */
    private $links;

    /**
     * @var object|array|null|Closure
     */
    private $meta;

    /**
     * @var bool
     */
    private $isShowData;

    /**
     * @var bool
     */
    private $isRoot;

    /**
     * @var bool
     */
    private $isDataEvaluated = false;

    /**
     * @param string                                                        $name
     * @param object|array|null|Closure                                     $data
     * @param array<string,\Neomerx\JsonApi\Contracts\Schema\LinkInterface> $links
     * @param object|array|null|Closure                                     $meta
     * @param bool                                                          $isShowData
     * @param bool                                                          $isRoot
     *
     * @SuppressWarnings(PHPMD.StaticAccess)
     */
    public function __construct(
        $name,
        $data,
        array $links,
        $meta,
        $isShowData,
        $isRoot
    ) {
        is_bool($isRoot) === true ?: Exceptions::throwInvalidArgument('isRoot', $isRoot);
        is_bool($isShowData) === true ?: Exceptions::throwInvalidArgument('isShowData', $isShowData);
        $isOk = (($isRoot === false && is_string($name) === true) || ($isRoot === true && $name === null));
        $isOk ?: Exceptions::throwInvalidArgument('name', $name);

        $this->name       = $name;
        $this->links      = $links;
        $this->meta       = $meta;
        $this->isShowData = $isShowData;
        $this->isRoot     = $isRoot;

        $this->setData($data);
    }

    /**
     * @inheritdoc
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @inheritdoc
     */
    public function getData()
    {
        if ($this->isDataEvaluated === false) {
            $this->isDataEvaluated = true;

            if ($this->data instanceof Closure) {
                /** @var Closure $data */
                $data = $this->data;
                $this->setData($data());
            }
        }

        assert(is_array($this->data) === true || is_object($this->data) === true || $this->data === null);

        return $this->data;
    }

    /**
     * @inheritdoc
     */
    public function getLinks()
    {
        return $this->links;
    }

    /**
     * @inheritdoc
     */
    public function getMeta()
    {
        if ($this->meta instanceof Closure) {
            $meta = $this->meta;
            $this->meta = $meta();
        }

        return $this->meta;
    }

    /**
     * @inheritdoc
     */
    public function isShowData()
    {
        return $this->isShowData;
    }

    /**
     * @inheritdoc
     */
    public function isRoot()
    {
        return $this->isRoot;
    }

    /**
     * @param array|object|null $data
     *
     * @return void
     */
    private function setData($data)
    {
        assert(is_array($data) === true || $data instanceof Closure || is_object($data) === true || $data === null);

        $this->data = $data;
    }
}

Thanks for your reply. After replacement the error is

[2018-02-21 02:17:08] local.ERROR: assert(): assert(is_array($data) === true || $data instanceof Closure || is_object($data) === true || $data === null) failed {"exception":"[object] (ErrorException(code: 0): assert(): assert(is_array($data) === true || $data instanceof Closure || is_object($data) === true || $data === null) failed at D:\Frameworks\XAMPP\htdocs\projectx\vendor
eomerx\json-api\src\Schema\RelationshipObject.php:167)
[stacktrace]
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'assert(): asser...', 'D:\\Frameworks\\X...', 167, Array)
#1 D:\Frameworks\XAMPP\htdocs\projectx\vendor
eomerx\json-api\src\Schema\RelationshipObject.php(167): assert(false, 'assert(is_array...')
#2 D:\Frameworks\XAMPP\htdocs\projectx\vendor
eomerx\json-api\src\Schema\RelationshipObject.php(92): Neomerx\JsonApi\Schema\RelationshipObject->setData(4)
#3 D:\Frameworks\XAMPP\htdocs\projectx\vendor
eomerx\json-api\src\Factories\Factory.php(385): Neomerx\JsonApi\Schema\RelationshipObject->__construct('owner', 4, Array, Object(Closure), true, false)
#4 D:\Frameworks\XAMPP\htdocs\projectx\vendor
eomerx\json-api\src\Schema\SchemaProvider.php(339): Neomerx\JsonApi\Factories\Factory->createRelationshipObject('owner', 4, Array, Object(Closure), true, false)
#5 D:\Frameworks\XAMPP\htdocs\projectx\vendor
eomerx\json-api\src\Schema\SchemaProvider.php(229): Neomerx\JsonApi\Schema\SchemaProvider->createRelationshipObject(Object(App\RigModel), 'owner', Array)

Most likely your Schema occasionally returns invalid value in self::DATA section.

As you has cut the error stack I can't tell you which one, however, it's likely to be related to RigModel.

The problem seems resolved when i changed the public functions () in the models to non-conflicting names that match the defined Resources. Strange.....

I will add the code changes above so it would diagnose such problems. It will help developers to fix issues with their schemas on early stages.