Is there documentation for non-dynamically adding a 'many' to a 'one' in a 'one-to-many' relationship? - symfony

I have a Customer who has several PhoneNumbers.
The user creates a new Customer via a form, and I want him to be able to specify a single PhoneNumber.
Symfony's documentation tells me how to do this if the user were creating a PhoneNumber and had to also specify a Customer (link). It also tells me how to solve my problem using some Javascript, as described by the Cookbook's recipe for dynamically adding entities (link).
What I'm missing is the part of the documentation where it simply describes a non-dynamic form that lets you add a single entity upon submission. So, the user fills out the customer's details, puts a phone number, and everything works out.
I suppose I could make a separate form, give it a PhoneNumberType, and then upon submission, call $customer->addPhoneNumber($phoneNumber). But it seems like there should be a way to handle it through the relationships alone & in a single form.

Coming back to this question, I realize the answer is simple. In my controller,
// CustomerController.php
$customer = new Customer();
$phoneNumber = new PhoneNumber();
$customer->addPhoneNumber($phoneNumber);
Now when I build my form, I'll have a single blank PhoneNumber associated with the new Customer, and everything will persist as expected.

Related

How to programmatically link newly created records to a record from another table

Thanks in advance for your advice!
Background
I’m creating a database to track orders placed by customers.
An ‘Orders’ table stores general details about an order like the customer’s name, order date, and delivery-required date.
A separate ‘Order_Items’ table stores the specific items that the customer has ordered.
The is a one-to-many relationship between the ‘Orders’ table and ‘Order_Items’ table, i.e. one ‘Order’ can have many ‘Order_Items’, but each ‘Order_Item’ must be associated with only one ‘Order’.
Current State
Currently, I have a page where the user creates a new ‘Order’ record. The user is then taken to another page where they can create as many ‘Order_Item’ records as are needed for the order.
Desired State
What I would like to achieve is: When a user creates new ‘Order_Item’ records, it automatically allocates the current ‘Order’ record as the foreign key for the new ‘Order_Item’ record.
What I've Tried So Far
Manual Action By The User: One way of establishing the link between an 'Order' and all of its 'Order_Items' would be to add a drop-down widget which which effectively asks the user something like "Which order number do all of these items belong to"? The user's action would then establish the link between the two tables and associate one 'Order' with many 'Order_Items'. However, my goal is for this step to be handled programatically instead.
Official Documentation: I’ve referred to the offical documentation which was useful, but as I'm still learning I don’t really know exactly what to search for. The prefetch feature appeared promising but does not actually establish a link; it just loads associated records more efficiently.
App Maker Tutorials: I found an App Maker tutorial which creates an HR App where a user can create a list of ‘Departments’, then create a list of ‘Employees’, and then link an ‘Employee’ to a ‘Department’. However, in the example app this connection is established manually by the user. In my desired state I would like the link to be established programatically.
Manual Save Mode:
I’ve also tried switching to manual save mode so that the user has to create a draft ‘Orders’ record and then several draft ‘Order Items’ records and then save them all at once. However, I haven’t managed to make this work. I’m not sure whether the failure of this approach is because 1) I’m try to create draft records on more than one table, 2) I’m just not doing it correctly, or 3) I thought I read somewhere that draft records are deprecated.
Other Ideas
I'm very new to this field and am may be wrong, but I have a feeling I may need to use some scripting to establish the link. For example, maybe I could use a global variable to remember which 'Order' the user creates. Then, for each 'Order_Item' I could use the onBeforeCreate event to trigger a script that establishes the link between the 'Order_Item' and the 'Order' that was remembered from the previously established global variable.
Updated Question
Thanks Markus and Morfinismo for your answers. I have been using both answers with some success.
Morfinismo: I've successfully used the code you directed me to on existing records but cannot seem to get it to work for newly created records.
For example:
widget.datasource.createItem(); // This creates a new record
var managerRecord = app.datasources.Manager.item; // This sets the Manager of the currently selected parent record as a variable successfully.
var teamRecord = app.datasources.Teams.item; // This attempts to set the Manager of the currently selected record as a variable. However, the record that was created in line 1 is not selected. Therefore, App Maker does not seem to know which record this line of code relates to and returns the error Cannot set property ‘Manager’ of null.
// Assign the manager to the team.
teamRecord.Manager = managerRecord; // This successfully assigns the manager but only in cases where the previous line of code was successful (i.e. existing records and not newly created ones).
Do you have any suggestions or comments on how to apply this code to records that are created by the initial line of code in line 1?
I have found the easiest way to create related items for situations such as yours is to actually import a form with the datasource set to Parent: Child (relation) or Parent: Child (relation) (create). So in your case the datasource would need to be set to Order: Order_Items (relation).
You can get this accomplished in two different ways using the form widget wizard:
Option 1:
If your page datasource is set to Order_Items, drag your form on your page.
In the datasource selection section, your datasource in the form widget should default to `Inherited: Order_Items'. Click the 'Advanced' button in the bottom left corner, then from the datasources category find Order as your datasource, then select relations in the next field, and then Order_Items in the next field, choose 'Insert only' or 'Edit' form and then the appropriate fields you want in the form.
Now every item that gets created in that form will automatically be a child record of the currently selected record in your Order datasource.
Option 2:
If your page datasource is set to Order, drag your form on your page.
In the datasource selection section, your datasource in the form widget should default to Inherited: Order. Scroll down in your datasource selection section until you find Order: Order_Items (relation), then choose 'Insert only' or 'Edit' form and then the appropriate fields you want in the form.
Now every item that gets created in that form will automatically be a child record of the currently selected record in your Order datasource.
In your Order model, make sure that the security setting is set appropriately that a user is allowed to create relations of Order_Items in Order. That is the simplest approach in my opinion since you don't have to hard code the parent into your form or client/server scripts. It is automatically based on the currently selected parent, and is essentially doing the same thing that #Morfinismo explained in the client script section.
The comment I placed under your question included a link to the official documentation that explains what you need. Anyways, your question is not clear enough to determine whether you are creating the records via client script or server script, hence this is a very general answer.
To manage relations via client script:
var managerRecord = app.datasources.Manager.item;
var teamRecord = app.datasources.Teams.item;
// Assign the manager to the team.
teamRecord.Manager = managerRecord;
// Changes are saved automatically if the datasource in auto-save mode
// Add a team member to a Manager's team.
// Note: Retrieve Members on the client before proceeding, such as by using prefetch option in datasource - datasources Team -> Members)
var engineerRecord = app.datasources.TeamMember.item;
teamRecord.Members.push(engineerRecord);
To manage relations via server script:
// Get the record for the Team to modify.
var teamRecord = app.models.Teams.getRecord("team1");
// Assign a manager to the Team.
var managerRecord = app.models.EmployeeDB.getRecord("manager1");
teamRecord.Manager = managerRecord;
// Note: The new association is not saved yet
// Assign a team member to the Team.
var engineerRecord = app.models.EmployeeDB.getRecord("engineer1");
teamRecord.Members.push(engineerRecord);
// Save both changes to the database.
app.saveRecords([teamRecord]);
The above information is taken directly from the official documentation, which like I said, I referred to in the comment I placed under your question.

Use a repository with JMS serializer

I have a Symfony 3.4 projet with a REST api. I use JMS serializer.
I have a entity User and I have a route /api/user which return the user id, name , ...
I also have a entity badges which has a relation many to many with user (so a user_badge table). Like I read, when the pivot table have extra column (like in my case on user_badge), I need to create two relation many to one to link my user to badges.
In my route /api/user I add the return on my badges with JMS, I return my badge id and the achievement date (the extra column) from user_badge with the method getUserBadges from my entity User.
But now I want to order by the badges using a column from the badge entity.
How can I achieve this ? The fact than my model user can't access the badges without a heavy foreach. I need to make a request to getting all the badges in the correct order and passing this to JMS.
(I don't know which source file I should provide, cause I don't really know how to achieve it)

FOSUserBundle registration form overridden - validation problems

I've modified my registration form and added a few fields (such as First name, Last name, and Organisation name).
My application will have 2 types of users - "regular" users, that will have to provide their First name and Last name, and also "organisations", that will have to provide their organisation name.
When the form is rendered, the system detects the user's "type" and only shows the form fields relevant to that user (for example: "organisations" don't get the First name and Last name fields).
The registration works fine, but there are no validation messages shown... Even if there is an error, it is not displayed.
How should I handle this?
I think it would be a better idea for you to instanciate a different form for different user level, instead of doing that in templating.
Use this:
parent::buildForm($builder, $options);
where you extend your form.

Symfony2 Mapping Model to Entity

I am currently trying to sort out my user registration in Smyfony2, loosely following their documentation here:
http://symfony.com/doc/current/cookbook/doctrine/registration_form.html
Sadly, their example is a bit simplistic.
My User Entity has a number of fields which only get added to during registration, and can't be changed there after, so I separated those out from my UserType into my RegistrationType.
The problem now, is that Symfony can't find any of the fields, requested for the form, which live within the User Entity, because it is looking for them in the Registration model. How do I get the Registration model to point to User Entity?
In the documenation example, they avoid all this as the "terms and conditions" checkbox doesn't get added to the database.
e.g. they use this:
$builder->add('user', new UserType());
but as I mentioned, that only has the fields I want the user to edit after registration.
I tried the data_class, but it complained about Form\Model\Registration wasn't of type Entity\User.
These seems like a really common issue when you are trying to embed bits of forms for a single entity, yet it doesn't cover it in the documentation.
And no, I don't want to use FoSUserBundle.
Actually, it's possible and really easy to have several form types for the same model class. You can have the RegistrationType with lots of fields and then the UserType with only some of those fields. Both use the same User model.

How to add/save temporary table on form

We created special form to creating purchase prices for vendors.
New form has almost the same fields as original (so we used PriceDiscTable), but the record/datasoruce was set as temporary table. After user filled mandatory fields will click button, (extra logic behind) and record will inster to database (real priceDiscTable).
The idea was to grand access to trade prices for users that not necessarily has access to purchase prices. In theory everything was ok, but when user with no access to PriceDiscTable open new form, error was shown "Not enougt right to use table 'Price agreements'".
We try set the AllowCheck to false in formDatasource but this only allow us to open the form, but user still cannot add or modify records.
Is there any way to force system to allow user to write data in the temporary table?
Disabling security key or grand access to real table is not an option.
Duplicate table and create with same fields is nuisance (if we use same table we can use data() method to assign fields)
I think that creating a new temporary table with [almost] the same fields would be the best solution.
If the only reason you oppose to this approach is that you wouldn't be able to use data() to copy data from one table to another you can use buf2BufByName() as described here: http://mybhat.blogspot.co.uk/2012/07/dynamics-ax-buf2buf-and-buf2bufbyname.html
You can use RunAs to impersonate another user...perhaps a system user. I don't entirely follow what you are trying to do, but it sounds like this solution would work for you if you know exactly what your custom code is doing and is capable of.
See Classes\AifOutboundProcessingService\runAsWrapper to see an example.
You will not be able to display the PriceDiscTable without giving the user at least "view" access or editing Classes\FormRun to somehow bypass the security key, which is kernel level so it's also not possible.
I agree with 10p where you should create a temp table and then create a custom method handler combined with buf2bufbyname() or buf2buf().
Another option you can screw around with, if you REALLY want to use .data() is using a Common as the datasource. You could add the fields you want on the grid with the common, then you can pass a common back/forth. This has a good amount of form setup to get this working, but it could produce what you want eventually I think.
static void Job8(Args _args)
{
Common common;
salesTable salesTable;
;
common = new DictTable(366).makeRecord();
select firstonly common where common.RecId == 5637145357;
salesTable.data(common);
info(strfmt("%1 - %2", salesTable.SalesId, salesTable.SalesName));
}

Resources