How to expose different GET routes for the same entity - api-platform.com

I'm using Symfony for the backend and API-Platform. I have an entity User like this :
* #ORM\Entity(repositoryClass=UserRepository::class)
* #ORM\Table(name="`user`")
*/
#[ApiResource(
itemOperations: [
'get' => [
'normalization_context' => ['groups' => ['user:read']],
],
],
)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
#[Groups(['user:read'])]
private string $email;
/**
* #ORM\Column(type="string", length=255)
*/
#[Groups(['user:read'])]
private string $firstname;
/**
* #ORM\Column(type="string", length=255)
*/
#[Groups(['user:read'])]
private string $lastname;
/**
* #ORM\OneToMany(targetEntity=Project::class, mappedBy="user", orphanRemoval=true)
*/
#[Groups(['user:read'])]
private Collection $foo;
/**
* #ORM\OneToOne(targetEntity=MediaObject::class, cascade={"persist", "remove"})
*/
#[ApiProperty(iri: 'http://schema.org/image')]
#[Groups(['user:read'])]
private ?MediaObject $picture1;
/**
* #ORM\OneToOne(targetEntity=MediaObject::class, cascade={"persist", "remove"})
*/
#[ApiProperty(iri: 'http://schema.org/image')]
#[Groups(['user:read'])]
private ?MediaObject $picture2;
}
For the moment, I have one GET route for an item : /api/users/{id}
I would like to have 3 GET routes for an item :
/api/users/{id}/data where I would have email, firstname and lastname
/api/users/{id}/foo where I would have foo
/api/users/{id}/pictures
where I would have picture1 and picture2
Is it possible and if so, how could this be done ?

Everything is explained here.
You have to do something like that:
#[ApiResource(
itemOperations: [
'get' => [
'normalization_context' => ['groups' => ['user:read']],
],
'get_data' => [
'method' => 'get',
'path' => '/api/users/{id}/data',
'normalization_context' => [
'user:read:data'
]
],
],
)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
// ...
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
#[Groups(['user:read', 'user:read:data'])]
private string $email;
// ...

Related

symfony embed Ajax field in form

In symfony I have a Cliente entity that can have N Reservas:
class Cliente {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Reserva", mappedBy="cliente")
*
*/
private $reservas;
....
}
class Reserva
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Cliente", inversedBy="reservas")
*
*/
private $cliente;
...}
In the ReservaType I have:
class ReservaType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('cliente')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'partes\EscuelaBundle\Entity\Reserva'
));
}
/**
* #return string
*/
public function getName() {
return 'partes_escuelabundle_reserva';
}
}
All that when I create a new reserva show my the typical select option with the list of all customers. I would change that for a ajax input type to select the customer. Any idea how to build it.
Thanks you!
fix it, with a ajax call that bring a list of links. Once clicking in the link it creates the new Reserva.

Doctrine in laravel, getting all user's roles

I have a simple project in laravel 5.4 with Doctrine 2.0. I have three tables: users, roles, user_roles. Screenshot from tables schemas from HEIDISQL I show below:
users:
roles:
user_roles:
I have three Entities classes for each table of course:
<?php
namespace TodoList\Http\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*
*/
private $id;
/**
*
* #ORM\Column(type="string")
*
*/
private $name;
/**
*
* #ORM\Column(type="string")
*
*/
private $email;
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="user", cascade={"persist"})
* #var ArrayCollection|Task[]
*/
private $tasks;
/**
* #ORM\OneToMany(targetEntity="UserRole", mappedBy="user")
*/
protected $user_roles;
/**
* User constructor
* #param #name
* #param #email
* #param $password
*/
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
$this->tasks = new ArrayCollection();
$this->user_roles = new ArrayCollection();
}
/**
*
* #return mixed
*
*
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getEmail()
{
return $this->email;
}
/**
* #return mixed
*/
public function getTasks()
{
return $this->tasks;
}
public function addTask(Task $task)
{
if(!$this->tasks->contains($task)) {
$task->setUser($this);
$this->tasks->add($task);
}
}
public function getId(){
return $this->id;
}
public function getUserRoles(){
return $this->user_roles;
}
}
<?php
namespace TodoList\Http\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="roles")
*
*/
class Role{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string")
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* #ORM\OneToMany(targetEntity="UserRole", mappedBy="role",cascade={"persist"})
*/
protected $user_roles;
public function getId(){
return $this->id;
}
public function getName(){
return $this->name;
}
public function getDescription(){
return $this->description;
}
}
<?php
namespace TodoList\Http\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="user_roles")
*/
class UserRole
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="user_roles")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
*/
private $user;
/**
*
* #ORM\ManyToOne(targetEntity="Role", inversedBy="user_roles")
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
*/
private $role;
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \NVC\UserBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set recipe
*
* #param \NVC\RecipeBundle\Entity\Recipe $recipe
* #return UserRecipeAssociation
*/
public function setRole(Role $role)
{
$this->role = $role;
return $this;
}
/**
* Get recipe
*
* #return \NVC\RecipeBundle\Entity\Recipe
*/
public function getRole()
{
return $this->role;
}
}
I have a problem when I'm trying retrieve roles of particular user by doctrine Entity Managar. I'm trying to do that in that way:
public function showUserRoles(EntityManagerInterface $em){
$userRoles = $em->getRepository('\TodoList\Http\Entities\UserRole');
$userRoles->findBy(['user' => 2]);
//count($userRole);
}
There is an error from method findBy
Error message is:
(1/1) FatalErrorException
Doctrine\Common\Proxy\AbstractProxyFactory::getProxyDefinition():
Failed opening required
'C:\xampp\htdocs\Project\storage\proxies__CG__TodoListHttpEntitiesRole.php'
(include_path='C:\xampp\php\PEAR')
Is anything wrong with my Entities? I don't know how could I solve that problem. Could someone help me with that?
I would be very greateful
Best regards ;)
You need to set folder C:\xampp\htdocs\Project\storage\proxies\ as writable and then you need to generate proxies by console command:
doctrine:generate:proxies

Error While Creating the schema for doctroin

I have tried to create the database schema by running the artisan command through CLI and got the following error:
The annotation "#Doctrine\ORM\Mapping\Names" in property App\Entity\Vouchers::$names does not exist, or could not be auto-loaded.
Following the Code for my Entity.
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="vouchers")
**/
class Vouchers
{
/**
* #var integer $id
* #ORM\Column(name="id", type="integer", unique=true, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #var string $names
* #ORM\Column(name="names", type="string", unique=false, nullable=false)
* #ORM\Names
*
*/
private $names;
/**
* #var string $amount
* #ORM\Column(name="amount", type="string", unique=false, nullable=false)
* #ORM\Amount
*
*/
private $amount;
//Getter And Setters
//ID
public function getId()
{
return $this->id;
}
//name
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
//amount
public function getAmount()
{
return $this->amount;
}
public function setAmount($amount)
{
$this->amount = $amount;
}
}
Please check and let me know if there is any mistake i have made in the above code and how it can be fixed. I have tried many other solution but still i am not able to figure this out.
Fixed it by replacing the name section with the following
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=150, nullable=false)
*/
private $name;

symfony 2 formbuilder entity error validation

I build a form with
$form = $this->createFormBuilder($user)
->add('locations', 'entity', array('class' =>'PrUserBundle:Location',
'property' => 'name',
'query_builder' => function(\Doctrine\ORM\EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.client_id = :client_id')
->setParameter('client_id', $this->clientId)
->orderBy('u.name', 'ASC');
},'required' => true, 'multiple' => true, 'expanded' => true)
)
After submitting,I would like to validate the form. This is done by a validation.yml
Pr\UserBundle\Entity\User:
properties:
usergroups:
- NotBlank: ~
message: You must select a location
I only get a error
Unable to parse at line 15 (near " message: You must select a location").
EDIT: This has been fixe for removing the ~ tilde like Rooneyl already told me (see comment)
How can I implement the validation of this field inside the form?
EDIT: It's a bit more complicativ I guess.
There are two entities. User and e.g. Location.
The User entity contains
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $client;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $client_id;
/**
* #ORM\Column(type="string", length=16383, nullable=true) //16383 = max varchar utf8
*/
private $imageurl;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $firstname;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $lastname;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $emailalert;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $phone;
/**
* #ORM\Column(type="integer", nullable = true)
*/
protected $lock_state;
/**
* #ORM\Column(type="array", nullable=true)
*/
private $locations;
/**
* #ORM\Column(type="array", nullable=true)
*/
private $usergroups;
/**
* #ORM\Column(type="string", length=5, options={"fixed" = true, "default" = "de_DE"})
*/
private $locale = 'de_DE';
/**
* #ORM\Column(type="string", length=32)
*/
private $timezone = 'UTC';
/**
* #ORM\Column(type="array", nullable=true)
*/
private $created='1';
For all those fields, I can get a validation. But for the field "locations" I dont get a validation. This will be data from the entity "Location" like you can see below:
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="string", length=20)
*/
public $name; //Raumbezeichnung, Ausgabelinie-Bezeichnung, Freitextbezeichnung, Standortname
/**
* #ORM\Column(type="integer")
*/
public $type;
/**
* #ORM\Column(type="string", length=20)
*/
public $parentLocation;
/**
* #ORM\Column(type="integer", nullable=true)
*/
public $parentlocation_id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
public $client;
/**
* #ORM\Column(type="integer")
*/
public $client_id;
I dont know if I can display this by a many2many connect in the entity, but actually I used to go the way I discribed above (I'm a noob in symfony until now).
I just want to force admins, to setup usergroups for each user at its beeing created within the form.
This will work:
Pr\UserBundle\Entity\User:
properties:
locations:
- NotBlank:
message: { "You must select a location" }

Problem making sense of doctrine 2

I'm having a hard time figuring out how to properly use Doctrine 2 with zend framework. I'm reading the docs and basing what I've done so far on that and the zendcasts. The problems actually start when I try to do relational stuff with my db, since I'm not so sure how to use doctrine collections. In my test case, I have an User entity:
class User
{
/**
* #var integer
* #Column (name="id", type="integer", nullable=false)
* #Id
* #GenerateValue(strategy="IDENTIY")
*
*/
private $id;
/**
* #Column(type="string",length=60,nullable=true)
* #var string
*/
private $email;
/**
*
* #param \Doctring\Common\Collections\Collection $property
* #OneToMany(targetEntity="Countries",mappedBy="user", cascade={"persist", "remove"})
*/
private $countries;
public function __get($property)
{
return $this->$property;
}
public function __set($property, $value)
{
$this->$property = $value;
}
}
Which is related to the countries entity:
class Countries {
/**
* #var integer
* #Column (name="id", type="integer", nullable=false)
* #Id
* #GenerateValue(strategy="IDENTIY")
*
*/
private $id;
/**
*
* #var string
* #Column(type="string")
*/
private $countryName;
/**
*
* #var User
* #ManyToOne(targetEntity="User")
* #JoinColumns({
* #JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $user;
public function __get($property)
{
return $this->$property;
}
public function __set($property, $value)
{
$this->$property = $value;
}
}
Now I can assign the countries from the controller with something like this:
$p1 = new \Federico\Entity\Countries();
$p1->countryName = 'Argentina';
$p2 = new \Federico\Entity\Countries();
$p2->countryName = 'España';
$u = new \Federico\Entity\User();
$u->firstname = 'John';
$u->lastname = 'Doe';
$u->id = 1;
which would show me this object:
object(Federico\Entity\User)[109]
private 'id' => int 1
private 'email' => null
private 'countries' =>
array
0 =>
object(Federico\Entity\Countries)[107]
private 'id' => null
private 'countryName' => string 'Argentina' (length=9)
private 'user' => null
1 =>
object(Federico\Entity\Countries)[108]
private 'id' => null
private 'countryName' => string 'España' (length=7)
private 'user' => null
public 'firstname' => string 'John' (length=4)
public 'lastname' => string 'Doe' (length=3)
If you pay attention to this, you'll see that the user property is set to null in the country objects. I don't understand if this is supposed to happen like this or not. Also, since users will be allowed to choose the countries from a checkbox list, and they'll be able to choose more than one country,...shouldn't the countries somehow be stored in the Db?
I don't see where you assign country to a user in your code. Anyway, you need to do two things:
Initialize $countries variable as a new Doctrine\Common\Collections\ArrayCollection in User constructor.
Manually connect country with user:
public function addCountry(Country $c)
{
if (!$this->countries->contains($c)) {
$this->countries->add($c);
$c->user = $user;
}
}
In doctrine 2 the use of the magic getters and setters is discouraged. As you can see they can cause problems for managing associations. Below is an example of how to manage the association that you have in your User entity.
namespace Whatever/Your/Namespace/Is;
use \Doctrine\Common\ArrayCollection;
class User
{
/**
* #Column (type="integer")
* #Id
* #var integer
*/
private $id;
/**
* #OneToMany(targetEntity="Country", mappedBy="user", cascade={"persist", "remove"})
* #var ArrayCollection
private $countries;
public function __construct()
{
$this->countries = new ArrayCollection();
}
public function getCountries()
{
return $this->countries;
}
public function setCountry(Country $country)
{
$this->country[] = $country;
$country->setUser($this);
return $this;
}
public function removeCountry(Country $country)
{
return $this->country->removeElement($country);
}
}
and for Country
class Country
{
/**
* #Id
* #Column(type="integer")
* #var integer
*/
private $id;
/**
* #Column(length=100)
* #var string
*/
private $country_name;
/**
* #ManyToOne(targetEntity="User", inversedBy="countries")
* #var User
*/
private $user;
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
public function getUser()
{
return $this->user;
}
// ...
}

Resources