hydrating multiple objects from fieldsets ZF2 - php

I have a problem with hydrating the objects in ZF2.
I have a form for saving either the organization-related info or person-related info into the database. The user makes the choice: save either organization or person. Just 1 form for all html inputs.
In ZF2, I created 2 fieldsets. In each fieldset class, I use setHydrator(new ClassMethods(false)) and setObject(new <objectForHydration>). The 2 fieldsets are included into the form with the following code:
$this->add([
'type' => 'Parties\Form\Fieldsets\RegisterOrganizationFieldset',
'options' => [
'use_as_base_fieldset' => true,
],
]);
$this->add([
'type' => 'Parties\Form\Fieldsets\RegisterPersonFieldset',
'options' => [
'use_as_base_fieldset' => true,
],
]);
I want RegisterOrganizationFieldset to hydrate OrganizationObject, and RegisterPersonFieldset to hydrate PersonObject.
I thought of hydrating both objects at the same time because this won't introduce conditionals into the form class. The problem is the hydration takes place just 1 object depending on which fieldset has use_as_base_fieldset = true. If both fieldsets have use_as_base_fieldset = true, the fieldset later in the code (RegisterPersonFieldset) hydrates only its respective object.
Could you tell how to hydrate both objects? Maybe how to hydrate objects in a better way?
EDIT:
As #jcropp pointed, I use Person and Organization as Parties that are independent entities sharing only Id property.

One way to hydrate two objects at the same time is to make them both the same object.
It is not clear from your question whether 1) a person who is registering is a member of a registering organization, or 2) "parties" are registering, and a party can be either an organization or a person. Here are some answers for both cases:
If persons are members of organizations in your data structure, a method for hydrating both at the same time is to treat the persons data as "collections" of the organization data elements. This method utilizes relationships between the fieldsets to create a single dataset in which both the organization data and the person data can be edited together. See the ZF2 Manual.
If your intent is to register individual parties, and a party can be either an organization or a person, a method for hydrating one or the other in the same form is to use table inheritance. In single table inheritance you would have a single table (and a single fieldset) for both types of parties, and a selection between the person or organization type would indicate whether data should be entered into the organization fields or the person fields of the table. In multiple table inheritance, you would create a party table that related to an organization table and to a person table; and organization and person fieldsets would extend the party fieldset.

Related

PHP Symfony FormType EntityCollection into Choices

I am beginner in PHP and Symfony and I started recently on a project.
We have 2 entities which are related by doctrine Annotation ManyToMany with JoinTable
Example: entity and datatable Room, entity and datatable Person and datatable RoomPerson (entity does not exist and just exist in doctrine annotation JoinTable).
The entity Room has a property Collection of Persons.
With a formType it is rendered in page as a select html element multiple (so we can choose several persons)
FormType with preEvent to fill list of possible persons:
$allowedPersons = $this->em->getRepository(Person::class)->findBy(***);
$form
->add('personList', EntityType::class, [
'class' => Person::class,
'choices' => $allowedPersons ,
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Room::class,
New request is to order the list of Persons.
So I made changes described in some tutorials to change declare the Entity RoomPerson et remove annotations ManyToMany for ManyToOne and OneToMany. I added the property "Order" on RoomPerson.
I Added the methods AddRoomPerson and RemoveRoomPerson to make updates of the list by the mapping of my FormType.
So my entity "Room" now only contains a property Collection of RoomPerson.
But I don't know how to use it in my FormType because I always want to show the list of Persons.
I tried a lot of things without success.
example:
$allowedPersons = $this->em->getRepository(Person::class)->findBy(***);
$form
->add('roomPersonList', EntityType::class, [
'class' => RoomPerson::class,
'choices' => $allowedPersons ,
'choice_value' => function(?RoomPerson $roomPerson) {
return $roomPerson? $roomPerson->getPerson()->getIdPerson() : '';
},
'choice_label' => function(?RoomPerson $roomPerson) {
return $roomPerson? $roomPerson->getPerson()->getName() : '';
},
I get following error:
Argument 1 passed to App\Form\RoomPersonType::App\Form{closure}() must be an instance of App\Entity\RoomPerson or null, instance of App\Entity\Person given, called in ..\vendor\symfony\form\ChoiceList\ArrayChoiceList.php on line 200"
So please I need help to transform my list of RoomPerson in my formtype and to make an update of this list in page.
When you are creating a form, the ->adds will make a reference to different columns you have defined in your App\Entity.
So, if you want to add something to your form this way, it has to be represented, again, in App\Entity.
Now, what you want to do, AFAIU, is fill a Room with people (class Person), and keep a list of those in the room (RoomPerson), and also a list of where every person has been (that's why it is a ManyToMany).
If instead you are looking at only where a Person has been the last time or at the moment, then it is a OneToMany relation, cause a room would be able to hold a bunch of people but any person would only be able to be at one place at a time (obviously).
Now I will simply take for granted you want to achieve the ManyToMany case. You should have all the columns needed in both Room and Person.
Now, RoomPerson should simply have a connection of those two and it's own id. You can add more things but for the purpose of this example let's just suppose we just need it to be a simple relating table so... your tables would look like (as an example):
<-M:N->
Room: <-M-> RoomPerson <-N-> Person:
- id (pk) - id (pk) - id (pk)
- space - room_id (fk) - gender
- style - person_id (fk) - room_usage
- purpose - age
- etc etc... - etc etc...
M being M number of posible objects on one side, N being N number of posible objects on the other side.
Once you have a DB like this, you can simply create a Form where you pass a Room, with every row you need in it.
If what you want is to select a room and have all the people displayed, you can, on the controller-side, get via queries a list of all the people that have been in each room, send it to the form, and then, on your template-side, play with html and js to dinamically show the correct list in each room.
I would need a more precise description to know exactly what you are trying to accomplish.

Fetch a Model's associations in Laravel to simplify creation/update

I have a Movie model with the following associations (belongsToMany):
Actor
Country
Genre
...
When a form is posted, I have this data (skipping a lot of details here):
'actors' => array(
'Cary Grant',
'Grace Kelly',
...
),
'genres' => array(
'Drama',
...
),
...
I'd like my update()/store() controller function to easily associate these Models.
An actor with the name 'Cary Grant' may or may not exist and may or may not be already associated with the movie I'm editing. Also I could remove him from this movie, so I'd need to remove the association. Same with Genre and everything else.
So I thought I'd do a BaseModel and do all of this only once in there, like this:
1. get the Movie Model's defined associations.
2. check if POST data contains those associations.
3. for each of them, check if they exist (if not create them) and return an array of ids. the column I'm checking is 'name', but it could be configurable.
4. sync() those ids.
For now, I don't need to add more stuff to the related model from the movie form (ex. an actor's birthdate).
I'm stuck at n.1 ($movie->getRelations() only works for existing movies) and in general I'm not sure if this is the right approach. Hints?
use direct relations: $model->actors
http://laravel.com/docs/4.2/eloquent#relationships
All sync() stuff will be done by ORM, so the most complex thing you should do is n.3. You must create diff between $model->actors and $_POST['actors'] and understand what actors you need to insert (create new actors).
I've met the same problem and this is what I do in my project:
Instead of retrieving all defined relations of the models, I white-listing relations that can be updated by adding a static member
Movie::$editableRelations = ['actors', 'genres', 'countries'];
Loop through the post data, and match with the $editableRelations arrays. If the data of a relation exists, following below steps, otherwise we simply do not touch this relation.
Step 3 and step 4 are the same as yours.

Model inheritance in Laravel 4

Groundwork
I have a database design (snipped to relevant portions) like so:
records
entities
people
where no proper relationship exists between the tables, but rather records is extended by entities is extended by people by sharing the same id.
I have my Eloquent models similarly defined so that Record is extended by Entity is extended by Person.
Goal
Record and Entity are abstract and I want to simply use Person and other models at that level in the hierarchy.
Problem
How do I 'link' Record and Entity to Person to make this all work seamlessly? I don't think relationships is appropriate. I assume it's related to something like this:
protected __construct() {
parent::__construct();
}
I suggest you still create a model for Person, Entity, and Record, and link them together with "belongsTo" relationships. (add entity_id column to "People" table, add "record_id" to "Entities" table).
If you are only working with the Person model, you could add a "saved" model observer to create the entity and record entries whenever you create a Person, and tie them all together with a global id.
http://laravel.com/docs/eloquent#model-observers
If you did it this way, you could access the person's entity and record field by doing something like:
$person->entity->fieldName
$person->record->fieldName
All that being said, this seems way too complicated. I would only have one table for People and store all the person's data there. imo.

One-to-one association in form?

In symfony 2.0, how to create a drop down list using one-to-one association in form? Can you guys put good example please?
I will try to answer your question the way I understand it. Let's say I have a Faculty object bound to a single University object. So in the form used to create or edit a faculty, I display a combo box of all the university in the database and the user choose one among them. There is one special Symfony field type that does exactly this: the entity type. Below is the code of the buildForm method that I use in my FacultyType object used to create the faculty form:
// Application\AcmeBundle\Form\Type\FacultyType
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name');
$builder->add('university', 'entity', array(
// The class of the entity used as a combo box item
'class' => 'AcmeBundle:University',
// The property of the entity displaying the entity as text
'property' => 'name',
// The query builder used to populate the combo box, accepts
// a QueryBuilder object or a \Closure like below
'query_builder' => function(EntityRepository $repository) {
// This will return a query builder selecting all universities
return $repository->createQueryBuilder('u');
}
));
}
Note: There are other properties that can be set for the entity field type, I invite you to take a look at this page for more information on it.
Rendered, this will show a combo box with all the universities I have set in the database. When the user save the form, the university chose is assigned to the faculty object bound to the form via a setter. You could probably render a drop-down list instead of a combo box. If you need to select multiple entities, the 'multiple' option of the field type entity could be useful.
This being said, the example I showed is not a One-to-One relation but rather a Many-to-One for the Faculty object and a One-to-Many for the University object. A One-to-One relation would be something more like a relation where a University has a unique Address. In this case, a combo box wouldn't be useful since the university can only have one adress so a sub-form would be more appropriate. If it has many adresses, then it becomes a One-to-Many relation like the relation between the university and its faculties.
Not sure if this will answer your question correctly but I hope it will lead you to a final solution.
Regards,
Matt
You need to use the entity field type in Symfony2. A good example is found at http://symfony.com/doc/current/reference/forms/types/entity.html

Taking the data mapper approach in Zend Framework

Let's assume the following tables setup for a Zend Framework app.
user (id)
groups (id)
groups_users (id, user_id, group_id, join_date)
I took the Data Mapper approach to models which basically gives me:
Model_User, Model_UsersMapper, Model_DbTable_Users
Model_Group, Model_GroupsMapper, Model_DbTable_Groups
Model_GroupUser, Model_GroupsUsersMapper, Model_DbTable_GroupsUsers (for holding the relationships which can be seen as aentities; notice the "join_date" property)
I'm defining the _referenceMap in Model_DbTable_GroupsUsers:
protected $_referenceMap = array (
'User' => array (
'columns' => array('user_id'),
'refTableClass' => 'Model_DbTable_Users',
'refColumns' => array('id')
),
'App' => array (
'columns' => array('group_id'),
'refTableClass' => 'Model_DbTable_Groups',
'refColumns' => array('id')
)
);
I'm having these design problems in mind:
1) The Model_Group only mirrors the fields in the groups table. How can I return a collection of groups a user is a member of and also the date the user joined that group for every group? If I just added the property to the domain object, then I'd have to let the group mapper know about it, wouldn't I?
2) Let's say I need to fetch the groups a user belongs to. Where should I put this logic? Model_UsersMapper or Model_GroupsUsersMapper?
I also want to make use of the referencing map (dependent tables) mechanism and probably use findManyToManyRowset or findDependentRowset, something like:
$result = $this->getDbTable()->find($userId);
$row = $result->current();
$groups = $row->findManyToManyRowset(
'Model_DbTable_Groups',
'Model_DbTable_GroupsUsers'
);
This would produce two queries when I could have just written it in a single query. I will place this in the Model_GroupsUsersMapper class.
An enhancement would be to add a getGroups method to the Model_User domain object which lazily loads the groups when needed by calling the appropriate method in the data mapper, which begs for the second question. Should I allow the domain object know about the data mapper?
This can be pretty confusing issue because a relational database can be hard to map to an object model.
I'd be inclined to focus on your object model requirements first. For example if in your object model it makes sense for your user object to (almost) always be aware of the groups then this relationship should be incorporated into the user class. If on the other hand you often need to use users without needing to know what groups they are a part of perhaps you can have two user classes, a base class and a group aware extended version (base_user and group_user).
I would try to avoid letting the domain object know about the data layer as that's kind of the whole point to using this pattern. The data layer should pretty much just be a dumb factory that instantiates your domain objects.
Just my take on it :)

Categories