How Symfony works to remove an collection items - php

When I submit a collection with removed elements, my elements are correctly removed but, I don't understand how Symfony remove elements.
When I die(); the script doesn't stop into my remover method, so I think Symfony doesn't pass into my method.
So, how Symfony can remove my elements without call my remover method ? How it's work ?
Application context :
I got some data from an API and I just want to add or remove data from my web interface. So, after I've add/remove data, I just want to post the new object on the API and remove the rows concerned. I also can compare the original object (get from the API) on pre submit and the new object on post submit to see the differences between both. But, if a method exist to call the remover of my object, I don't have to use this second solution and I think the first solution with a personnal remover is better.
Example of my remover :
public function removeMyElement($myElement)
{
personnalMethodTreatment($myElement);
if (!$this->myElement->contains($myElement)) {
return;
}
$this->myElement->removeElement($myElement);
}
Thank's for your help !
SOLUTION
So, thank to all for the help.
I write this lines to help other people who would have the same problem.
By default, Symfony call this own remover. If you want to call a custom remover, add the by_reference option at false to your collection form type.
by_reference: false
More information about by_reference https://symfony.com/doc/current/reference/forms/types/collection.html#by-reference
To conclude, by default Symfony call your custom method in this order :
Setter > Remover
So, if you have a setter and a remover, Symfony will prefer the former.
To solve my issu, I've followed the precedent instructions and I maked my specific treatment into my setter.
Hoping to have helped people.

Related

TYPO3 fluid select property remains empty after submit

Im creating an edit page for my model where I have the following code:
<f:form action="createEditSave" addQueryString="1" method="POST" object="{activity}" objectName="activity">
<f:form.select property="competence" options="{competences}" prependOptionLabel="" prependOptionValue="" optionLabelField="name" />
</f:form>
When I submit the form(and select an option in the select) I expect the model in my createEditSaveAction to contain in this case a competence. But it remains empty even though the request does contain the argument. Am I wrong in thinking it should automatically select the object and must I handle it myself in my createEditSaveAction?
I believe my html is correct.
When submitting my form I receive no validation errors and get correctly send to my createEditSaveAction. Only here I expect my Activity model to have a competence model but the setCompetence() function receives a empty objectStorage.
Depends on what happened to send you back to the form:
If the problem was validation errors the value should be prefilled since it will exist in the request data from the referring request, which is then read by the ViewHelper to determine the current value.
If you redirected to an edit action the property value only exists on the object you passed and if that object is, for example, not assigned as a template variable in the action that displays your form.
It may help if you specify the optionValueField property - and it may also help if you explicitly pass a value for the field.
Don't forget that if your use case is somehow too specialised to fit this, you can always use f:form.select.option in a loop to render options manually, including selected attribute.
Final word: from the naming of your action it looks like you have one action that is capable of both creating and updating an object. This is bad practice - you should be using two different actions for this, and on the "new" action your object argument should be optional and null by default, on "edit" it should be mandatory. It may also be a good opportunity to review your controller in general, to confirm that it actually does use properly declared and annotated arguments and argument types for all the actions. If you circumvent the framework, things like form validation and subsequently resolving of field values may not work like you expect.
Resolved my own issue. The problem was the annotation in my model which said it was a objectStorage.
Had a similar issue with my form, I had to include both the name and the propery tag.
<f:form.select name="foo" property="foo">
<f:form.select.option value="bar">Bar</f:form.select.option>
</f:form.select>

Magento2 - setData() For Added Fields

I have added a field(key) in table(quote_item) through module installation(InstallSchema) and in Api Code I am using the following code to add value for that. But its not adding the value to that field in DB.
//cartItemObject \Magento\Quote\Model\Quote\Item
$cartItemObject->setData("key", "value");
Can anyone please help me on this?
Before making the setData, did you start the model? If you are using factory you should do as follows:
$cartItemObject=$this->model->create(); // after this you would have access to the following methods getData(), setData(), etc
In any case if it still does not work I advise you to review this information for handling model in magento 2

ZF2: Where does the controller return/result get manipulated by the MVC?

I am working on a RESTful API in Zend Framework 2. I use the AbstractRestfulController to handle requests. In that controller I want to directly return an array or object (of a custom model class), not a JsonModel. That stuff and the conversion of the result to arrays (as a preparation for the JSON encoding) should happen later automatically.
I tried to catch the MvcEvent::EVENT_DISPATCH event to manipulate the $e->getResult()value but when I return an associative array in the controller I get a ViewModel in the result instead of the plain data passed in by the controller method.
I tried to create a custom view strategy by implementing the ListenerAggregateInterface class. In the ViewEvent::EVENT_RESPONSE event catch, I dumped the $e->getResult() value and got the already encoded result. Also here, I need the plain result to prepare it for encoding.
Where can I hook in to manipulate the controller's plain return value before encoding to JSON? Where does ZF2 generally manipulate the returned value in the MVC lifecycle?
Thank you in advance!
I don't have so much time to investigate in this issue, but my guess is that you may omit to stop event propagation when you attached a listener to MvcEvent::EVENT_DISPATCH. So what you set as the event result is probably overridden later in the dispatch process.
Try to attach your callback with a higher priority and stop the propagation ($e->stopPropagation() from the callback), since the event manager won't stop the propagation by itself until one or the other callback returns a Zend\StdLib\ResponseInterface object.
Anyway, I know you probably have good reasons trying to "hack" the dispatch process this way, but I tend to think that there could be even better reasons to adapt your code to fit the default process ;)
Here, zf2 creates a ViewModel in case an assoc array is detected in the result, registered at priority -80. According to this documentation page this is the first event catch changing the result returned by the controller.
What I did wrong is attaching my MvcEvent::EVENT_DISPATCH to the $application->getEventManager() instead of $application->getEventManager()->getSharedManager() (like zf2 does). I don't understand yet what the difference is, but it works.
Here is how I registered the event in the onBootstrap method:
$application->getEventManager()->getSharedManager()->attach(
__NAMESPACE__,
MvcEvent::EVENT_DISPATCH,
array($this, 'createJsonModelFromResult'),
-10
// priority of -10 because at priority 1 the mvc
// runs the actual controller method
);
At the end of the createJsonModelFromResult method I also added $e->stopPropagation(); because we already found the matching ViewModel.
Now the $e->getResult() value is exactly the same as returned in my controller actions and I can prepare it for JSON encoding. Cool!
I have no idea how you want to return an array or Object. Usually people make a DTO (Data Transfer Object), serialize it, and then send it. In this method the DTO at the end converts to JSON.
What format do you want to use in response? String (serialized DTO), XML, or something else? You can create a class extending ViewModel and serialize your array for your format.
Anyway, you do not need to get MVC_EVENT.

Doctrine 2: Force scheduleForUpdate on a non-changed entity

How can I schedule an entity for update, manually, when no property is actually changed?
I tried $entityManager->getUnitOfWork()->scheduleForUpdate($entity) but it gave an error in the core, and I have no intetion of debuging Doctrine.
The entity is managed if it matters: $entity = $repository->findOne(1)
I need this so doctrine would call my EventSubscriber on flush().
I've also tried something like $entityManager->getEventManager()->dispatchEvent(\Doctrine\ORM\Events::preUpdate), but then my listener's preUpdate() receives EventArgs instead of PreUpdateEventArgs.
Any help is appreciated!
Method mentioned by Wpigott not working for me (at least in doctrine/orm v2.4.2), instead I'm using this:
$entityManager->getUnitOfWork()->setOriginalEntityProperty(spl_object_hash($entity), 'field_name', '__fake_value__');
Where field_name existent property name.
The solution is a bit hacky, but I was able to achieve this by doing something like the following.
$objectManager->getUnitOfWork()->setOriginalDocumentData($object, array('__fake_field'=>'1'));
This essentially causes Doctrine to think the document has changed from the original, and it computes it as a change which will cause the events to be executed on flush.
The example is for the MongoODM solution, but the same technique should work for ORM like below.
$objectManager->getUnitOfWork()->setOriginalEntityData($object, array('__fake_field'=>'1'));
Even though this question is quite a bit old, I just found a way much more elegant to solve this problem I want to share here using Doctrine ORM 2.6.2:
You can simply tell the ClassMetadataInfo object of your table to just state those fields as dirty that you pass to the propertyChanged function of the UnitOfWork. The important parts here are the setChangeTrackingPolicy and propertyChanged calls:
$unitOfWork = $entityManager->getUnitOfWork();
$classMeta = $entityManager->getClassMetadata('Your\Table\Class');
$ctp = $classMeta->changeTrackingPolicy; # not a function but a variable
# Tell the table class to not automatically calculate changed values but just
# mark those fields as dirty that get passed to propertyChanged function
$classMeta->setChangeTrackingPolicy(ORM\ClassMetadataInfo::CHANGETRACKING_NOTIFY);
# tell the unit of work that an value has changed no matter if the value
# is actually different from the value already persistent
$oldValue = $entity->getValue('fieldName'); # some custom implementation or something
$newValue = $oldValue;
$unitOfWork->propertyChanged($entity, 'fieldName', $oldValue, $newValue);
# field value will be updated regardless of whether its PHP value has actually changed
$entityManager->flush();
# set the change tracking policy back to the previous value to not mess things up
$classMeta->setChangeTrackingPolicy($ctp);
You may also want to have a look at the Doctrine\Common\NotifyPropertyChanged interface.
I hope this will be useful for someone.
What's the goal? If there is no property changed, why would you plan an update?

How do you restore the values of the form in case if validation failed (in Kohana 3)

There is a sample in the bottom of the official documentation http://kohanaframework.org/3.2/guide/kohana/security/validation
But obviously it wont work at the request as long as $post['username'] in View is used but the $post array is empty on first request.
So how do you restore the values in this case? Any general solution?
PS: yes, I do understand I could do isset($post['username']) ? $post['username'] : ''; but it is just annoying
I use the model to display the data in the form. That way the initial form value is the initial value in the model.
I then update the model data with POST data in the controller, if there are validation errors, the model data will contain the POST data. This means I don't have to put any conditional logic in the view, and I just do: Form::input('name', $model->name)
Here's a more detailed explanation of this approach: Kohana ORM and Validation, having problems
I use Arr::get function:
echo Form::input('name', Arr::get($post, 'name'))
I was just looking at the old documentation on Building and Validating a Form.
You can see from the sample code that first you need to initialize an array with the form field names as the key and set the value to an empty string. And if there's an error, fill in the values of each element. In the views, you can simply call Form::input() normally without any if statement or some sort.
I guess Kohana has already been built this way from the start. And it doesn't seem to change. You'll probably just need to do the same thing.

Categories