Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Automatically Setting the owner Field

Automatically Setting the owner Field

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

The voter from chapter 52 needs $project->getOwner() – this chapter adds the field AND ensures it gets set AUTOMATICALLY on creation, NEVER by the client itself.

Adding the owner field

api/src/Entity/Project.php
use App\Entity\User;

// ... inside the class:

#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
#[Groups(['project:read'])]
private ?User $owner = null;

public function getOwner(): ?User
{
    return $this->owner;
}

public function setOwner(User $owner): static
{
    $this->owner = $owner;

    return $this;
}

Achtung: DELIBERATELY WITHOUT project:write in the groups – if owner were WRITABLE, ANY user could claim, when creating a project, that ANOTHER user is the owner. The field is set INSTEAD via a state processor.

Writing an owner processor

api/src/State/ProjectOwnerProcessor.php
<?php

declare(strict_types=1);

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Project;
use App\Entity\User;
use Symfony\Bundle\SecurityBundle\Security;

final class ProjectOwnerProcessor implements ProcessorInterface
{
    public function __construct(
        private readonly ProcessorInterface $persistProcessor,
        private readonly Security $security,
    ) {
    }

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
    {
        if ($data instanceof Project && null === $data->getOwner()) {
            $user = $this->security->getUser();

            if ($user instanceof User) {
                $data->setOwner($user);
            }
        }

        return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
    }
}

EXACTLY the same wrapping pattern as UserPasswordHasherProcessor from chapter 48 – Symfony\Bundle\SecurityBundle\Security provides the CURRENTLY logged-in user, EXACTLY like $this->getUser() in a classic Symfony controller.

use App\State\ProjectOwnerProcessor;

#[ApiResource(
    processor: ProjectOwnerProcessor::class,
    // ...
)]

Testing the complete behavior

curl -k -X POST https://localhost/api/projects \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name": "My new project"}'

The created project has owner AUTOMATICALLY set to the LOGGED-IN user – a PATCH ON THIS project by the SAME user now WORKS (chapter 53), by a DIFFERENT user without ROLE_ADMIN STILL does NOT.

Tipp: Don't forget the migration: owner_id as a NEW, NOT-NULLABLE column requires EITHER a default value in the migration for ALREADY-existing test data, OR a PRIOR doctrine:database:drop --force && doctrine:database:create, to start fresh with an EMPTY database.