API-platform POST operation swagger page empty - swagger

Symfony 3.4.10
Api-platform/core
I set up API-Platform/core on a Symfony 3.4.10 project, everything work well and I can access the swagger page for test via "/api" (url route to show api test interface).
For the GET operations everything is right.
But for the POST operation on an entity named "Trajet" (see code) the "example value" show only "{}" and nothing else. If I try the button "Try it out" I get a blank space where nothing is shew instead of the traditional form to test a post operation (see capture).
capture of the swagger page:
I don't understand what I missed. Could someone please give me ideas how to fix it and where the problem can come from. I'm out of ideas to find a solution.
Here is the code of my entity Trajet for which post operation is empty and seem to be not usable.
<?php
namespace Covoituragesimple\AnnonceBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* Trajet
* #ApiResource(
* collectionOperations={"get", "post"},
* itemOperations={"get"},
* attributes={
* "normalization_context"={"groups"={"read"}},
* "denormalization_context"={"groups"={"write"}}
* }
* )
* #ORM\Table(name="trajet")
* #ORM\Entity(repositoryClass="Covoituragesimple\AnnonceBundle\Repository\TrajetRepository")
*/
class Trajet
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Groups({"read"})
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="numberofseats", type="integer")
* #Assert\NotBlank()
* #Groups({"read"})
*/
private $numberofseats;
/**
* #var \DateTime
*
* #ORM\Column(name="creationdate", type="datetime")
* #Assert\Type("\DateTime")
* #Groups({"read"})
*/
private $creationdate;
/**
* #var \DateTime
*
* #ORM\Column(name="rdvdatetime", type="datetime")
* #Assert\Type("\DateTime")
* #Groups({"read"})
*/
private $rdvdatetime;
/**
* #ORM\ManyToOne(targetEntity="Covoituragesimple\AnnonceBundle\Entity\Commune")
*/
private $commune;
/**
* #var string
*
* #ORM\Column(name="chercheoupropose", type="text")
* #Groups({"read"})
*/
private $chercheoupropose;
/**
* #var string
*
* #ORM\Column(name="message", type="text")
* #Assert\NotBlank(
* message="Un petit message pour votre annonce"
* )
* #Groups({"read"})
*/
private $message;
/**
* #var string
*
* #ORM\Column(name="contrepartietype", type="text")
* #Groups({"read"})
*/
private $contrepartietype;
/**
* #ORM\ManyToOne(targetEntity="Covoituragesimple\AnnonceBundle\Entity\Module")
* #Groups({"read"})
*/
protected $module;
/**
* #var string
*
* #ORM\Column(name="contrepartiemsg", nullable=true, type="text")
* #Groups({"read"})
*/
private $contrepartiemsg;
/**
* #ORM\ManyToOne(targetEntity="Covoituragesimple\AnnonceBundle\Entity\Covoitureur",
inversedBy="trajets",
cascade={"persist"})
*/
protected $covoitureur;
/**
* #ORM\OneToMany(targetEntity="Covoituragesimple\AnnonceBundle\Entity\Contact", mappedBy="trajet", cascade={"remove"})
*/
private $contacts;
/**
* #var bool
*
* #ORM\Column(name="moderated", type="boolean")
*/
private $moderated = false;
/**
* #var bool
*
* #ORM\Column(name="active", type="boolean")
*/
private $active = true;
/**
* Constructor
*/
public function __construct()
{
$this->setNumberofseats(1);
$this->setMessage("");
$this->setRdvdatetime(new \DateTime('today'));
$this->setCreationdate(new \DateTime('now'));
$this->contacts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set numberofseats.
*
* #param int $numberofseats
*
* #return Trajet
*/
public function setNumberofseats($numberofseats)
{
$this->numberofseats = $numberofseats;
return $this;
}
/**
* Get numberofseats.
*
* #return int
*/
public function getNumberofseats()
{
return $this->numberofseats;
}
/**
* Set creationdate.
*
* #param \DateTime $creationdate
*
* #return Trajet
*/
public function setCreationdate($creationdate)
{
$this->creationdate = $creationdate;
return $this;
}
/**
* Get creationdate.
*
* #return \DateTime
*/
public function getCreationdate()
{
return $this->creationdate;
}
/**
* Set rdvdatetime.
*
* #param \DateTime $rdvdatetime
*
* #return Trajet
*/
public function setRdvdatetime($rdvdatetime)
{
$this->rdvdatetime = $rdvdatetime;
return $this;
}
/**
* Get rdvdatetime.
*
* #return \DateTime
*/
public function getRdvdatetime()
{
return $this->rdvdatetime;
}
/**
* Set chercheoupropose.
*
* #param string $chercheoupropose
*
* #return Trajet
*/
public function setChercheoupropose($chercheoupropose)
{
$this->chercheoupropose = $chercheoupropose;
return $this;
}
/**
* Get chercheoupropose.
*
* #return string
*/
public function getChercheoupropose()
{
return $this->chercheoupropose;
}
/**
* Set message.
*
* #param string $message
*
* #return Trajet
*/
public function setMessage($message)
{
$this->message = $message;
return $this;
}
/**
* Get message.
*
* #return string
*/
public function getMessage()
{
return $this->message;
}
/**
* Set contrepartietype.
*
* #param string $contrepartietype
*
* #return Trajet
*/
public function setContrepartietype($contrepartietype)
{
$this->contrepartietype = $contrepartietype;
return $this;
}
/**
* Get contrepartietype.
*
* #return string
*/
public function getContrepartietype()
{
return $this->contrepartietype;
}
/**
* Set contrepartiemsg.
*
* #param string|null $contrepartiemsg
*
* #return Trajet
*/
public function setContrepartiemsg($contrepartiemsg = null)
{
$this->contrepartiemsg = $contrepartiemsg;
return $this;
}
/**
* Get contrepartiemsg.
*
* #return string|null
*/
public function getContrepartiemsg()
{
return $this->contrepartiemsg;
}
/**
* Set moderated.
*
* #param bool $moderated
*
* #return Trajet
*/
public function setModerated($moderated)
{
$this->moderated = $moderated;
return $this;
}
/**
* Get moderated.
*
* #return bool
*/
public function getModerated()
{
return $this->moderated;
}
/**
* Set active.
*
* #param bool $active
*
* #return Trajet
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active.
*
* #return bool
*/
public function getActive()
{
return $this->active;
}
/**
* Set module.
*
* #param \Covoituragesimple\AnnonceBundle\Entity\Module|null $module
*
* #return Trajet
*/
public function setModule(\Covoituragesimple\AnnonceBundle\Entity\Module $module = null)
{
$this->module = $module;
return $this;
}
/**
* Get module.
*
* #return \Covoituragesimple\AnnonceBundle\Entity\Module|null
*/
public function getModule()
{
return $this->module;
}
/**
* Set covoitureur.
*
* #param \Covoituragesimple\AnnonceBundle\Entity\Covoitureur|null $covoitureur
*
* #return Trajet
*/
public function setCovoitureur(\Covoituragesimple\AnnonceBundle\Entity\Covoitureur $covoitureur = null)
{
$this->covoitureur = $covoitureur;
return $this;
}
/**
* Get covoitureur.
*
* #return \Covoituragesimple\AnnonceBundle\Entity\Covoitureur|null
*/
public function getCovoitureur()
{
return $this->covoitureur;
}
/**
* Add contact.
*
* #param \Covoituragesimple\AnnonceBundle\Entity\Contact $contact
*
* #return Trajet
*/
public function addContact(\Covoituragesimple\AnnonceBundle\Entity\Contact $contact)
{
$this->contacts[] = $contact;
return $this;
}
/**
* Remove contact.
*
* #param \Covoituragesimple\AnnonceBundle\Entity\Contact $contact
*
* #return boolean TRUE if this collection contained the specified element, FALSE otherwise.
*/
public function removeContact(\Covoituragesimple\AnnonceBundle\Entity\Contact $contact)
{
return $this->contacts->removeElement($contact);
}
/**
* Get contacts.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getContacts()
{
return $this->contacts;
}
/**
* Set commune.
*
* #param \Covoituragesimple\AnnonceBundle\Entity\Commune|null $commune
*
* #return Trajet
*/
public function setCommune(\Covoituragesimple\AnnonceBundle\Entity\Commune $commune = null)
{
$this->commune = $commune;
return $this;
}
/**
* Get commune.
*
* #return \Covoituragesimple\AnnonceBundle\Entity\Commune|null
*/
public function getCommune()
{
return $this->commune;
}
}

I think it's because you forget to define "write" group in your entity attribute, if you rename it by "read" in denormalization_context (or add "write" group in your entity attributes), it should work.
Something like this:
* #ApiResource(
* collectionOperations={"get", "post"},
* itemOperations={"get"},
* attributes={
* "normalization_context"={"groups"={"read"}},
* "denormalization_context"={"groups"={"read"}} // <-- here
* }
* )
More detail here: https://api-platform.com/docs/core/serialization
I hope this can help you

Related

Discord oAuth2 login after authorization was given

I have a symfony4 application and I'm using knpuniversity/oauth2-client-bundle to authenticate a user against discords oAuth endpoint.
The user clicks on the 'Login via Discord' button, he sees the authorization page from discord, accepts it and is now logged in on my page.
So far so good.
Here is what is not working:
The user is on another computer, so no session on my page. He logs in to discord web client. After that he visits my page but he is not logged in.
When he clicks again on 'Login via Discord' he sees the authorization page again instead of directly being logged in on my page.
Maybe I get something wrong here but usually when I use an oAuth login with google, facebook or anything else just like here on stackoverflow I never see the authorization page again. I click on 'login with XY' and, as long as I'm logged in to my corresponding account, I will immediately be logged in on the other page as well.
<?php
namespace App\Security;
use App\Entity\User;
use App\Repository\UserRepository;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Client\OAuth2Client;
use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator;
use League\OAuth2\Client\Token\AccessToken;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class DiscordAuthenticator extends SocialAuthenticator
{
/**
* #var \KnpU\OAuth2ClientBundle\Client\ClientRegistry
*/
private $clientRegistry;
/**
* #var \App\Repository\UserRepository
*/
private $repository;
/**
* #var \Symfony\Component\Routing\RouterInterface
*/
private $router;
/**
* DiscordAuthenticator constructor.
*
* #param \KnpU\OAuth2ClientBundle\Client\ClientRegistry $clientRegistry
* #param \App\Repository\UserRepository $repository
* #param \Symfony\Component\Routing\RouterInterface $router
*/
public function __construct(
ClientRegistry $clientRegistry,
UserRepository $repository,
RouterInterface $router
) {
$this->clientRegistry = $clientRegistry;
$this->repository = $repository;
$this->router = $router;
}
/**
* #inheritDoc
*/
public function start(Request $request, AuthenticationException $authException = null)
{
return new RedirectResponse('/login/', Response::HTTP_TEMPORARY_REDIRECT);
}
/**
* #inheritDoc
*/
public function supports(Request $request): bool
{
return $request->attributes->get('_route') === 'discord_set_token';
}
/**
* #inheritDoc
*/
public function getCredentials(Request $request)
{
return $this->fetchAccessToken($this->getDiscordClient());
}
/**
* #inheritDoc
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
try {
/** #var \Wohali\OAuth2\Client\Provider\DiscordResourceOwner $discordUser */
$discordUser = $this->getDiscordClient()
->fetchUserFromToken($credentials);
$email = $discordUser->getEmail();
$existingUser = $this->repository->findOneBy(
[
'externalId' => $discordUser->getId(),
'externalIdSource' => 'discord',
]
);
if ($existingUser) {
return $existingUser;
}
$user = $this->repository->findOneBy(['email' => $email]);
if (!$user) {
$user = new User(
$discordUser->getId(),
'discord',
$discordUser->getUsername(),
$discordUser->getEmail()
);
$user->setExternalId($discordUser->getId());
$user->setExternalIdSource('discord');
$user->setToken($credentials->getToken());
$user->setRefreshToken($credentials->getRefreshToken());
$user->setTokenExpiresFromTimestamp($credentials->getExpires());
}
$this->repository->persist($user);
return $user;
} catch (\Throwable $e) {
throw new AuthenticationException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* #inheritDoc
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response
{
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
return new Response($message, Response::HTTP_FORBIDDEN);
}
/**
* #inheritDoc
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): Response
{
$targetUrl = $this->router->generate('home');
return new RedirectResponse($targetUrl);
}
/**
* #return \KnpU\OAuth2ClientBundle\Client\OAuth2Client
*/
private function getDiscordClient(): OAuth2Client
{
return $this->clientRegistry
->getClient('discord');
}
}
<?php
namespace App\Security;
use App\Entity\User;
use App\Repository\UserRepository;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserProvider implements UserProviderInterface
{
/**
* #var \App\Repository\UserRepository
*/
private $repository;
/**
* UserProvider constructor.
*
* #param \App\Repository\UserRepository $repository
*/
public function __construct(UserRepository $repository)
{
$this->repository = $repository;
}
/**
* #inheritDoc
*/
public function loadUserByUsername($username): UserInterface
{
$user = $this->repository->findOneBy(['email' => $username]);
if (!$user) {
throw new UsernameNotFoundException(sprintf('No User with username %s found', $username));
}
return $user;
}
/**
* #inheritDoc
*/
public function refreshUser(UserInterface $user): UserInterface
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
// TODO find out how to use the refresh token to get a new one
return $user;
}
/**
* #inheritDoc
*/
public function supportsClass($class): bool
{
return $class === User::class;
}
}
security:
providers:
user_provider:
entity:
class: App:User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
logout:
path: /logout
target: /login
guard:
authenticators:
- App\Security\DiscordAuthenticator
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityManager;
/**
* Class UserRepository
*/
class UserRepository
{
/**
* #var \Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* #var \Doctrine\ORM\EntityRepository
*/
private $repository;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
$this->repository = $entityManager->getRepository(User::class);
}
/**
* Finds an entity by its primary key / identifier.
*
* #param int $id
*
* #return \App\Entity\User|null
*/
public function find(int $id): ?User
{
return $this->repository->find($id);
}
/**
* Finds all entities in the repository.
*
* #return \App\Entity\User[]
*/
public function findAll(): iterable
{
return $this->repository->findAll();
}
/**
* Finds entities by a set of criteria.
*
* #param array $criteria
* #param array|null $orderBy
* #param int|null $limit
* #param int|null $offset
*
* #return \App\Entity\User[]
*/
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): iterable
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
/**
* Finds a single entity by a set of criteria.
*
* #param array $criteria
* #param array|null $orderBy
*
* #return \App\Entity\User|null
*/
public function findOneBy(array $criteria, array $orderBy = null): ?User
{
return $this->repository->findOneBy($criteria, $orderBy);
}
/**
* Counts entities by a set of criteria.
*
* #param array $criteria
*
* #return int
*/
public function count(array $criteria): int
{
return $this->repository->count($criteria);
}
/**
* Select all elements from a selectable that match the expression and
* return a new collection containing these elements.
*
* #param \Doctrine\Common\Collections\Criteria $criteria
*
* #return \App\Entity\User[]
*/
public function matching(Criteria $criteria): iterable
{
return $this->repository->matching($criteria);
}
/**
* #param \App\Entity\User $user
*
* #throws \Doctrine\ORM\ORMException
* #throws \Doctrine\ORM\OptimisticLockException
*/
public function persist(User $user): void
{
$this->entityManager->merge($user);
$this->entityManager->flush();
}
}
<?php
namespace App\Controller;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route(path="discord/")
*/
class DiscordOAuthController extends AbstractController
{
/**
* #var \KnpU\OAuth2ClientBundle\Client\ClientRegistry
*/
private $clientRegistry;
/**
* DiscordOAuthController constructor.
*
* #param \KnpU\OAuth2ClientBundle\Client\ClientRegistry $clientRegistry
*/
public function __construct(ClientRegistry $clientRegistry)
{
$this->clientRegistry = $clientRegistry;
}
/**
* #Route(name="discord_redirect_authorization", path="redirect_authorization")
*
* #return \Symfony\Component\HttpFoundation\Response
*/
public function redirectAuthorizationAction(): Response
{
return $this->clientRegistry->getClient('discord')
->redirect(['identify', 'email', 'guilds']);
}
/**
* #Route(name="discord_set_token", path="set_token")
*
* #return void
*/
public function setTokenAction(): void
{
// empty as authenticator will handle the request
}
}
At the time I was working on this I didn't had much time and only briefly looked into the documentation.
Now I have had more time and put some time into reading the whole documentation of Discords oAuth.
I then found the query param prompt which when set to none will only once request the authorisation and otherwise will directly redirect to the redirect_uri

Swagger ui endpoints are duplicated

I am using the wonderful project api platform. I create my entities and endpoints are working like a charm.
Right now, I want to configure the documentation because endpoints are showed duplicated. For example, I have a relation 1 to N between two entities and on documentation which is automatically generated via swagger the endpoints are duplicated.
For example, in this relation between competition and event, I have the same endpoint [/competitions/{id}/events] for each entity.
Do you know if is there any way to show endpoints once? It is not a big deal, but I want to keep the documentation as clean as possible.
Edited
Competition:
/**
* Competitions able to request.
*
* #ApiResource(
* attributes={
* "normalization_context"={"groups"={"read"}}
* },
* collectionOperations={"get", "post"},
* itemOperations={"get"}
* )
* #ORM\Entity
*/
class Competition
{
/**
* #var int The competition Id
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read","write"})
*/
private $id;
/**
* #var string Name of the competition
*
* #ORM\Column
* #Assert\NotBlank
* #Groups({"read","write"})
*
*/
public $name = '';
/**
* #ORM\OneToMany(targetEntity="Event", mappedBy="competitions", cascade={"persist"})
* #ApiSubresource(maxDepth=1)
* #Groups("write")
*/
public $events;
Event:
/**
* Available event
*
* #ApiResource(
* attributes={
* "normalization_context"={"groups"={"read"}},
* "denormalization_context"={"groups"={"write"}}
* },
* collectionOperations={"get", "post"},
* itemOperations={
* "get"}
* )
* #ORM\Entity
*/
class Event
{
/**
* #var int The entity Id
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read", "write"})
*/
private $id;
/**
* #var string The name of the event available.
*
* #ORM\Column(type="text")
* #Assert\NotBlank
* #Groups({"read","write"})
*/
public $name = '';
/**
* #var string Start date
*
* #ORM\Column(type="datetime")
* #Assert\NotBlank
* #Groups({"read","write"})
*/
public $start;
/**
* #ORM\ManyToOne(targetEntity="Competition", inversedBy="events")
* #Groups({"write"})
*/
public $competitions;
You could be able to disable some "operations":
https://api-platform.com/docs/core/operations
<?php
// api/src/Entity/Book.php
use ApiPlatform\Core\Annotation\ApiResource;
/**
* ...
* #ApiResource(
* collectionOperations={"get"},
* itemOperations={"get"}
* )
*/
class Book
{
// ...
}
To hide/show what you want.

How to access properties of node over 2 relations with NEO4J-PHP-OGM

I cant get my head around how to access properties over 2 relationships with the neo4j-php-ogm library.
Say for example I have a "user" node, which connects to MANY "resource" nodes, which in return are each connected to a fixed number of predefined "MetaResource" node. The "resource" nodes have properties and the "MetaResource" nodes have the Meta-Properties of each resource type. How can I know access the properties of the "MetaResource" nodes starting from a "user" node? In Neo4j one such route looks like this:
(user)-[r:HAS_RESOURCE]->(resource)-[m:METARESOURCE]->(metaResource)
My example user entity:
/**
* #OGM\Node(label="User")
*/
class User
{
/**
* #OGM\GraphId()
* #var int
*/
private $id;
/**
* #OGM\Relationship(type="HAS_RESOURCE", direction="OUTGOING", targetEntity="\AppBundle\Entity\Resources", collection=true)
* #var ArrayCollection|\AppBundle\Entity\Resources[]
*/
protected $resources;
/**
* #return \Doctrine\Common\Collections\ArrayCollection|\AppBundle\Entity\Resources[]
*/
public function getResources()
{
return $this->resources;
}
/**
* #return \Doctrine\Common\Collections\ArrayCollection|\AppBundle\Entity\Resources[]
*/
public function getResource($name)
{
foreach($this->resources as $resource){
if($resource->getResourceType() == $name){
return $resource;
break;
}
}
}
/**
* #param AppBundle\Entity\Resources $resources
*/
public function addResource(Resources $resources)
{
if (!$this->resources->contains($resources)) {
$this->resources->add($resources);
}
}
}
My Example Resource Entity:
/**
* #OGM\Node(label="Resources")
*/
class Resources
{
/**
* #OGM\GraphId()
* #var int
*/
protected $id;
/**
* #OGM\Property(type="int")
* #var int
*/
protected $resourcecount;
/**
* #OGM\Relationship(type="METARESOURCE", direction="OUTGOING", targetEntity="\AppBundle\Entity\MetaResource", collection=false)
* #var MetaResource
*/
protected $metaResource;
/**
* #param \AppBundle\Entity\MetaResource $metaResource
*/
public function __construct(MetaResource $metaResource)
{
$this->metaResource = $metaResource;
}
public function getId()
{
return $this->id;
}
public function getResourceCount()
{
return $this->resourcecount;
}
public function setResourceCount($resourcecount)
{
$this->resourcecount = $resourcecount;
}
/**
* #return \AppBundle\Entity\MetaResource
*/
public function getMetaResource()
{
return $this->metaResource;
}
}
And my Example MetaResource Entity:
/**
* #OGM\Node(label="MetaResource")
*/
class MetaResource
{
/**
* #OGM\GraphId()
* #var int
*/
protected $id;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $resourceType;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $name_DE;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $icon;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $iconColour;
/**
* #OGM\Property(type="string")
* #var string
*/
protected $colour;
public function getResourceType()
{
return $this->resourceType;
}
public function getName_DE()
{
return $this->name_DE;
}
public function getIcon()
{
return $this->icon;
}
public function getIconColour()
{
return $this->iconColour;
}
public function getColour()
{
return $this->colour;
}
}
And finally the code from my controller, which sets up the relations:
$metaResource=$em->getRepository(MetaResource::class)->findOneBy('resourceType', 'wood');
$rWood = new Resources($metaResource);
$rWood->setResourceCount(20);
$em->persist($rWood);
$em->flush();
$user->addResource($rWood);
If I now have a look at the Neo4j webconsole, all relationships and nodes are correctly inserted.
Now, if I get the resources of a user with $user->getResources() I successfully get all the resource objects, but the "$metaResource" property is always NULL instead of the anticipated Object of my MetaResource entity. For example if I do:
foreach($user->getResources() as $resource){
var_dump($resource->getMetaResource());
}
Then it outputs only NULLs.
On the other hand, if I directly get a resource object (for example with $resource = $em->getRepository(Resources::class)->findOneById(123) ) and then try to get the connected MetaResource with $resource->getMetaResource() it works. What am I missing?
Cheers
I have made some progress regarding this use case. I'm using now a proxy generator that can handle this use case (this was a big missing part into the lib actually but takes time to implement).
So please test with the latest release 1.0.0-beta7.

2 How to join two entities in my project

I have a relation one-to-many between project and images and many-to-one between project and propriety. I would to select the procts ho have image.cover=1 and propriety.activated=1 but the code always give me all images for projects
class ProjectImage
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Project", inversedBy="images")
* #ORM\JoinColumn(nullable=false, name="id_project", referencedColumnName="id")
*/
private $idProject;
******************
class Project
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Promoteur", inversedBy="projects")
* #ORM\JoinColumn(nullable=false, name="id_promoteur", referencedColumnName="id")
*/
private $idPromoteur;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Governorate")
* #ORM\JoinColumn(nullable=false, name="id_governorate")
*/
private $idGovernorate;
/**
*
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Delegation")
* #ORM\JoinColumn(nullable=true, name="id_delegation")
*/
private $idDelegation;
/**
* #ORM\ManyToOne(targetEntity="BI\AdminBundle\Entity\Locality")
* #ORM\JoinColumn(nullable=true, name="id_locality")
*/
private $idLocality;
/**
* #ORM\OneToMany(targetEntity="BI\AdminBundle\Entity\ProjectImage", mappedBy="idProject",cascade={"persist", "remove", "merge"})
*/
private $images;
**********************************
class Promoteur
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity = "BI\AdminBundle\Entity\Project", mappedBy = "idPromoteur")
*/
private $projects;
On your OneToMany associations, you should use an ArrayCollection since you store can several instances of your target entity on this end. You should also import the ArrayCollection class and instanciate this collection in your constructor.
So in your Project class you may want to add something like this:
use Doctrine\Common\Collections\ArrayCollection;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="BI\AdminBundle\Entity\ProjectImage",
mappedBy="idProject",cascade={"persist", "remove", "merge"})
*/
private $images;
public function __construct() {
$this->images = new ArrayCollection();
}
Then you can generate the getters and setters with app/console doctrine:generate:entities. This command will also create two additional methods addImage and removeImage to manage your collection.
Hope this will helps

Doctrine2 - what DQL to use?

The first entity called BUNDLE
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Course\Course
* #ManyToMany(targetEntity="Akademie\Course\Course", mappedBy="bundles")
*/
private $courses;
The second entity is called COURSE
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Bundle\Bundle
* #ManyToMany(targetEntity="Akademie\Bundle\Bundle", inversedBy="courses")
*/
private $bundles;
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Course\CourseDate
* #OneToMany(targetEntity="Akademie\Course\CourseDate", mappedBy="course")
*/
private $courseDates;
/**
* #var int
* #Column(type="boolean")
*/
private $hidden;
and the third is called COURSEDATE
/**
* #var \Akademie\Course\Course
* #ManyToOne(targetEntity="Akademie\Course\Course", inversedBy="courseDates")
* #JoinColumn(nullable=false)
*/
private $course;
/**
* #var \DateTime
* #Column(type="datetimetz", nullable=true)
*/
private $beginDate;
I have parameter course and I need to get all bundles, which contains this course. What's more, all other courses in that bundle has to have courseDate newer than current date and can't be hidden. Otherwise I don't want to get this bundle. I hope it is clear now...
In a repository (bundle of entity BUNDLE for example), you have to create a custom method :
public function myMethod($course){
$qb = $this->createQueryBuilder("b")
->join("b.course", "c")
->join("c.courseDates", "cd")
->Where("c = :course")
->andWhere(" cd.beginDate > :now ")
->andWhere("c.hidden = 1")// if 1 means not hidden
->setParameter(":course", $course)
->setParameter(":now", new \DateTime('now'));
And then, in your controller, you have to do something like that :
$bundles = $this->getDoctrine()->getManager()->getRepository('namespace of your BUNDLE entity')->myMethod($course);

Resources