Symfony don't update date field - symfony

In my Controller, I want change two values in my entity (only for index "3) :
$cle->getVersions()[0]->getLots()[3]->setTantieme(97);
$cle->getVersions()[0]->getLots()[3]->setDateSuppression(new \DateTime);
dump($cle);
$em->flush();
But, only "Tantieme" value is changed. I don't understand. In my entity, I have :
/**
* #var string
*
* #ORM\Column(name="date_suppression", type="datetime", nullable=true)
*/
protected $date_suppression;
public function setDateSuppression($date_suppression)
{
$this->date_suppression = $date_suppression;
}
public function getDateSuppression()
{
return $this->date_supppression;
}
It is a trait . And it works great with others entities.
Dump result juste before flush :
Image
Tantieme is always updated, but date_suppression never ...

Try to return "something" in your setDateSuppression() method:
public function setDateSuppression($date_suppression)
{
$this->date_suppression = $date_suppression;
return $this;
}
EDIT:
Try like that :
$cle->getVersions()[0]->getLots()[3]->setDateSuppression(new \DateTime());

Related

Symfony4, how to properly handle missing form field ? (without exception in $this->propertyAccessor->setValue)

I have a Task entity, with two mandatory, non-nullable, fields:
title
dueDatetime
and Form to create task. The form is called by external scripts through POST with application/x-www-form-urlencoded (so no json or anything fancy), so I use standard symfony to handle this.
Problem is I don't control the scripts, and if the script forgot one of the argument, symfony4 will directly throw an exception at the handleRequest step, before I have the time to check if the form is valid or not. Which result in an ugly response 500.
My question: How to avoid that ? The best for me would be to just continue to use "form->isValid()" as before , but if there's an other standard way to handle that, it's okay too.
Note: it would be best if I don't have to put my entity's setter as accepting null values
The exception I got:
Expected argument of type "DateTimeInterface", "NULL" given.
in vendor/symfony/property-acces /PropertyAccessor.php::throwInvalidArgumentException (line 153)
in vendor/symfony/form/Extension/Core/DataMapper/PropertyPathMapper.php->setValue (line 85)
in vendor/symfony/form/Form.php->mapFormsToData (line 622)
in vendor/symfony/form/Extension/HttpFoundation/HttpFoundationRequestHandler.php->submit (line 108)
in vendor/symfony/form/Form.php->handleRequest (line 492)
A curl that reproduce the error :
curl -d 'title=foo' http://127.0.0.1:8080/users/api/tasks
The code :
Entity:
class Task
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="bigint")
*/
private $id;
/**
* #Assert\NotNull()
* #Assert\NotBlank()
* #ORM\Column(type="string", length=500)
*/
private $title;
/**
*
* #ORM\Column(type="datetimetz")
*/
private $dueDatetime;
public function getDueDatetime(): ?\DateTimeInterface
{
return $this->dueDatetime;
}
public function setDueDatetime(\DateTimeInterface $dueDatetime): self
{
$this->dueDatetime = $dueDatetime;
return $this;
}
public function setTitle($title)
{
$this->title = $title;
return $this;
}
public function getTitle()
{
return $this->title;
}
}
Form
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('dueDatetime')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Task::class]);
}
}
Controller:
class TaskController extends AbstractController
{
/**
* #Route(
* "/users/api/tasks",
* methods={"POST"},
* name="user_api_create_task"
* )
*/
public function apiCreateTask(Request $request)
{
$task = new Task();;
// the use of createNamed with an empty string is just so that
// the external scripts don't have to know about symfony's convention
$formFactory = $this->container->get('form.factory');
$form = $formFactory->createNamed(
'',
TaskType::class,
$task
);
$form->handleRequest($request); // <-- this throw exception
// but this code should handle this no ?
if (!$form->isSubmitted() || !$form->isValid()) {
return new JsonResponse([], 422);
}
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($task);
$entityManager->flush();
return new JsonResponse();
}
}
There are at least 2 ways to handle this.
In the two ways you will have to add #Assert\NotNull() to the dueDatetime attribute.
1 - You can try/catch the exception of the handleRequest call.[edit] this one breaks the flow, not good.
2 - You can make nullable the setter setDueDatetime(\DateTimeInterface $dueDatetime = null). If you choose this one, please be sure to always validate your entity before an Insert/Update in DB else you will get an SQL error.
In the two cases it will be handled by the validator isValid() and you will have a nice error in your front end.
You need to allow nullable parameter (with "?") in method setDueDatetime
public function setDueDatetime(?\DateTimeInterface $dueDatetime): self
{
$this->dueDatetime = $dueDatetime;
return $this;
}

Type error with ArrayCollection / OneToMany relationship in Symfony 3.4

For the past couple of days I have been trying to create a bidirectionnal ManyToOne-OneToMany relationship in Symfony 3.4
I have two entities. One is Contribution and the other is Source. A Contribution can have several sources. So the relationship should be
Contribution – ManyToOne – Source – OneToMany – Contribution
But I keep getting the following error during $em→flush(); in my controller:
Type error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in /var/www/html/Edebate/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 605
I do not have any set method related to the Array Collection in my Entity Contribution as I could see in other posts here:
Type error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given
Symfony-Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given
And the annotations are ok as mentionned here:
Doctrine OneToMany relationship error
Any help would be appreciate ! :)
Here is my Entity Contribution
use Doctrine\Common\Collections\ArrayCollection;
//annotations
abstract class Contribution
{
/**
* #ORM\OneToMany(targetEntity="Shaker\DebateBundle\Entity\Source", mappedBy="parent")
*/
protected $sources;
//Other attributes and methods
public function __construct() {
$this->sources = new ArrayCollection();
}
/**
* Add source
*
* #param \Shaker\DebateBundle\Entity\Source $source
*
* #return Contribution
*/
public function addSource(\Shaker\DebateBundle\Entity\Source $source)
{
$this->sources[] = $source;
return $this;
}
/**
* Remove source
*
* #param \Shaker\DebateBundle\Entity\Source $source
*/
public function removeSource(\Shaker\DebateBundle\Entity\Source $source)
{
$this->sources->removeElement($source);
}
/**
* Get sources
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSources()
{
return $this->sources;
}
}
And this is in my Entity Source:
/**
* #ORM\ManyToOne(targetEntity="Shaker\DebateBundle\Entity\Contribution", inversedBy="sources")
*/
protected $parent;
/**
* Set parent
*
* #param \Shaker\DebateBundle\Entity\Contribution $parent
*
* #return Contribution
*/
public function setParent(\Shaker\DebateBundle\Entity\Contribution $parent = null)
{
$this->parent = $parent;
$parent->addSource($this);
return $this;
}
/**
* Get parent
*
* #return \Shaker\JRQBundle\Entity\Contribution
*/
public function getParent()
{
return $this->parent;
}
And in my Controller, the problem arises with flush:
$formsourcebook->handleRequest($request);
$contributionid=$formsourcebook->get('ContributionId')->getData();
if ($formsourcebook->isValid()) {
$topicargtarget=$this->getContribution($contributionid);
$sourcebook->setUser($user);
$sourcebook->setContribution($topicargtarget);
$em->persist($sourcebook);
$em->flush();
}
I don't know your question very well. However, did you try with this syntax in the Source entity?
private $parent;
// ...
public function __construct() {
$this->parent = new ArrayCollection();
// or new \Doctrine\Common\Collections\ArrayCollection();
}
I think you're forgetting the constructor in the class.
I think you "switched" some logic when working with collections. Here's how I think your "add" method should look like:
public function addSource(\Shaker\DebateBundle\Entity\Source $source)
{
$this->sources[] = $source;
$source->setParent($this);
return $this;
}
And in the other entity:
public function setParent(\Shaker\DebateBundle\Entity\Contribution $parent = null)
{
$this->parent = $parent;
return $this;
}
There are missing variables in your controller snippet, together with the form fields definitions, so you shouldn't work that much after submitting the form. Try to directly map as many fields as you can (even via autoguessing), and even if it looks ugly, but works, but then you can beautify later. Just my two cents with several months of delay.

Doctrine2 EntityNotFoundException when getting an entity from relation

In a Symfony2 project using Doctrine2. I have a Lead entity related with Promotion entity 1-N. A Lead con have a related Promotion or not.
//Lead.php
...
/**
* #var string $promotionCode
* #ORM\Column(name="promotion_code", type="string", length=16)
*/
private $promotionCode;
/**
* #var Promotion $promotion
* #ORM\ManyToOne(targetEntity="Promotion")
* #ORM\JoinColumn(name="promotion_code", referencedColumnName="id")
*/
private $promotion;
...
public function setPromotionCode($promotionCode) {
$this->promotionCode = $promotionCode;
}
public function getPromotionCode() {
return $this->promotionCode;
}
public function setPromotion($promotion) {
$this->promotion = $promotion;
}
public function getPromotion() {
return $this->promotion;
}
When I want to obtain the related promotion (if any) y do
$lead = $em->getRepository('BuvMarketplaceBundle:Lead')->find($id);
$promotion = $lead->getPromotion();
If the lead has a promotion this is OK. But if not this code returns a Promotion "entity", but when I try to use if I get an EntityNotFoundException.
So I have to test if the related promotion exists like this:
if (is_object($promotion) && method_exists($promotion, 'getDiscount')) {
try {
$promotion->getDiscount();
} catch(EntityNotFoundException $e) {
$promotion = null;
}
} else {
$promotion = null;
}
I know that I can use a findBy in the Promotion Repository, and may be another methods to check this.
But the question is if this is a bug or a feature in Doctrine2, so I'm getting a "false entity" when I think it may be a null.

symfony 2 Error:Call to a member function * on a non-object in *

I have an entity Users
class Users
{
//...
/**
* #ORM\Column(name="firstName", type="string", length=50, nullable=true)
*/
private $firstname;
public function getFirstname()
{
return $this->firstname;
}
/*
*#ORM\OneToMany(targetEntity='Worksamples', mappedBy='user')
*/
private $worksample;
public function __constraction()
{
$this->worksample = new ArrayCollection();
}
public function getWorksample()
{
$this->worksample;
}
}
and another one entity called Worksamples
class Worksamples
{
//...
/**
* #ORM\Column(name="sampleSource", type="string", length=255, nullable=false)
*/
private $samplesource;
public function getSamplesource()
{
return $this->samplesource;
}
/**
* #ORM\Column(name="UserId", type="integer", nullable=false)
*/
private $userid;
public function getUserid()
{
return $this->userid;
}
/*
*#ORM\ManyToOne(targetEntity="Users", inversedBy="worksample")
*#ORM\JoinColumn(name="UserId", referencedColumnName="id")
*/
private $user;
public function getUser()
{
return $this->user;
}
}
in my controller i have this action
public function indexAction($id)
{
$user = $this->getDoctrine()
->getRepository('AcmeWellcomeBundle:Users')
->find($id);
$sample = $user->getWorksample()->getSamplesource();
return $this->render('AcmeWellcomeBundle:Default:index.html.twig', array('sample' => $sample));
}
and I have this error
FatalErrorException: Error: Call to a member function getSamplesource() on a non-object in ....
it supposed a User has many Worksamples and a Worksample has only one User.
any help?
Before using your code
Did you run your classes through the console of your app? If not execute this in your terminal or a console through SSH on your Server:
php app/console doctrine:generate:entities [YourVendorName]
Afterwards update your database using:
php app/console doctrine:schema:update --force
And clear caches:
app/console cache:clear
Those steps will make sure that all annotations are actually used and your database is set up correctly.
Then: You don't need private $userid; in Worksamples and you don't need $this->worksample = new ArrayCollection(); in Users. Doctrine will handle all this for your. Also it would be good to rename $worksample to $worksamples as it will always return an arrayCollection and never a single object.
When all is set up correctly, you can simply use $workspace->getUser() which will return an object of class User attached to this specific object.
In your controller
First of all get the list of worksamples. Then check whether any worksamples are attached to the object. Then for example get the vlue from the first object in the list:
$samples = $user->getWorksamples();
if ($samples) {
$sample = $samples[0]->getSamplesource();
}
Some notes:
The constructor of a class is called __construct() and not __constraction().
As a single object represents a user or a workspace, your classes should also be named User and Wokrspace in singular.

Found the public method "add", but did not find a public "remove" in symfony2 entity

I get this exeption when I submit my form:
Found the public method "addRemote", but did not find a public "removeRemote" on class App\CoreBundle\Entity\Scene
The weired think is that the remove method exist ...
But i wrote it myself (When I did php app/console doctrine:generate:entities) doctrine didn't generated it. Did I make something wrong ?
/**
* #var array $remote
*
* #ORM\Column(name="remote", type="array", nullable=true)
*/
private $remote;
/**
* Set remote
*
* #param array $remote
* #return Scene
*/
public function addRemote($value, $key=null) {
if($key!=null){
$this->remote[$key] = $value;
}else{
$this->remote[] = $value;
}
return $this;
}
/**
* Remove remote
*/
public function removeRemote(){
unset($this->remote);
}
I allso tried:
/**
* Remove remote
*/
public function removeRemote($key=null){
if($key!=null && array_key_exists($key, $this->remote)){
unset($this->remote[$key]);
}
unset($this->remote);
return $this;
}
You have bigger problem than this; you are abusing your forms :)
Add.. and Remove... methods should be used for relations, not columns as per your code. Also, both add and remove methods must accept parameter that will be either added or removed.
If you still need an array, than getRemotes() method should return key=>value array. Adder and remover will later get that key, based on what user have picked in choice form type.

Resources