Using Symfon2.0 and Doctrine, I am trying to do the following:
Insert a new row in the database
in the moment of inserting, automatically generate a code and also insert it.
That code is related to the ID of the table. Something like <something>/row_id
How can I easily do this?
I've been trying Doctrine Livecycle callbacks. But:
PrePersist still doesn't have the ID.
PostPersist have the ID, but somehow the insertion has already been done and, although I can set any property from the Entity, I don't know how to make it to be persisted "again" to the database.
Any clue overthere?
Any other way to do it properly?
In your create controller:
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
$entity->setCode($code);
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('entity_show'
,array('id' => $entity->getId())));
}
The second block ($entity->setCode...) is what you need to add and will need to be customized to suit your purposes
Alternatively, you can use Listeners:
<?php
namespace ormed\ormedBundle\Listener;
use Doctrine\ORM\Event\OnFlushEventArgs; use
Symfony\Component\DependencyInjection\Container;
class LastModifiedListener {
private $container;
public function __construct(Container $container){$this->container = $container;}
public function onFlush(OnFlushEventArgs $eventArgs)
{
$entityManager = $eventArgs->getEntityManager();
$unitOfWork = $entityManager->getUnitOfWork();
foreach ($unitOfWork->getScheduledEntityInsertions() AS $entity) {
$entity->setCode( $code );
$entityManager->persist($entity);
$classMetadata = $entityManager->getClassMetadata(get_class($entity));
$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity);
} } }
Related
I'm new learner of Symfony 4 and I'm looking for help. I've an Entity named "Player" and I want to generate a random confirmation number.
For now, I'm using a variable $confirmNbr and I save the $confirm in my database with $participant->setConfirmationNumber($confirmNbr);.
What I want it's create a function generateRandomNumber() in my Entity Player.php like this :
public function generateConfirmationNumber() : self
{
$this->confirmationNumber = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',6)),0,5);
return $this;
}
This is my Controller file
/**
* #Route("/", name="homepage")
*/
public function new(Player $player, EntityManagerInterface $em, Request $request)
{
$participant = $this->playerrepo->findAll();
$form = $this->createForm(PlayerFormType::class);
$randomNbr = $player->generateConfirmationNumber();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$participant = new Player;
$participant->setName($data['name']);
$participant->setFirstname($data['firstname']);
$participant->setEmail($data['email']);
$participant->setConfirmationNumber($confirmNbr);
$participant->setRegisterAt(new \DateTime);
$em->persist($player);
$em->flush();
$this->addFlash('success', 'Player added!');
return $this->redirectToRoute('homepage');
}
return $this->render('app/subscribe.html.twig', [
'playerForm' => $form->createView(),
'player'=>$player,
]);
}
And this is my error message :
Unable to guess how to get a Doctrine instance from the request
information for parameter "player".
Can you help me please ?
Your method is expecting an instance of the Player object - where should it come from? Doctrine is trying to guess it and get it from the URL, but it cannot. Your method is for creating new players - why do you need an instance of a player? Just remove that parameter from the method signature, i.e. change it to:
public function new(EntityManagerInterface $em, Request $request)
I've found the solution. I've modified my set function and deleted my function that I've added. Everything works!
Hello i saw a lot of tutorials and still dont know how can i make custom functions in my already done repository.
this is content of my CommentController:
public function newAction(Request $request, $productId)
{
$comment = new Comment();
$form = $this->formFactory->create(CommentForm::class, $comment);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->get('doctrine')->getManager();
/** #var Product $product */
$product = $em->getRepository(Product::class)->find($productId);
$comment->setAuthor($this->tokenStorsge->getToken()->getUser());
$comment->setProduct($product);
$comment->setContent($form->get('content')->getData());
$this->em->persist($comment);
$this->em->flush();
}
return $this->render(':form:comment.html.twig', array(
'form' => $form->createView(),
));
}
and i just want to make some function to make controller more beautiful any ideas? if you give me and example how can i insert my data into database via custom repository function. I know how to make custom query thats all. Every help/idea is very helpfull!
From here
Doctrine 2 ORM does not support INSERT via DQL or the DQL query builder. For a complete syntax, check the EBNF of DQL.
You can add more abstractions if you want your controller to look slightly more beautiful, off the top of my head (effective in Symfony 2.8):
BaseController.php:
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
abstract class BaseController extends Controller
{
/**
* #return ProductRepository
*/
protected function getProductRepo()
{
return $this->get('doctrine.orm.entity_manager')->getRepository(Product::class);
}
}
CommentController.php:
Use native controller functions to create a form and get the currently logged in user. And if you are not intend to add more complex logic between $form->isSubmitted() and $form->isValid() use just $form->isValid()
class CommentController extends BaseController
{
public function newAction(Request $request, $productId)
{
$comment = new Comment();
$form = $this->createForm(CommentForm::class, $comment);
$form->handleRequest($request);
if ($form->isValid()) {
/** #var Product $product */
$product = $this->getProductRepo()->find($productId);
$comment->setAuthor($this->getUser());
$comment->setProduct($product);
$comment->setContent($form->get('content')->getData());
$this->em->persist($comment);
$this->em->flush();
}
return $this->render(':form:comment.html.twig', array(
'form' => $form->createView(),
));
}
}
I am using Doctrine 2.4.6 in my Symfony 2.6.1 project. The problem is that changes made to entity in preUpdate callback are not saved in database. Code follows:
class MyListener {
public function preUpdate(PreUpdateEventArgs $args) {
$entity = $args->getEntity();
$args->setNewValue('name', 'test');
// echo $args->getNewValue('name'); --> prints 'test'
}
}
class DefaultController extends Controller {
/**
* #Route("/commit", name="commit")
*/
public function commitAction(Request $request) {
$content = $request->getContent();
$serializer = $this->get('jms_serializer');
/* #var $serializer \JMS\Serializer\Serializer */
$em = $this->getDoctrine()->getManager();
/* #var $em \Doctrine\Orm\EntityManagerInterface */
$persons = $serializer->deserialize($content, 'ArrayCollection<AppBundle\Entity\Person>', 'json');
/* #var $persons \AppBundle\Entity\Person[] */
foreach($persons as $person) {
$em->merge($person);
}
$em->flush();
return new JsonResponse($serializer->serialize($persons, 'json'));
// Person name is NOT 'test' here.
}
}
The preUpdate doesn't allow you to make changes to your entities. You can only use the computed change-set passed to the event to modify primitive field values. I bet if you check the database you'll see that the Person entities did get updated, you just won't see them in the $persons variable until the next time you manually retrieve them.
What you'll have to do after the flush is retrieve the entities from the database to see their updates values:
$em->flush();
$personIds = array_map(function($person) { return $person->getId(); }, $persons);
$updatedPersons = $em->getRepository('AppBundle:Person')->findById($personIds);
return new JsonResponse($serializer->serialize($updatedPersons, 'json'));
I have a many-to-many relationship between users (the owning side) and user groups, and am having issues using doctrine module's hydrator to create a new user group.
When I create a new user group and hydrate, persist, and flush it, the records change in the database, but the entity variable itself representing the user group doesn't end up with any users in it post-hydration.
Context: We have a REST controller route that we use to create a new user group via POST. It accepts parameters to initialize it with some users via hydration. This operation successfully updates the database, but its response is incorrect. It is supposed to extract the data from the now-persistent entity and echo it back to the client. However, it fails to extract any users, so the response incorrectly returns as an empty group. Not using the hydrator's extract method and instead using more basic doctrine commands fails too--it seems like the entity variable itself is just not kept up to date after being persisted.
So my question really is: why is the hydrator not extracting users? If we've messed up the owner/inverse assocation, why is it working at all (i.e. persisting the users to the database but not to the entity).
Here is the relevant code, probably only the first two blocks are needed.
public function create($data) {
...
$hydrator = $this->getHydrator();
$em = $this->getEntityManager();
$entity = $this->getEntity();
$entity = $hydrator->hydrate($data, $entity);
// Persist the newly created entity
$em->persist($entity);
// Flush the changes to the database
$em->flush();
return $this->createResponse(
201,
true,
'Created item',
$this->getHydrator()->extract($entity)
);
Here is are the setters and getters the hydrator is using:
... more fields...
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="groups")
*/
protected $users;
...
/**
* Getter for users
*
* #return mixed
*/
public function getUsers() {
return $this->users;
}
public function addUsers(Collection $users) {
foreach ($users as $user) {
$user->addGroups(new ArrayCollection(array($this)));
}
}
I think the above is the only relevant code, but I'll include some more in case I'm wrong. Here is the getHydrator method:
public function getHydrator() {
if(null === $this->hydrator) {
$hydrator = new DoctrineObject($this->getEntityManager(), $this->getEntityName());
// Use Entity metadata to add extraction stategies for associated fields
$metadata = $this->em->getClassMetadata($this->getEntityName());
foreach ($metadata->associationMappings as $field => $mapping) {
// Use our custom extraction strategies for single and collection valued associations
if($metadata->isSingleValuedAssociation($field)) {
$hydrator->addStrategy($field, new RestfulExtractionStrategy());
}
else if($metadata->isCollectionValuedAssociation($field)) {
$hydrator->addStrategy($field, new RestfulExtractionCollectionStrategy());
}
}
$this->hydrator = $hydrator;
}
return $this->hydrator;
}
Here is the RestfulExtractionCollectionStrategy (the other strategy isn't being used here, I have verified this).
namespace Puma\Controller;
use DoctrineModule\Stdlib\Hydrator\Strategy\AllowRemoveByValue;
use Doctrine\Common\Collections\Collection;
/**
* You can use this strategy with fields that are collections,
* e.g. one to many. You need to use the RestfulExtractionStrategy
* if you want to get extract entities from a singleton field, e.g. manyToOne.
**/
class RestfulExtractionCollectionStrategy extends AllowRemoveByValue
{
public function extract($value)
{
if ($value instanceof Collection) {
$return = array();
foreach ($value as $entity) {
if(method_exists($entity, 'getId')){
$return[] = $entity->getId();
}
else {
$return[] = $entity;
}
}
return $return;
}
return $value;
}
}
I am not quite familiar with hydration, etc., so your code looks kind of strange to me and I cannot guarantee this will work, but have you tried to refresh the entity after flushing (i.e. $em->refresh($entity)) and maybe return the entity instead of $this->getHydrator()->extract($entity)?
I think I've finally solved it--I added a line to the "setter" method, addUsers which manually updates the users property of the group after updating the related users. I would be a bit surprised if this was best practice, though. I had thought that updating the owning side (the users) would automatically update the inverse side (the user group). Perhaps I was wrong. If anyone else has a better idea I'll gladly give the answer credit to them.
public function addUsers(Collection $users) {
foreach ($users as $user) {
$user->addGroups(new ArrayCollection(array($this)));
// This is the new line (updating the usergroup property manually)
$this->users->add($user);
}
}
If I var_dump($object), the field status is updated in the object, but not saved in database.
Can you help me ?
<?php
namespace Acme\MyBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
class SoftDeleteListener {
public function preSoftDelete(LifecycleEventArgs $args){
$em = $args->getEntityManager();
$object = $args->getEntity();
//if entity has field "status"
if($em->getClassMetadata(get_class($object))->hasField('status')){
//set the status with string "deleted"
$object->setStatus('deleted');
}
}
}
?>
You should persist your object and notify the UoW that you have made some changes. You can achieve that adding this in your condition:
$em->persist($object);
$classMetadata = $em->getClassMetadata(get_class($object));
$em->getUnitOfWork()->computeChangeSet($classMetadata, $object);