Symfony/SonataAdmin Show fields from two entities - symfony

I have two entities :
User that contains login data (with FOSUser),
and other informations about them (name, first name, date of birth, etc) in another entity called UserInfo.
In SonataAdmin, I want to manage my Users (done) but I need to add fields in the table that are in UserInfo (name, first name...).
Any idea ?
Thanks !

Depending on the relationship type, you should be able to just reference userinfo.firstName, eg:
public function configureShowFields(ShowMapper $show)
{
$show->add('userinfo.firstName')
->add('userinfo.dob');
}
Of course, if you have many userinfo's attached to the entity I don't think this will work.

There must be existing a relation in between user and userInfo. say OneToOne relation. Then from userInfo entity u will get the user data and will show on the Admin side.
i.e.
$subject = $this->getSubject();
$user = $this->subject->getUser();
Will give you user, if you want to further perform actions on that user.

Related

Entity data in crudcontroller based on current logged in user or user id

I'm new to Symfony and I've already learned a lot, but now I run into a problem that I can't find the answer to.
I have a crudcontroller which uses the entity (e.g.) Articles, but the articles in the database have different user ids.
The crudcontroler MUST only show the articles of the current logged in user/user id. I know how to get the user id, but I don't know how to manipulate the entity to ONLY get the articles for the specific user to display in the crudcontroller.
Example:
User with user id 5 is logged in the dashboard. Get articles where user id is 5 in crudcontroller ONLY. Do not get or display any other.
Symfony version: 5.2
Easyadmin: 3.2
I hope someone can push me in the right direction. Currently pulling my hair out on this one. Nothing to be found on Google on this subject.
EDIT:
I've finally found the way to have more control with the createIndexQueryBuilder().
I've overridden that one with:
public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
$response = parent::createIndexQueryBuilder($searchDto,$entityDto,$fields,$filters);
$response->where('entity.user_id = 5);
return $response;
}
BUT then I get this error:
[Semantical Error] line 0, col 65 near 'user_id = 5': Error: Class App\Entity\RepairServices has no field or association named user_id
That's right because user_id isn't part of the entity BUT it is in the database and I need to check on it. How can I do that?

Symfony - Read-only entities hydrated from YAML

Is it possible to have simple read-only entities, that can have an association with an other doctrine entity, but their data is stored in a text ( YAML ) file ?
Let's say I have a product entity, and I want to set a category for each product. But for now, I only have very few categories ( and don't need to edit or add ), so I don't want/need to create a full doctrine entity with it's own table in the DB.
So I create a very simple entity:
class ProductCategory
{
private $id;
private $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
}
Now I would like to create a simple YAML file where the data is stored, like so:
0: Cheese
1: Meat
2: Dairy Products
....
Then I would like to set a ManyToOne relation from the product entity to the ProductCategory entity.
Is that possible ?
And, how to "query" the categories ? ( let's say I want to list all categories that start with a certain letter )
'Why' you ask ?
Well for now, as I said, I only have very few categories, but maybe some day I want to add many more, and even have a CRUD editor for them and so on, then I could easily convert it to a full doctrine entity.
Or any other suggestions on how to approach this ?
There is already a library that provides what you are looking for that's called Alice:
https://github.com/nelmio/alice
https://github.com/hautelook/AliceBundle
https://github.com/fzaninotto/Faker
https://github.com/h4cc/AliceFixturesBundle
This way you can create random test data en masse and can still work with Doctrine as usual.
If you want to do this manually it will be a pain to solve the problem of connecting the entities. Your best bet is to keep all of them in arrays with id's being used as keys but even then you will probably end up writing lots of glue code to connect the entities.

Laravel 5.3 Save related model with array

I have a User model and Event model.
A User can have/create many Events
An Event belongs to User.
I have made this form just for demo:
And i get this output when i dd($request);
How to save this in my database table events.
These array fields are problem...do i need to make some new table except users and events??
Yes, it looks like you need another table. I've just taken an educated guess at the table names because I'm not 100% sure what these times and professions refer to, it looks like you already have a table storing the professions, but here are the relationships I can see:
A user can have many events
An event belongs to a user
An event has many timeslots
A timeslot belongs to an event
A profession has many timeslots
A timeslot has many professions
So your events and professions (don't worry if you've called it something else) table should look like:
events(id, user_id, name, start, end);
professions(id, profession,..);
And you need to add an extra table:
time_slots(id, event_id, profession_id, amount, from, to, hours)
Then set those relationships up inside your models.
EDIT
The basic way to make a store method is to use the relationships like so:
public function store(Request $request){
// Get the request as an array
$request = $request->all();
// create a new event
$event = Event::create($request);
// Map timeslots to an array of Timeslot objects:
$timeslots = array_map(function($personalId, $amount, $from, $to, $hours) {
return new App\Timeslot($personalId, $amount, $from, $to, $hours);
}, $request['personal_id'], $request['amount'], $request['from'], $request['to'], $request['hours']);
// Save all timeslots for the event
$event->timeslots()->saveMany($timeslots)
}
I haven't tried that code, but it should point you inb the right direction. You should take a look at laravel relationships to see how this works:
https://laravel.com/docs/5.3/eloquent-relationships#the-save-method

Doctrine 2, prevent getting unjoined entities

given a user and his coupons, I want to get a user and all of his coupons:
foreach ($this->createQueryBuilder('x')->select('u, c')->where('x.email = ?0')->setParameter(0, $email)->leftJoin('u.coupons', 'c')->getQuery()->getResult() as $entity)
{
$entity->getCoupons();
}
this is very good until I forget to join the coupons:
foreach ($this->createQueryBuilder('x')->select('u')->where('x.email = ?0')->setParameter(0, $email)->getQuery()->getResult() as $entity)
{
$entity->getCoupons();
}
sadly this still works even though no coupons were joined. Here it does an other SELECT. In additional, this 2nd select will be wrong. Id rather want to get a exception or AT LEAST an empty array instead. Is there any workaround for this?
What you're experiencing is expected doctrine behavior.
When you select a User entity, Doctrine will get the record from the database. If you aren't explicitly joining the Coupon entity (or any other entities with relationship to User), Doctrine will create a Proxy object. Once you access this proxy object by calling $user->getCoupons(), Doctrine will fire a new query to the database to get the coupons for your User entity. This is called lazy-loading.
I'm not sure if there is a way to change this in the way you described.
What you can do is to create a method in your UserRepository called findUserAndCoupons($email) and have your query there. Whenever you need to find a user and his coupons, you could simply retrieve it in your controller using:
class MyController extends Controller {
public function myAction(){
$user = $this->getDoctrine()->getRepository('UserRepository')->findUserAndCoupons($email);
foreach($user->getCoupons() as $coupon) {
// ....
}
}
}
This way you won't need to remember the actual query and copy/paste it all over the place. :)

How to make work soft deletable and unique entity using symfony 2

I've soft deletable and a uniqueentity field. It works great but...
If the record is deleted "softdeleted", I can't create the same record. I think it's because the record is not realy deleted in the DB. But I need to that.
So what is the best way to dothis ?
Totaly deleted the record ? So is softdeletable a good choice ?
Find a way that if the record is softdeleted, I can create again the same record
Thanks for your advices
After you removed the unique constraint from the database level, You can set to your entity this.
#UniqueEntity(fields={"name", "deleteTime"}, ignoreNull=false)
In this case the validation will fail if you already have a "non-soft deleted" row with the given name in your database, but it won't if the deleteTime is setted.
since you are using soft delete and unique constraints, you can't actually use a unique constraint on the database level.
I suggest you handle the unique constraint check manually, this could be done in a doctrine life cycle event
One way to do this is by creating a callback function in your entity and annotate it to fire on the event:
/** #PrePersist */
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
// check if this entity's unique field is OK
}
This will only ensure you don't save anything incorrect in the database, but it won't handle your forms nicely. So in addition, you probably want to use the UniqueEntity validator for this, and create a custom repositoryMethod to check the uniqueness.
This custom repository method can be used by both the prePersist and the UniqueEntity validator.
You have three choices
Hard Delete the item
Remove the Unique (and handle it in doctrine)
When you create the new entity, you deactivate the softdeletable filter
$em->getFilters()->disable('soft-deleteable');
This will let you find the "deleted" items. Then you can do things like overwrite the old entry, harddelete it manually or whatever your app needs you to do with it.
In my case, I used this way
Remove the unique index of the column on the Database
public function up(Schema $schema) : void
{
$this->addSql('DROP INDEX UNIQ_A2E0150FE7927C74 ON admins');
$this->addSql('CREATE UNIQUE INDEX UNIQ_A2E0150FE7927333 ON
admins (email,deleted_at)');
}
Add this constraint on your Entity
/**
* #ORM\Entity(repositoryClass=AdminRepository::class)
* #ORM\Table(name="admins",
* uniqueConstraints={
* #UniqueConstraint(name="admins",
* columns={"email", "deleted_at"})
* })
It means that you make the pair email (unique column) and deleted_at unique, instead of just the email field. And now, I can create another admin with the same email, if the old one was deleted (Using soft delete)

Resources