api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.4k stars 859 forks source link

Unable to generate an IRI for the item of type App\\Entity\\User #5432

Closed Marko1212 closed 1 year ago

Marko1212 commented 1 year ago

I have created an API using Symfony 6 and API Platform 3. For the first entities, everything went fine but I have an error now when I am doing a GET collection request for User entity (end point : api/users) :

Unable to generate an IRI for the item of type \"App\\Entity\\User\"

So why this happens and how to fix it ?

Here is an excerpt from my User entity :

#[ApiResource(

operations: [
    new Delete(),
    new Get(),
    new Put(),
    new Patch(),
    new GetCollection(),
    new Post()
],
normalizationContext: ['groups' => ['read:User']]
)]
#[ApiFilter(OrderFilter::class)]
#[ORM\Entity(repositoryClass: UserRepository::class)]
class User
{

#[ORM\Id]
#[ORM\Column(unique: true, nullable: false, type: 'string')]
#[Groups(groups: ['read:User'])]
#[ApiProperty(identifier: true)]
private $username;

#[ORM\OneToOne(mappedBy: 'user', cascade: ['all'])]
#[Groups(groups: ['read:User'])]
private ?Employee $employee = null;

#[ORM\Column(name: 'first_name', length: 255, nullable: true)]
#[Groups(groups: ['read:User'])]
private ?string $firstName = null;

#[ORM\Column(name: 'last_name', length: 255, nullable: true)]
#[Groups(groups: ['read:User'])]
private ?string $lastName = null;

#[ORM\OneToMany(mappedBy: 'username', targetEntity: UserRole::class, cascade: ['all'], orphanRemoval: true)]
#[Groups(groups: ['read:User'])]
private Collection $userRoles;

#[ORM\Column(length: 2000, nullable: true)]
private ?string $password = null;

public function __construct()
{
    $this->userRoles = new ArrayCollection();
}

public function getUsername(): string
{
    return $this->username;
}

public function setUsername(string $username): self
{
    $this->username = $username;
    return $this;
}

Thanks in advance!

Marko1212 commented 1 year ago

This fixes the issue :

#[ApiResource(
    operations: [
        new Delete(uriTemplate: 'users/{username}'),
        new Get(uriTemplate: 'users/{username}'),
        new Put(uriTemplate: 'users/{username}'),
        new Patch(uriTemplate: 'users/{username}'),
        new GetCollection(uriTemplate: 'users'),
        new Post(uriTemplate: 'users')
    ],
...
]
bobas01 commented 5 months ago

Hello i have the same problem but i try this solution and change nothing in my side. `<?php

namespace App\Entity;

use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Post; use Doctrine\DBAL\Types\Types; use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Delete; use App\Controller\MeController; use Doctrine\ORM\Mapping as ORM; use App\Entity\Traits\HasIdTrait; use App\Repository\UserRepository; use App\Entity\Traits\HasNameTrait; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Action\NotFoundAction; use ApiPlatform\Metadata\GetCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Security\Core\User\UserInterface;

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use App\State\UserPasswordHasher; use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;

[ORM\Entity(repositoryClass: UserRepository::class)]

[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]

[ApiResource(

operations: [

    new GetCollection(
        name: 'me',
        uriTemplate: '/me',
        controller: MeController::class,
        read: false,
        paginationEnabled: false,
        security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_USER')",

    ),
    new Post(
        processor: UserPasswordHasher::class,
    ),
    new Delete(
        security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_USER')",
    ),
    new Patch(
        security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_USER')",
    ),
    new Get(
        controller: NotFoundAction::class,
        read: false,
        output: false,
        paginationEnabled: false,
        normalizationContext: ['groups' => ["read:User"]],
        filters: [],
        security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_USER')",

    ),
],

)]

[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]

class User implements UserInterface, PasswordAuthenticatedUserInterface, JWTUserInterface {

use HasIdTrait;

use HasNameTrait;

#[ORM\Column(length: 180)]
#[Groups(('read:User'))]
private ?string $email = null;

/**
 * @var list<string> The user roles
 */
#[ORM\Column]
#[Groups(('read:User'))]
private array $roles = [];

/**
 * @var string The hashed password
 */
#[ORM\Column(length: 255)]
#[Groups(('user:create'))]
private ?string $password = null;

#[Groups(['user:create'])]
private ?string $plainPassword = null;

#[ORM\Column(length: 50)]
#[Groups(('read:User'))]
private ?string $firstName = null;

#[ORM\Column(length: 50)]
#[Groups(('read:User'))]
private ?string $username = null;

#[ORM\Column(type: Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $date_of_birth = null;

#[ORM\Column(length: 255, nullable: true)]
#[Groups(('read:User'))]
private ?string $address = null;

#[ORM\Column(length: 100, nullable: true)]
#[Groups(('read:User'))]
private ?string $city = null;

#[ORM\Column(length: 10, nullable: true)]
#[Groups(('read:User'))]
private ?string $postal_code = null;

#[ORM\Column(length: 255, nullable: true)]
#[Groups(('read:User'))]
private ?string $province = null;

#[ORM\Column(length: 50, nullable: true)]
#[Groups(('read:User'))]
private ?string $country = null;

#[ORM\Column]
private ?bool $club = null;

#[ORM\OneToMany(targetEntity: Packages::class, mappedBy: 'user')]
private Collection $packages;

#[ORM\OneToMany(targetEntity: Rates::class, mappedBy: 'user')]
private Collection $rates;

#[ORM\OneToMany(targetEntity: Likes::class, mappedBy: 'user')]
private Collection $likes;

#[ORM\OneToMany(targetEntity: Posts::class, mappedBy: 'user')]
private Collection $posts;

#[ORM\ManyToOne(inversedBy: 'user')]
private ?Club $clubs = null;

#[ORM\Column]
private bool $isVerified = false;

public function setId(int $id): self
{
    $this->id = $id;
    return $this;
}

public function getEmail(): ?string
{
    return $this->email;
}

public function setEmail(string $email): static
{
    $this->email = $email;

    return $this;
}

public function getFirstName(): ?string
{
    return $this->firstName;
}

public function setFirstName(string $firstName): static
{
    $this->firstName = $firstName;

    return $this;
}

public function getUsername(): ?string
{
    return $this->username;
}

public function setUsername(string $username): static
{
    $this->username = $username;

    return $this;
}

public function getDateOfBirth(): ?\DateTimeInterface
{
    return $this->date_of_birth;
}

public function setDateOfBirth(\DateTimeInterface $date_of_birth): static
{
    $this->date_of_birth = $date_of_birth;

    return $this;
}

/**
 * A visual identifier that represents this user.
 *
 * @see UserInterface
 */
public function getUserIdentifier(): string
{
    return (string) $this->email;
}

/**
 * @see UserInterface
 *
 * @return list<string>
 */
public function getRoles(): array
{
    $roles = $this->roles;
    // guarantee every user at least has ROLE_USER
    $roles[] = 'ROLE_USER';

    return array_unique($roles);
}

/**
 * @param list<string> $roles
 */
public function setRoles(array $roles): static
{
    $this->roles = $roles;

    return $this;
}

/**
 * @see PasswordAuthenticatedUserInterface
 */
public function getPassword(): ?string
{
    return $this->password;
}

public function setPassword(string $password): static
{
    $this->password = $password;

    return $this;
}

public function getPlainPassword(): ?string
{
    return $this->plainPassword;
}

public function setPlainPassword(?string $plainPassword): self
{
    $this->plainPassword = $plainPassword;

    return $this;
}

/**
 * @see UserInterface
 */
public function eraseCredentials(): void
{
    // If you store any temporary, sensitive data on the user, clear it here
    $this->plainPassword = null;
}

// ...

public function __construct()
{
    $this->packages = new ArrayCollection();
    $this->rates = new ArrayCollection();
    $this->likes = new ArrayCollection();
    $this->posts = new ArrayCollection();
    $this->roles = ['ROLE_USER'];
}

/**
 * @return Collection<int, Packages>
 */
public function getPackages(): Collection
{
    return $this->packages;
}

public function addPackage(Packages $package): static
{
    if (!$this->packages->contains($package)) {
        $this->packages->add($package);
        $package->setUser($this);
    }

    return $this;
}

public function removePackage(Packages $package): static
{
    if ($this->packages->removeElement($package)) {
        // set the owning side to null (unless already changed)
        if ($package->getUser() === $this) {
            $package->setUser(null);
        }
    }

    return $this;
}

public function getAddress(): ?string
{
    return $this->address;
}

public function setAddress(string $address): static
{
    $this->address = $address;

    return $this;
}

public function getCity(): ?string
{
    return $this->city;
}

public function setCity(string $city): static
{
    $this->city = $city;

    return $this;
}

public function getPostalCode(): ?string
{
    return $this->postal_code;
}

public function setPostalCode(string $postal_code): static
{
    $this->postal_code = $postal_code;

    return $this;
}

public function getProvince(): ?string
{
    return $this->province;
}

public function setProvince(?string $province): static
{
    $this->province = $province;

    return $this;
}

public function getCountry(): ?string
{
    return $this->country;
}

public function setCountry(string $country): static
{
    $this->country = $country;

    return $this;
}

public function isClub(): ?bool
{
    return $this->club;
}

public function setClub(bool $club): static
{
    $this->club = $club;

    return $this;
}

/**
 * @return Collection<int, Rates>
 */
public function getRates(): Collection
{
    return $this->rates;
}

public function addRate(Rates $rate): static
{
    if (!$this->rates->contains($rate)) {
        $this->rates->add($rate);
        $rate->setUser($this);
    }

    return $this;
}

public function removeRate(Rates $rate): static
{
    if ($this->rates->removeElement($rate)) {
        // set the owning side to null (unless already changed)
        if ($rate->getUser() === $this) {
            $rate->setUser(null);
        }
    }

    return $this;
}

/**
 * @return Collection<int, Likes>
 */
public function getLikes(): Collection
{
    return $this->likes;
}

public function addLike(Likes $like): static
{
    if (!$this->likes->contains($like)) {
        $this->likes->add($like);
        $like->setUser($this);
    }

    return $this;
}

public function removeLike(Likes $like): static
{
    if ($this->likes->removeElement($like)) {
        // set the owning side to null (unless already changed)
        if ($like->getUser() === $this) {
            $like->setUser(null);
        }
    }

    return $this;
}

/**
 * @return Collection<int, Posts>
 */
public function getPosts(): Collection
{
    return $this->posts;
}

public function addPost(Posts $post): static
{
    if (!$this->posts->contains($post)) {
        $this->posts->add($post);
        $post->setUser($this);
    }

    return $this;
}

public function removePost(Posts $post): static
{
    if ($this->posts->removeElement($post)) {
        // set the owning side to null (unless already changed)
        if ($post->getUser() === $this) {
            $post->setUser(null);
        }
    }

    return $this;
}

public static function createFromPayload($username, array $payload): self
{
    return (new self())
        ->setEmail($username)
        ->setRoles($payload['roles'] ?? []);
}

public function getClubs(): ?Club
{
    return $this->clubs;
}

public function setClubs(?Club $clubs): static
{
    $this->clubs = $clubs;

    return $this;
}

public function isVerified(): bool
{
    return $this->isVerified;
}

public function setIsVerified(bool $isVerified): static
{
    $this->isVerified = $isVerified;

    return $this;
}

} `