API Platform - remove password hash from result - symfony

I have User entity that cointains attributes like: id, email, password...
Password attribute is a password hash, and I would like to remove it from GET result from item and collection operations.
Is there any annotation for this? ( I tried #ApiProperty (readable=false), but without success)
I suppose I can remove password from result through event subscriber but I am curious if there is any simple way how to achieve it.

Use the Groups in Entity
/**
* #ApiResource(attributes={
* "normalization_context"={"groups"={"read"}},
* "denormalization_context"={"groups"={"write"}}
* })
*/
class User {
/**
* #Groups("write")
* #ORM\Column(..........)
*/
private $password;
Doc: https://api-platform.com/docs/core/serialization#using-serialization-groups

Related

Api platform, prevent POST method when some datas are the same

I'm using symfony with API PLATFORM to create a contacts share system :
One User can share one or many contacts to one or many other users.
I created ContactShare entity :
/**
* #ApiResource()
* #ORM\Entity(repositoryClass=ContactShareRepository::class)
*/
class ContactShare
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity=Contact::class, mappedBy="contactsToShare")
*/
private $contacts;
/**
* #ORM\ManyToOne(targetEntity=AppUser::class, inversedBy="shareContactsOwner")
*/
private $sender;
/**
* #ORM\OneToMany(targetEntity=AppUser::class, mappedBy="shareContactsReceivers")
*/
private $receivers;
...
...
}
When i tested with postman i can post a new share :
My question is :
How to add constraints or validators to prevent the POST method of contact share if we
share the same contacts to the same user, and Prevent POST method if we send the same
contact to a duplicated user ?
You can create a custom validator and call valid as shown here.
If validation returns one (or more) error, you should return some kind of response with proper HTTP status code (4xx?).
Moreover, if this validation should be performed only for this API call (I think this is a domain requirement, so it should be always applyed, but it's only a guess of mine) you can take advantage of validation groups.
UPDATE: API Platform seems to take care of this on your behalf, so you don't need to call explicitly valid

Doctrine throw error: "A new entity was found through the relationship" after removing entity

Let's say I have two entities, Project and User with relation.
Project.php
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(onDelete="SET NULL")
*/
private $creator;
When I remove the User entity, the doctrine leaves the User object(without ID) in the Project entity. In a normal situation, this is fine but I am using DomainEvents. In this scenario, after removing the User entity, DomainEvent triggers saving some data in the DB and secondary saving data(after removing) throw this error. This happens because of now in the Project entity we have the detached(from the EM) User object without ID.
I thought about a listener, that will remove empty objects in the entity after removing, but I am not sure that is a good variant
What is the best variant for solving this error?
The onDelete option doesn't apply a cascade removing.
If you want to do so I think you should have to add the cascade={"remove"} option to the ManyToOne.
Try as following :
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User", cascade={"remove"})
* #ORM\JoinColumn(onDelete="SET NULL")
*/
private $creator;
Removing entity in doctrine

Symfony2 & FOSRestBundle: Getting UUID packed in a BINARY(16) field from MySQL

I am facing a weird problem relating to UUIDs.
I have developed a REST API using Symfony2+FOSRestBundle+JMSSerializer. As I need to update some tables from two sources I thought of using UUID as primary key for one entity.
I did a doctrine:mapping:import to generate entities in my Symfony project. Everything correct. I ended up with the following entity (only exposing the key field and generated getter for simplicity):
<?php
namespace Stardigita\TgaAPIBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TgaBookings
*
* #ORM\Table(name="tga_bookings", indexes={[...]})
* #ORM\Entity
*/
class TgaBookings
{
/**
* #var string
*
* #ORM\Column(name="book_cd_booking_UUID", type="blob", length=16, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $bookCdBookingUuid;
/**
* Get bookCdBookingUuid
*
* #return string
*/
public function getBookCdBookingUuid()
{
return $this->bookCdBookingUuid;
}
...
No setter was generated. I can still do it myself and I will, as I will need to know the key beforehand.
The data for this field is correctly stored in the table as a BINARY(16). When I recover the data calling the REST GET method, I get this:
[
{
"book_cd_booking_uuid": "Resource id #1244",
"book_cd_booking": 8,
....
My question is: how can I get the actual data from the field?
I suppose something has to be done in the field getter, but I tried some solutions without any success.
Thanks.
UPDATE:
I've managed to get the actual data logged, modifying the getBookCdBookingUuid method this way:
/**
* Get bookCdBookingUuid
*
* #return string
*/
public function getBookCdBookingUuid()
{
return bin2hex($this->bookCdBookingUuid);
}
and changed the type to "guid" in the property annotation:
/**
* #var string
*
* #ORM\Column(name="book_cd_booking_UUID", type="guid", length=16, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $bookCdBookingUuid;
I have represented the hex UUID correctly in the log before returning the results in the controller:
[2014-11-03 19:52:07] app.ERROR: 1046684e5f6711e4a09f00089bce936a [] []
But still getting an exception relating UTF invalid characters:
request.CRITICAL: Uncaught PHP Exception RuntimeException: "Your data could not be encoded because it contains invalid UTF8 characters." at /var/www/tga_api/vendor/jms/serializer/src/JMS/Serializer/JsonSerializationVisitor.php line 36 {"exception":"[object] (RuntimeException: Your data could not be encoded because it contains invalid UTF8 characters. at /var/www/tga_api/vendor/jms/serializer/src/JMS/Serializer/JsonSerializationVisitor.php:36)"} []
Also I got no response from the service. A 500 error is returned.
Please, I need to solve this issue. Any ideas are welcome.
Thanks.
GeneratedValue
I notice you're using the annotation #ORM\GeneratedValue(strategy="IDENTITY") for the UUID property. IDENTITY means the database should/will use auto-increments, which shouldn't be done when using UUIDs. Please change it to #ORM\GeneratedValue(strategy="NONE") or remove it completely.
Conversion
The string form of a UUID (like 01234567-89ab-cdef-0123-456789abcdef) should be converted to binary when it's persisted in the database, and converted back when fetched from the database.
The easiest way to do this is to introduce a custom type. See here for an example.
Bugs
Doctrine (even master/2.5) has some issues with using UUIDs in associations. I'm attempting to fix these issues in PR #1178.
If you need UUIDs in associations and can't wait till it's fixed, then use regular integer ids and have the UUID is a separate column.

How to define multiple many-to-one relations between two Doctrine tables?

I've got a problem with doctrine with Symfony when I try to define to relations Many-to-one between the table Challenge and User getting the next error.
Error when I try to define:
The table User has the attribute: id, challengesMaked, challengesReceived and the table Challenge has these atributes: id, idUser1, idUser2 where idUser1 I want to relation with id from User and idUser2 I want to relation with id from User too. The relation between User and Challenge are One to Many (One user can challenge to another user) and between Challenge to User are Many to One (One challenge is received only by a User)
So, how can I define this attributes in my entity to fix my bug. Right now, in my User Entity I have defined these attributes like ...
/**
* #var Challenge ArrayCollection
* #ORM\OneToMany(targetEntity="\MQL\PlayerBundle\Entity\Challenge", mappedBy="idUser1", cascade={"persist"})
*/
protected $challengesMaked;
/**
* #var Challenge ArrayCollection
* #ORM\OneToMany(targetEntity="\MQL\PlayerBundle\Entity\Challenge", mappedBy="idUser2", cascade={"persist"})
*/
protected $challengesReceived;
And in the Challenge Entity I have defined ...
/**
* #var User ArrayCollection
* #ORM\ManyToOne(targetEntity="\FOS\UserBundle\Entity\User", inversedBy="challengesMaked")
**/
protected $idUser1; //Challenger
/**
* #var User ArrayCollection
* #ORM\ManyToOne(targetEntity="\FOS\UserBundle\Entity\User", inversedBy="challengesReceived")
**/
protected $idUser2; //Challenged
What am I doing wrong?

using of unique constraint making the user unable to login in symfony2

I have used an unique constraint for the username in the registration form of the user.
User entity has following code
/*
* #UniqueEntity(fields="username",message="Username is already in use")
*/
class users
{
/**
* #var string
* #Assert\NotBlank(message="username should not be blank")
* #ORM\Column(name="username", type="string", length=40)
*
*/
private $username;
/**
* #var string
* #Assert\NotBlank(message="password should not be blank")
* #ORM\Column(name="password", type="string", length=40)
*/
private $password;
}
For registration every thing went fine with this entity when comes to login it is showing error username already in use. Can we keep the unique constraint within controller i.e within form.so that only for registration form uniqueness is applied.
Use validation groups:
http://symfony.com/doc/2.1/book/validation.html#validation-groups
(when you follow the link - you'll see very similar case: user and registration)
edit:
I assume that you have an "user_type" field in your user entity (for example possible values could be: "normal_user" and "affiliate"). If so, then you just need specify these two fields combination as a unique. Like this:
#UniqueEntity(fields={"username", "user_type"},message="Username is already in use") */

Resources