best practice of Symfony controllers - symfony

I'm looking for best practice in symfony controller logic. My current code
have one controller:
<?php
namespace App\Controller;
use App\Entity\Categories;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class Controller extends AbstractController
{
/**
* #Route("/", name="main_index")
*/
public function index()
{
$categories = $this->getDoctrine()
->getRepository(Categories::class)
->findAll();
return $this->render('index.html.twig', [
'categories' => $categories,
]);
}
}
categories Entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Categories
*
* #ORM\Table(name="categories", indexes={#ORM\Index(name="title", columns={"title"}), #ORM\Index(name="url", columns={"url"})})
* #ORM\Entity
*/
class Categories
{
/**
* #var bool
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string|null
*
* #ORM\Column(name="title", type="string", length=255, nullable=true, options={"default"="NULL"})
*/
private $title = 'NULL';
/**
* #var string|null
*
* #ORM\Column(name="url", type="string", length=255, nullable=true, options={"default"="NULL"})
*/
private $url = 'NULL';
/**
* #var string|null
*
* #ORM\Column(name="header_text", type="text", length=65535, nullable=true, options={"default"="NULL"})
*/
private $headerText = 'NULL';
/**
* #var string|null
*
* #ORM\Column(name="body_text", type="text", length=65535, nullable=true, options={"default"="NULL"})
*/
private $bodyText = 'NULL';
/**
* #var string|null
*
* #ORM\Column(name="footer_text", type="text", length=65535, nullable=true, options={"default"="NULL"})
*/
private $footerText = 'NULL';
/**
* #var \DateTime|null
*
* #ORM\Column(name="created_at", type="datetime", nullable=true, options={"default"="NULL"})
*/
private $createdAt = 'NULL';
/**
* #var \DateTime|null
*
* #ORM\Column(name="updated_at", type="datetime", nullable=true, options={"default"="NULL"})
*/
private $updatedAt = 'NULL';
public function getId(): ?bool
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
return $this;
}
public function getUrl(): ?string
{
return $this->url;
}
public function setUrl(?string $url): self
{
$this->url = $url;
return $this;
}
public function getHeaderText(): ?string
{
return $this->headerText;
}
public function setHeaderText(?string $headerText): self
{
$this->headerText = $headerText;
return $this;
}
public function getBodyText(): ?string
{
return $this->bodyText;
}
public function setBodyText(?string $bodyText): self
{
$this->bodyText = $bodyText;
return $this;
}
public function getFooterText(): ?string
{
return $this->footerText;
}
public function setFooterText(?string $footerText): self
{
$this->footerText = $footerText;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(?\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
}
I want to repeat "$categories" variable to all my other pages.
So it means - extra query on every page, but I don't want to repeat code:
$categories = $this->getDoctrine()
->getRepository(Categories::class)
->findAll();
everywhere, because all the pages must to show categories all the time. Also by symfony logic all the #route should have own function. So how I suppose to make the route logic and not to repeat the categories request code? by making another outside class with this code and just reuse it in all the other route methods?
EDIT:
My solution:
templates/index.html.twig file (one place):
{{ render(controller('App\\Repository\\CategoriesListRepository::getCategories')) }}
templates/categories.html.twig (one file):
{% for category in categories %}
<li>
{{ category.getName() }}
</li>
{% endfor %}
Repository/CategoriesListRepository.php :
<?php declare(strict_types=1);
namespace App\Repository;
use App\Entity\Categories;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
/**
* Class CategoriesListRepository
* #package App\Repository
*/
final class CategoriesListRepository extends AbstractController
{
/**
* #var \Doctrine\Common\Persistence\ObjectRepository
*/
private $repository;
/**
* CategoriesListRepository constructor.
* #param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(Categories::class);
}
public function getCategories(): Response
{
return $this->render('categories.html.twig', ['categories' => $this->repository->findAll()]);
}
}
would be nice to hear some comments/recommendations

There are several possible solutions. The most obvious one would be to subclass AbstractController, add a protected method getCategories() to it and call that method from all the controller methods where the categories are needed.
But still: this is very repetitive. Therefore, I’d probably add a custom Twig function, so that in any template where it is needed, you just write something like {{ displayCategories() }} or {% for category in getCategories() %} ... {% endfor %}, and the Twig extension handles all that for you. (See Twig docs for more info. This is not difficult. You just have to inject Doctrine as a dependeny to the extension’s constructor and overwrite getFunctions() method from Twig_Extension).

You can call a controller from a template.
Create the controller that renders only list of categories:
public function listAllAction()
{
$categories = $this->getDoctrine()
->getRepository(Categories::class)
->findAll();
return $this->render('categories.html.twig', [
'categories' => $categories,
]);
}
and then call it with render function in a twig file:
<div id="list-of-categories">
{{ render(controller(
'App:Category:listAll',
)) }}
</div>

Take a look at How to Inject Variables into all Templates (i.e. global Variables).
You would create the following config:
# config/packages/twig.yaml
twig:
# ...
globals:
# the value is the service's id
category_service: '#App\Service\CategoryService'
And in your CategoryService you would get all categories within a getCategories() method. Later on you can call in your twig template category_service.getCategories().

You can have $categories as a container's variable by using $container->set() method and then get the variable with $container->get('categories').

If you only want to avoid repeating the code (have the a code copy on different places), the previous answers may fit. But if you wan't to not execute your repository calls over and over again with the goal to optimize database performance, in my opinion its no good practice to move code to places which are not responsible for (e.g. twig global variables).
Even if the result may be always the same over different pages, it could also be that different results return yet. But thats something you should not be worry about.
Instead i would go for using the doctrine result cache for my queries. The cache should decide whether the requested data is the same as in the previous request or not and give me the data.
As long as you are using doctrine and no DBAL you will be fine with this.

Related

Using DoctrineBehaviors translatable in Symfony 4?

I'm trying to use the DoctrineBehaviors translatable extension in Symfony 4.Just setup a test following the documentation example:
translatable entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #ORM\Entity(repositoryClass="App\Repository\FAQRepository")
*/
class FAQ
{
use ORMBehaviors\Translatable\Translatable;
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
protected $id;
/.**
* #ORM\Column(type="datetime", nullable=true)
*/
protected $updatedAt;
public function getId(): ?int
{
return $this->id;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
}
translation entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #ORM\Entity
*/
class FAQTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #ORM\Column(type="text")
*/
protected $question;
/**
* #ORM\Column(type="text")
*/
protected $answer;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $category;
public function getQuestion(): ?string
{
return $this->question;
}
public function setQuestion(string $question): self
{
$this->question = $question;
return $this;
}
public function getAnswer(): ?string
{
return $this->answer;
}
public function setAnswer(string $answer): self
{
$this->answer = $answer;
return $this;
}
public function getCategory(): ?int
{
return $this->category;
}
public function setCategory(?int $category): self
{
$this->category = $category;
return $this;
}
}
Testing the translatable entity:
/**
* #Route("/test", name="test")
*/
public function testfaq()
{
$em = $this->getDoctrine()->getManager();
$faq = new FAQ();
$faq->translate('fr')->setQuestion('Quelle est la couleur ?');
$faq->translate('en')->setQuestion('What is the color ?');
$em->persist($faq);
$faq->mergeNewTranslations();
$em->flush();
return $this->render('app/test.html.twig', [
]);
}
A new ID is added in the faq table.
But nothing is persisted in the faqtranslation table.
Bundles.php :
Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle::class => ['all' => true],
All the documentations I found seem to refer to Symfony 3 or even Symfony 2, is it possible to use DoctrineBehaviors translatable in Symfony 4 ?
I don't know if you found your answer since (I hope you did), but yes you can use KnpLabs/DoctrineBehaviors with Symfony 4. Maybe, you just needed to wait a little longer for an update.

Selecting If One Row From Entity Exists in Symfony / Twig

I am making a web app using Symfony 4.
The app has (among others) a User entity, Post entity, and a PostLike entity. A user can create many posts, and a post can have many likes. So PostLike references User and Post. Below is my PostLike entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #ORM\Entity(repositoryClass="App\Repository\PostLikeRepository")
*/
class PostLike
{
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="postLikes")
* #ORM\JoinColumn(nullable=true)
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Post", inversedBy="postLikes")
* #ORM\JoinColumn(nullable=true)
*/
private $post;
/**
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getUser()
{
return $this->user;
}
/**
* #param mixed $user
*/
public function setUser($user): void
{
$this->user = $user;
}
/**
* #return mixed
*/
public function getPost()
{
return $this->post;
}
/**
* #param mixed $post
*/
public function setPost($post): void
{
$this->post = $post;
}
public function getCreatedAt()
{
return $this->createdAt;
}
}
When I am on the view page for an individual post, how would I reference whether a user has liked this post in TWIG? This will be the ‘many’ side of the relationship, but I just need one row (if it exists), and I’m not sure how to do this...
TIA.
In the controller you can check whether such PostLike with such user and post exist or not and pass it to the view:
$liked = false;
$postLike = $this->getDoctrine()->getManager()->getRepository('AppBundle:PostLike')->findOneBy(['user'=>$user->getId(),'post'=>$post->getId()]);
if($postLike !== null){
$liked = true;
}
If you want to simply show whether Likes exist you can add a field to the Post entity:
public function hasLikes()
{
return (0 === count($this->likes)) ? false : true;
}
and include in twig something like {% if post.hasLikes %}Liked{% endif %}.
You could do something similar with a count and a badge to show the number of likes.

Controller, repo and twig print array (Symfony3)

I need to print domains of a single user
ENTITY (here is the entity code)
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Domini
*
* #ORM\Table(name="domini")
* #ORM\Entity(repositoryClass="AppBundle\Repository\DominiRepository")
*/
class Domini
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="id_user", type="integer")
*/
private $idUser;
/**
* #var string
*
* #ORM\Column(name="dominio", type="string", length=100, unique=true)
*/
private $dominio;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set idUser
*
* #param integer $idUser
*
* #return Domini
*/
public function setIdUser($idUser)
{
$this->idUser = $idUser;
return $this;
}
/**
* Get idUser
*
* #return int
*/
public function getIdUser()
{
return $this->idUser;
}
/**
* Set dominio
*
* #param string $dominio
*
* #return Domini
*/
public function setDominio($dominio)
{
$this->dominio = $dominio;
return $this;
}
/**
* Get dominio
*
* #return string
*/
public function getDominio()
{
return $this->dominio;
}
}
REPOSITORY (here is the Repo code)
<?php
namespace AppBundle\Repository;
use AppBundle\Entity\Domini;
use Doctrine\ORM\EntityRepository;
class DominiRepository extends \Doctrine\ORM\EntityRepository
{
/**
* #return dominio[]
*/
public function findAllPublishedOrderedBySize()
{
$query = 'SELECT dominio FROM AppBundle:Domini dominio';
$mydomain = $this->getEntityManager()->createQuery($query);
return $mydomain->execute();
}
}
CONTROLLER
<?php
// src/AppBundle/Controller/DominiController.php
namespace AppBundle\Controller;
use AppBundle\Entity\Domini;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Doctrine\ORM\EntityManagerInterface;
class DominiController extends Controller
{
/**
* #Route("/admin/domini")
*/
public function dominiAction()
{
$title = "ADMIN";
$nome_utente = $this->getUser();
$user = $this->getUser()->getId();
$em = $this->getDoctrine()->getManager();
$dominilist = $em->getRepository('AppBundle:Domini')
->findAllPublishedOrderedBySize();
return $this->render('admin/domini.html.twig', [
'title' => $title,
'nome_utente' => $nome_utente,
'user' => $user,
'dominilist' => $dominilist,
]);
}
}
TWIG
<h1>{{ title }}</h1>
<h2>Benvenuto: {{ nome_utente }}</h2>
<h3>USER ID:{{ user }}</h3>
<ul>
{% for item in dominilist %}
<li>{{ item.dominio }}</li>
{% endfor %}
</ul>
MYSQL TABLE
table name: domini
fields: id, id_user, dominio
Now all works fine but 'dominilist' => $dominilist doesn't work. Dominio is the domain name saved under "dominio". Why?
IF i try to cicle this field it doesn't work.
If you want to select all the data stored in that table, you can use a quick and handy method directly in your controller
# Controller
$dominilist = $em->getRepository('AppBundle:Domini')
->findAll();
Or you can find domini by id in the controller too:
# Controller
$user = $this->getUser()->getId();
$dominilist = $em->getRepository('AppBundle:Domini')->findBy(['id'=>$user]);
And only if you want to have a more complex query, then you can create q method in the repository. As that "I need to print domains of a single user"
# Repository
public function findAllPublishedOrderedBySize($id)
{
$qb = $this->createQueryBuilder('d');
$qb
->select('d.dominio')
->where('d.id = :id')
->setParameter('id', $id)
;
return $qb->getQuery()->getResult();
}
# Controller
$user = $this->getUser()->getId();
$domini = $em->getRepository('AppBundle:Domini')
->findAllPublishedOrderedBySize($user);
Anyway, those type of queries are small, and you can create them in the controller, as I showed you above.

Symfony 3.3: unable to add and remove items of the same entity with collection form type

I am new to Symfony, so I started with the official tutorial, installed Symfony framework 3.3.2 and worked through the tutorial while customizing entities, controllers, forms and views to my specific needs.
So basically I have an entity named BasePreset, there are already a couple of rows in the DB, and I finally have managed to create a form collection type that renders a list of editable BasePreset entity fields with 'add' and 'remove' links: the 1st adds new blank fields to the list, and every 'remove' link removes the corresponding fields from DOM. Everything according to docs.
So I succeed to update the existing fields (I see the right changes in form HTML after reloading and in the DB as well).
The problem is, add/delete not working. No errors given. Checked in Chrome Dev tools: parameters sent as expected.
I used the following documentation (and a lot of googling of course) regarding the form builder:
http://symfony.com/doc/current/forms.html
https://symfony.com/doc/current/best_practices/forms.html
https://symfony.com/doc/current/form/form_collections.html
https://symfony.com/doc/current/reference/forms/types/collection.html
Now, in this doc is stated:
You have to create both addTag() and removeTag() methods, otherwise
the form will still use setTag() even if by_reference is false. You'll
learn more about the removeTag() method later in this article.
At this moment I don't have any referenced subentity as it is described in the examples. I just want be able to edit the same plain entity, including adding new items and deleting existing. Maybe I'm wrong, but this seems as kind of a trivial basic goal in my mind. I don't understand how to properly add 'setBasePreset' and 'removeBasePreset' methods to the 'BasePreset' entity itself.
Of course I can skip using the form builder, but I'd like to leverage its power as a part of the framework. Any advice, example, maybe pointing to some relevant doc/tutorial that I missed - will be greatly appreciated.
Post example (with one addition and one removal):
base_presets[base_presets][5][name]:new_preset
base_presets[base_presets][5][description]:new, not really added
base_presets[base_presets][0][name]:ffffas44432df
base_presets[base_presets][0][description]:asdfffff2333
base_presets[base_presets][2][name]:ffffasdf2222
base_presets[base_presets][2][description]:asdff3fff2333
base_presets[base_presets][3][name]:yoyoshka
base_presets[base_presets][3][description]:nananaf
base_presets[base_presets][4][name]:123fffdsaasdf
base_presets[base_presets][4][description]:pop123
base_presets[_token]:H2QwRHdvZW1WAdc6VTONnspxvH1U-oC8rCEEprDdMCQ
The 'BasePresetsType' class:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class BasePresetsType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('base_presets', CollectionType::class, array(
'entry_type' => BasePresetType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false // also tried 'true' but without any success
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => null,
));
}
}
The 'BasePresetType' class:
<?php
namespace AppBundle\Form;
use AppBundle\Entity\BasePreset;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
class BasePresetType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', TextType::class)
->add('description', TextareaType::class);
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => BasePreset::class,
]);
}
}
The controller method:
<?php
// ...
/**
* #Route("/admin/list_base_presets", name="list_base_presets")
*/
public function listBasePresetsAction(Request $request, EntityManagerInterface $em, LoggerInterface $logger) {
$base_presets = $em->getRepository("AppBundle\Entity\BasePreset")->findAll();
$form = $this->createForm(BasePresetsType::class, array('base_presets' => $base_presets));
$form->handleRequest($request);
$current_route = $request->get('_route');
if ($form->isSubmitted() && $form->isValid()) {
foreach ($base_presets as $base_preset) {
$em->persist($base_preset);
}
$em->flush();
// ... do other work - like sending an email, etc..
// maybe set a 'flash' success message for the user
return $this->redirectToRoute($current_route);
}
return $this->render('manage_params/list_base_presets.html.twig', array(
'form' => $form->createView()
));
}
The view:
{% extends "base.html.twig" %}
{% block body %}
{{ form_start(form) }}
{{ form_label(form.base_presets) }}
{{ form_errors(form.base_presets) }}
<ul class="base-presets" data-prototype="{{ form_widget(form.base_presets.vars.prototype)|e('html_attr') }}">
{% for base_preset in form.base_presets %}
<li class="base-preset-item">
{{ form_errors(base_preset) }}
{{ form_widget(base_preset) }}
</li>
{% endfor %}
<li class="form-submit">
<input type="submit" value="Submit" class="btn btn-default pull-right" />
</li>
</ul>
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
<script>
var $collection_holder;
// Setup an "add a base preset" link
var $add_base_preset_link = $('Add a base preset');
var $new_link_li = $('<li></li>').append($add_base_preset_link);
$(document).ready(function () {
// Get the ul that holds the collection of base presets
$collection_holder = $('ul.base-presets');
// add the "add a base preset" anchor and li to the tags ul
$collection_holder.prepend($new_link_li);
// count the current form inputs we have, use that as the new index when inserting a new item
$collection_holder.data('index', $collection_holder.find('li.base-preset-item').length);
$add_base_preset_link.on('click', function (e) {
e.preventDefault();
addBasePresetForm($collection_holder, $new_link_li);
});
// add a delete link to all of the existing base presets form li elements
$collection_holder.find('li.base-preset-item').each(function () {
addBasePresetFormDeleteLink($(this));
});
});
function addBasePresetForm($collection_holder, $new_link_li) {
// Get the data-prototype
var prototype = $collection_holder.data('prototype');
// Get the new index
var index = $collection_holder.data('index');
// Replace '__name__' in the prototype's HTML to instead be a number based on how many items we have
var new_form = prototype.replace(/__name__/g, index);
// increment the index for the next item
$collection_holder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a base preset" link li
var $new_form_li = $('<li class="base-preset-item"></li>').append(new_form);
$new_link_li.after($new_form_li);
addBasePresetFormDeleteLink($new_form_li);
}
function addBasePresetFormDeleteLink($base_preset_form_li) {
var $remove_form_a = $('Delete this base preset');
$base_preset_form_li.append($remove_form_a);
$remove_form_a.on('click', function (e) {
e.preventDefault();
$base_preset_form_li.remove();
})
}
</script>
{% endblock %}
And, finally, the longest listing - the 'BasePreset' entity class:
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* Class BasePreset
* #package AppBundle\Entity
*
* #ORM\Entity
* #ORM\Table(name="base_presets")
* #UniqueEntity(fields="name", message="There should be only one (unique) base preset")
*/
class BasePreset {
/**
* #ORM\OneToMany(targetEntity="BaseParamsGroup", mappedBy="base_preset")
*/
private $base_params_groups;
/**
* #var int
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* #var string
*
* #Assert\NotBlank()
* #ORM\Column(type="string", length=4000)
*/
private $description;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime")
*/
private $created;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", columnDefinition="TIMESTAMP on update CURRENT_TIMESTAMP")
*/
private $updated;
public function __construct() {
$this->base_params_groups = new ArrayCollection();
$this->created = new \DateTime();
$this->updated = new \DateTime();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return BasePreset
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* #param string $description
*
* #return BasePreset
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set created
*
* #param \DateTime $created
*
* #return BasePreset
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* #param \DateTime $updated
*
* #return BasePreset
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Add baseParamsGroup
*
* #param \AppBundle\Entity\BaseParamsGroup $baseParamsGroup
*
* #return BasePreset
*/
public function addBaseParamsGroup(\AppBundle\Entity\BaseParamsGroup $baseParamsGroup)
{
$this->base_params_groups[] = $baseParamsGroup;
return $this;
}
/**
* Remove baseParamsGroup
*
* #param \AppBundle\Entity\BaseParamsGroup $baseParamsGroup
*/
public function removeBaseParamsGroup(\AppBundle\Entity\BaseParamsGroup $baseParamsGroup)
{
$this->base_params_groups->removeElement($baseParamsGroup);
}
/**
* Get baseParamsGroups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getBaseParamsGroups()
{
return $this->base_params_groups;
}
}
Since you use form without Data class, you need to access submitted data directly from form object:
foreach ($form->get('base_presets')->getData() as $base_preset) {
$em->persist($base_preset);
}
Update:
That work with managing existing and persisting new ones. If you need to remove entities, you can compare entities loaded from DB with submitted ones, and then remove filtered.

new entity not detected

I created a new entity in an entity folder where I already have some other used entity. However this new entity is not detected by doctrine:mapping:info nor doctrine:schema:validate
It appears the file is simply not taken into account (if I write an error inside symfony is executed without issue).
I was thinking about a VM system issue but then I tried to create other new files (such as a new YML,a new symfony form) and it works...
I also cleared the cache:clear and doctrine:cache:all options
here is the class:
<?php
namespace NRtworks\BusinessDimensionBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use JsonSerializable;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Table(name="test")
*/
class test implements JsonSerializable
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=50)
*/
protected $name;
/**
* #ORM\Column(type="string", length=100)
*/
protected $description;
/**
* Constructor
*/
public function __construct($id = NULL)
{
$this->id = $id;
$this->name = "Chart Of Accounts";
$this->description = "Default chart of accounts";
}
//this method returns an array with default values
public function getDefaultObject()
{
$result = Array();
$result['id'] = $this->id;
$result['name'] = $this->name;
$result['description'] = $this->code;
return $result;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
/**
* Set name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*/
public function getName()
{
return $this->name;
}
/**
* Set code
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* Get description
*/
public function getDescription()
{
return $this->description;
}
public function jsonSerialize()
{
return array(
'id' => $this->id,
'name' => $this->name,
'description' => $this->description
);
}
}
?>
where could this come from ?
You need to define #ORM\Entity annotation for your class:
/**
* #ORM\Entity
* #ORM\Table(name="test")
*/
class test implements JsonSerializable
{

Resources