I'm a beginner on Sf6 and i'm stuck on a problem with the doctrine extension. I try to recover some datas from an API and send them to a front-end Angular 13. My personnal project is an application for manage some garden equipments and i look for to recover datas according to the role of the user. If the current user have ['ROLE_USER'] i want to fetch his owns datas but if the user have ['ROLE_ADMIN'] i want to fetch all the datas for this entity. I'm ever able to do it with my entity Garden but not for the equipments entity. My relationnal logical data model:

And the code for CurrentUserExtension.php :
<?php
namespace App\Doctrine;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Garden;
use App\Entity\Lawnmower;
use App\Entity\Lightning;
use App\Entity\Pool;
use App\Entity\Portal;
use App\Entity\Watering;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Security;
/**
* This extension makes sure normal users can only access their own Datas
*/
final class CurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
private $security;
public function __construct(Security $security) {
$this->security = $security;
}
public function applyToCollection(QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
string $operationName = null): void {
$this->addWhere($queryBuilder, $resourceClass);
}
public function applyToItem(QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
array $identifiers,
string $operationName = null,
array $context = []): void {
$this->addWhere($queryBuilder, $resourceClass);
}
private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void {
if ($this->security->isGranted('ROLE_ADMIN')
|| null === $user = $this->security->getUser()) {
return;
}
$rootAlias = $queryBuilder->getRootAliases()[0];
switch ($resourceClass) {
case Garden::class:
$queryBuilder->andWhere(sprintf('%s.user = :current_user', $rootAlias))
->setParameter('current_user', $user);
break;
case Lawnmower::class:
case Lightning::class:
case Pool::class:
case Portal::class:
case Watering::class:
$gardenAlias = sprintf("%s_garden", $rootAlias);
$queryBuilder->innerJoin(sprintf('%s.garden', $rootAlias), $gardenAlias)
->andWhere(sprintf('%s.user = :current_user', $gardenAlias))
->setParameter('current_user', $user);
break;
}
}
}
It's my first post on Stackoverflow so feel free to say me if my post isn't formated as well. Some help will be appreciated. Ps: As you could see in the final class CurrentUserExtension.php i'm using Api Platform.
According to the documentation of Api Platform (https://api-platform.com/docs/core/extensions/) i'm able to fetch gardens depending of the user role, the final class CurrentUserExtension work as expected. I'm looking for doing the same for the equipments entities (Watering, Lawnmower, Pool, Portal and Lightning). Notice the relation between my entities (one-to-many):
- A User could have many gardens but a Garden could belong to a single User.
- A Garden could have many waterings but a Watering could belong to a single Garden.
I just saw there is an error on my relationnal logical data model: the entities Lawnmower, Pool, Portal and Lightning doesn't have the property garden_user_id in their classe. But the entity Watering is ok, i have just a single foreign key garden_id.
I'm able to give you the SQL request for retrieve all the waterings for the user which have the id 2 (this request works fine):
SELECT w.id, w.garden_id, w.name, w.flow_sensor, w.pressure_sensor, w.status FROM watering AS w INNER JOIN garden AS g ON g.id = w.garden_id INNER JOIN user AS u ON u.id = g.user_id WHERE u.id = 2
I think i'm near to my goal but now i've the following error => "[Semantical Error] line 0, col 104 near 'o_garden INNER': Error: 'o_garden' is already defined."
Your problem can be solved with a "conception" change. I would say I do not try to make a single api url with different behaviors based on the user.
To make this work, I advise you to do something like this :
Be careful; my answer is on Symfony 6.2, Php 8, and Api Platform 3
And inside
So ! What does it do?
By default, the Garden entity is only accessible to ADMIN.
So by default,
/api/gardenscant be accessed by a non admin user.But,
/api/gardens/my-gardensas a custom controller returns only a garden linked to the currently connected user.Just call a different endpoint based on the user role on your front end.
But if you want to keep one endpoint, you could do this inside the custom controller :