Search code examples
phpsymfonydoctrineentity-relationshipapi-platform.com

Adding relationship to an Entity couses weird ORM mapping error


In Symfony Api Platform application, using Maker Bundle to add a relationship field "Owner" to "Community" Entity coused all "Get" api calls to return the same error. This is a new project I use all the newest available version.

Request: curl -X 'GET'
'http://127.0.0.1:8000/api/communities?page=1'
-H 'accept: application/ld+json'

//Error

{
  "@id": "/api/errors/500",
  "@type": "hydra:Error",
  "title": "An error occurred",
  "detail": "Attempted to load class \"ClassMetadataInfo\" from namespace \"Doctrine\\ORM\\Mapping\".\nDid you forget a \"use\" statement for another namespace?",
  "status": 500,
  "type": "/errors/500",
  "trace": [
    {
      "file": "\\vendor\\api-platform\\core\\src\\Doctrine\\Orm\\Extension\\EagerLoadingExtension.php",
      "line": 98,
      "function": "joinRelations",
      "class": "ApiPlatform\\Doctrine\\Orm\\Extension\\EagerLoadingExtension",
      "type": "->"
    },
    {
      "file": "\\vendor\\api-platform\\core\\src\\Doctrine\\Orm\\Extension\\EagerLoadingExtension.php",
      "line": 53,
      "function": "apply",
      "class": "ApiPlatform\\Doctrine\\Orm\\Extension\\EagerLoadingExtension",
      "type": "->"
    },
// Community.php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use App\Repository\CommunityRepository;
use Doctrine\DBAL\Types\Types;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\User;


#[ORM\Entity(repositoryClass: CommunityRepository::class)]
#[ApiResource(
    normalizationContext: ['groups' => ['community:read']],
    denormalizationContext: ['groups' => ['community:create', 'community:update']],
)]
#[ORM\Table(name: '`community`')]
#[UniqueEntity('name')]
class Community
{
    const STATUS_PUBLIC = 'public';
    const STATUS_PRIVATE = 'private';
    const STATUS_RESTRICTED = 'restricted';

    #[Groups(['community:read'])]
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[Assert\NotBlank]
    #[Groups(['community:read', 'community:create', 'community:update'])]
    #[ORM\Column(length: 50)]
    
    private ?string $name = null;

    // Address and name of given community
    #[Groups(['community:read', 'community:create', 'community:update'])]
    #[ORM\Column(type: Types::TEXT, nullable: true)]
    private ?string $description = null;

    // Amount of users of given community
    #[ORM\Column]
    #[Groups(['community:read'])]
    private ?int $numberOfUsers = 0;

    // Date of creation of given community
    #[Groups(['community:read'])]
    #[ORM\Column(type: Types::DATETIMETZ_MUTABLE)]
    private ?\DateTimeInterface $creation_time = null;

    // Status of given community; PUBLIC, PRIVATE, RESTRICTED
    #[Groups(['community:read', 'community:create', 'community:update'])]
    #[ORM\Column(type: 'string', length: 10)]
    private ?string $status = self::STATUS_PUBLIC;

    #[Groups(['community:read', 'community:create', 'community:update'])]
    #[ORM\ManyToOne(targetEntity: User::class ,inversedBy: 'owned_communites')]
    #[ORM\JoinColumn(nullable: false)]
    private ?User $owner = null;

    //getters and setters
// User Entity

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use Doctrine\DBAL\Types\Types;
use App\Repository\UserRepository;
use App\State\PasswordHasher;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;

use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\Community;

#[ApiResource(
    operations: [
        new GetCollection(),
        new Post(processor: PasswordHasher::class, validationContext: ['groups' => ['Default', 'user:create']]),
        new Get(),
        new Put(processor: PasswordHasher::class),
        new Patch(processor: PasswordHasher::class),
        new Delete(),
    ],
    normalizationContext: ['groups' => ['user:read']],
    denormalizationContext: ['groups' => ['user:create', 'user:update']],
)]
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[UniqueEntity('email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[Groups(['user:read'])]
    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    #[ORM\GeneratedValue]
    private ?int $id = null;

    #[Assert\NotBlank]
    #[Assert\Email]
    #[Groups(['user:read', 'user:create', 'user:update'])]
    #[ORM\Column(length: 80, unique: true)]
    private ?string $email = null;

    #[ORM\Column]
    //DEBUG ONLY:
    //#[Groups(['user:read', 'user:create', 'user:update'])]
    private ?string $password = null;

    #[Assert\NotBlank(groups: ['user:create'])]
    #[Groups(['user:create', 'user:update'])]
    private ?string $plainPassword = null;

    #[ORM\Column(type: 'json')]
    private array $roles = [];

    #[Assert\NotBlank]
    #[Groups(['user:read', 'user:create', 'user:update'])]
    #[ORM\Column(length: 25)]
    private ?string $nickname = null;

    #[Assert\NotBlank]
    #[Groups(['user:read', 'user:create', 'user:update'])]
    #[ORM\Column(length: 30)]
    private ?string $login = null;

    #[Assert\NotBlank]
    #[Groups(['user:read', 'user:create', 'user:update'])]
    #[ORM\Column(type: Types::DATETIMETZ_MUTABLE)]
    private ?\DateTimeInterface $birthday = null;

    #[Groups(['user:read'])]
    #[ORM\Column(type: Types::DATETIMETZ_MUTABLE)]
    private ?\DateTimeInterface $creation_time = null;

    #[Groups(['user:read', 'user:create', 'user:update'])]
    #[ORM\OneToMany(targetEntity: Community::class, mappedBy: 'owner')]
    private Collection $owned_communites;
//getters and setters

Solution

  • Something is completely broken in Relationships in the newest version of the stack. The error appears everytime you add connection between entities. You can either try downgrading each component of Doctrine one by one via composer or simply move to Laravel and create your API there. It's much less broken. Cheers!