Skip to content
This repository was archived by the owner on Jan 2, 2023. It is now read-only.
This repository was archived by the owner on Jan 2, 2023. It is now read-only.

SerializerInterface violates LSP #115

@f3ath

Description

@f3ath

Hi @tobscure
First of all, thanks for your efforts making this library. I was looking at the php libraries implementing jsonapi in order to pick one for one of my projects. There are a few of them worth trying, including yours. Unfortunately, it looks like that all of them suffer from the same issue.

Issue

They all have the similar idea of serializers - the logic which converts a business entity (model) into a json data object. And these serializers look pretty much similarly: they have a number of methods like getId($model), getAttributes($model) which take the entity as a parameter. These methods know about their $models internal structure and they use this knowledge to extract the id, attributes or whatever is needed to build the json. Consider the example from readme:

use Tobscure\JsonApi\AbstractSerializer;

class PostSerializer extends AbstractSerializer
{
    protected $type = 'posts';

    public function getAttributes($post, array $fields = null)
    {
        return [
            'title' => $post->title,
            'body'  => $post->body,
            'date'  => $post->date
        ];
    }
}

PostSerializer can only deal with $post models. The getAttributes() call will fail on everything else except a properly structured post object. But SerializerInterface does not restrict the model to anything particular. What SerializerInterface says is basically: you give me anything (@param mixed $model) and I tell you its attributes. Therefore, PostSerializer breaks the contract given by SerializerInterface. It means violation of Liskov Substitution Principle.

Solution (well, a kind of)

Instead of these pseudo-universal serializers, we should have something like ResourceInterface:

interface ResourceInterface
{
    public function getType(): string;
    public function getId(): string;
    public function getAttributes(array $fields = null): array;
    public function getLinks(): array;
    public function getMeta(): array;
    public function getRelationship($name):  ?\Tobscure\JsonApi\Relationship;
}

And a use-case would be like

class PostResource implements ResourceInterface
{
    protected $type = 'posts';
    public function __construct($post)
    {
       // validate $post
    }

    public function getAttributes(array $fields = null)
    {
        return [
            'title' => $this->post->title,
            'body'  => $this->post->body,
            'date'  => $this->post->date
        ];
    }
}
$document->setData(new PostResource($post));

Since your library version is still 0.*, it is not too late to make backward-incompatible changes to fix this issue. Please let me know what you think.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions