multiple not mapped hidden input symfony2 - symfony

I have an article entity. When I create an article, I want to be able to add zero to n images to it.
To do so, I upload files with a jQuery plugin in a temporary directory, and add an <input type=hidden> to my form, with the file's full path as value.
It works fine when there is no validation error. But when there is, I got an error saying:
An exception has been thrown during the rendering of a template ("Notice: Array to string conversion") in form_div_layout.html.twig at line 13
And I'm pretty sure it's because it tries to do this :
ErrorHandler ->handleError ('8', 'Array to string conversion', '/var/www/project/app/cache/dev/twig/47/a4/ac9a00176739f843e919f5f89883191930038a6e0aaa218869e4966ab7c6.php', '175', array('context' => array('value' => array('njm4uqsa9y6#54edfdaedd0736w3wstk.jpeg'),...
Here is my formType :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('content')
->add('maxVote')
->add('expireAt', 'datetime', array(
'widget' => 'single_text',
'input' => 'string',
'format' => 'dd-mm-yyyy',
)
)
->add('category', 'entity', array(
'class' => 'AppBundle:StoryCategory',
'required' => true
)
)
->add('answers', 'collection', array(
'type' => new AnswerType()
)
)
->add('visibility', 'choice', array(
'choices' => array(1 => "label.public", 2 => "label.semiprivate", 3 => "label.private"),
'expanded' => false,
'multiple' => false
)
)
->add('attachment', 'hidden', array(
'mapped' => false,
'required' => false
)
)
->add('save', 'submit')
;
}
Do you have any idea what is happening, or what should I do ?
Edit:
The form is empty. I create a new instance of Story
$story = new Story();
$form = $this->createForm(new StoryType(), $story);
And when I submit the form I do
$form->handleRequest($request);
Edit 2:
Story.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Story
*
* #ORM\Table(name="story")
* #ORM\Entity(repositoryClass="AppBundle\Repository\StoryRepository")
*/
class Story
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
* #Assert\NotBlank()
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="content", type="text")
* #Assert\NotBlank()
*/
private $content;
/**
* #var string
*
* #ORM\Column(name="token", type="string", length=70, unique=true)
*/
private $token;
/**
* #var \DateTime
*
* #ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updated_at", type="datetime")
*/
private $updatedAt;
/**
* #var \DateTime
*
* #ORM\Column(name="expire_at", type="datetime")
* #Assert\NotBlank()
*/
private $expireAt;
/**
* #var string
*
* #ORM\Column(name="author_ip", type="string", length=50, nullable=true)
*/
private $authorIp;
/**
* #var integer
*
* #ORM\Column(name="max_vote", type="integer", nullable=true)
* #Assert\Type(type="integer")
* #Assert\Range(
* min = 0,
* max = 20000,
* minMessage = "validation.story.maxvote.min",
* maxMessage = "validation.story.maxvote.max"
* )
*/
private $maxVote;
/**
* #var integer
*
* #ORM\Column(name="nb_vote", type="integer")
*/
private $nbVote;
/**
* #var integer
* 1 = public, 2 = semi-private, 3 = private (only invited members)
*
* #ORM\Column(name="visibility", type="integer")
*
*/
private $visibility;
/**
* #var boolean
*
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
/**
* #var StoryCategory
*
* #ORM\ManyToOne(targetEntity="StoryCategory", inversedBy="stories")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
* })
* #Assert\NotNull()
*/
private $category;
/**
* #ORM\OneToMany(targetEntity="Answer", mappedBy="story", cascade={"persist", "remove"})
* #Assert\Count(
* min = "2",
* max = "4",
* minMessage = "validation.story.answer.min",
* maxMessage = "validation.story.answer.max",
* groups={"premium"}
* )
* #Assert\Count(
* min = "2",
* max = "2",
* minMessage = "validation.story.answer.min",
* maxMessage = "validation.story.answer.max",
* )
*/
private $answers;
/**
* #ORM\OneToMany(targetEntity="Attachment", mappedBy="story", cascade={"persist", "remove"})
*/
private $attachments;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="stories")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $author;
public function __construct()
{
$datetime = new \DateTime();
$this->createdAt = $datetime;
$this->updatedAt = $datetime;
$this->token = base_convert(time(), 10, 36).\AppBundle\Library\StringHelper::randomString();
$this->isActive = false;
$this->nbVote = 0;
}
}
Twig view :
{% extends '::base.html.twig' %}
{% block basecontent %}
{{ form_errors(form) }}
{{ form_start(form, {attr: {id: 'story-form', novalidate: 'novalidate'}}) }}
{{ form_row(form.title) }}
{{ form_row(form.content) }}
{{ form_row(form.category) }}
<h3>Les choix de réponses possibles</h3>
{% for answer in form.answers %}
{{ form_widget(answer) }}
{% endfor %}
{{ form_row(form.visibility) }}
{{ form_row(form.expireAt) }}
{% for attachement in form.attachment %}
{{ form_row(attachment) }}
{% endfor %}
{{ form_end(form) }}
{# upload zone #}
<div class="upload-block">
<form action='{{ path('story_file_upload') }}' id="dropzone" class="dropzone">
</form>
</div>
{% endblock basecontent %}
This is what I add with javascript :
$("#story-form").append('<input type="hidden" name="story_form[attachment][]" value="'+response.filename+'"/>');
So I tried without it being an array (I removed the ending [] in the name), and it works. So I assume the problem comes from that, I have to tell the formType that it's an array. But how ?
Thank you

I couldn't make it work, so I removed the "attachments" field from the formType.
When I upload a file, I then add using javascript an <input type="hidden"> with a name that does not match the fields from the formType.
For example, the fields generated by Symfony are named story_form['name']. I just named mine attachments[]. That way Symfony doesn't tell me that there is an extra field.
In my controller I get the values with $request->request->get('attachments').
There probably is a better way to do it, but I haven't found it.

You're using in your vew:
{% for attachement in form.attachment %}
{{ form_row(attachment) }}
{% endfor %}
Where your declaring attachment as an hidden field:
->add('attachment', 'hidden', array(
'mapped' => false,
'required' => false
)
)
A hidden field is no more than a string stored in an <input type="hidden">, you can't iterate through it.

Related

Translations not working with Symfony 3.3, KNP Doctrine Behaviors & Sonata Admin

Could someone explain me what i am doing wrong. I have an entity with classes Actualite and ActualiteTranslation.
I created ActualiteAdmin class with sonanta:admin:generate.
Everything is working as expected. I debug fields with dump($actualite) in the controller and i see that each fields are well displayed :
array:1 [▼
0 => Actualite {#742 ▼
-id: 8
-date: DateTime {#806 ▶}
-image: null
#translations: PersistentCollection {#709 ▼
-snapshot: array:1 [ …1]
-owner: Actualite {#742}
-association: array:16 [ …16]
-em: EntityManager {#789 …11}
-backRefFieldName: "translatable"
-typeClass: ClassMetadata {#738 …}
-isDirty: false
#collection: ArrayCollection {#662 ▼
-elements: array:1 [▼
"fr" => ActualiteTranslation {#705 ▼
#actucategorie: "categorie"
#alt: "image"
#titre: "Page Facebook"
#article: "mon article"
#id: 4
#locale: "fr"
#translatable: Actualite {#742}
#slug: "page-facebook"
}
]
}
#initialized: true
}
#newTranslations: null
#currentLocale: "fr"
#defaultLocale: "fr"
}
]
I have thir error in Twig Template when using {{actualite.translations.titre}}:
Key "translations" for array with keys "0" does not exist.
This is the code I use :
namespace BDN\ActualitesBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* Actualite
*
* #ORM\Table(name="bdn_actualite")
* #ORM\Entity(repositoryClass="BDN\ActualitesBundle\Repository\ActualiteRepository")
*
*/
class Actualite
{
use ORMBehaviors\Translatable\Translatable;
/**
* #param $method
* #param $args
*
* #return mixed
*/
public function __call($method, $args)
{
if (!method_exists(self::getTranslationEntityClass(), $method)) {
$method = 'get' . ucfirst($method);
}
return $this->proxyCurrentLocaleTranslation($method, $args);
}
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var string
*
* #ORM\Column(name="image", type="string", length=255, nullable=true)
*/
private $image;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set date
*
* #param \DateTime $date
*
* #return null
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set image
*
* #param string $image
*
* #return null
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string
*/
public function getImage()
{
return $this->image;
}
}
namespace BDN\ActualitesBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* ActualiteTranslation
*
* #ORM\Entity
* #ORM\Table(name="bdn_actualite_translation")
*
*/
class ActualiteTranslation
{
use ORMBehaviors\Translatable\Translation;
use ORMBehaviors\Sluggable\Sluggable;
/**
* #var string
*
* #ORM\Column(name="actucategorie", type="string", length=50)
*/
protected $actucategorie;
/**
* #var string
*
* #ORM\Column(name="alt", type="string", length=255)
*/
protected $alt;
/**
* #var string
*
* #ORM\Column(name="titre", type="string", length=255, unique=true)
*/
protected $titre;
public function getSluggableFields()
{
return ['titre'];
}
/**
* #var string
*
* #ORM\Column(name="article", type="text")
*/
protected $article;
/**
* Set actucategorie
*
* #param string $actucategorie
*
* #return ActualiteTranslation
*/
public function setActucategorie($actucategorie)
{
$this->actucategorie = $actucategorie;
return $this;
}
/**
* Get actucategorie
*
* #return string
*/
public function getActucategorie()
{
return $this->actucategorie;
}
/**
* Set alt
*
* #param string $alt
*
* #return ActualiteTranslation
*/
public function setAlt($alt)
{
$this->alt = $alt;
return $this;
}
/**
* Get alt
*
* #return string
*/
public function getAlt()
{
return $this->alt;
}
/**
* Set titre
*
* #param string $titre
*
* #return ActualiteTranslation
*/
public function setTitre($titre)
{
$this->titre = $titre;
return $this;
}
/**
* Get titre
*
* #return string
*/
public function getTitre()
{
return $this->titre;
}
/**
* Set article
*
* #param string $article
*
* #return ActualiteTranslation
*/
public function setArticle($article)
{
$this->article = $article;
return $this;
}
/**
* Get article
*
* #return string
*/
public function getArticle()
{
return $this->article;
}
}
<!-- begin snippet: js hide: false console: true babel: false -->
<?php
namespace BDN\ActualitesBundle\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use A2lix\TranslationFormBundle\Form\Type\TranslationsType;
class ActualiteAdmin extends AbstractAdmin
{
/**
* #param DatagridMapper $datagridMapper
*/
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('id')
->add('date')
->add('image')
;
}
/**
* #param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('id')
->add('date')
->add('image')
->add('_action', null, array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
),
))
;
}
/**
* #param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('date')
->add('image')
->add("translations", TranslationsType::class, array(
"fields" => array(
"actucategorie" => [],
"alt" => [],
"titre" => [],
"slug" => ["display" => false,],
"article" => [ "field_type" => "text"],
),
))
;
}
/**
* #param ShowMapper $showMapper
*/
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
->add('id')
->add('date')
->add('image')
->add("translations", TranslationsType::class, array(
"required_locales" => ['fr'],
"fields" => array(
"actucategorie" => [],
"alt" => [],
"titre" => [],
"article" => [ "field_type" => "text"],
),
))
;
}
}
{% extends "::base.html.twig" %}
{% block page %}
<section class="row jumbotron">
<div class="col-lg-12">
<div class="row">
<div class="col-xs-9">
<h3>{{ actualite.getTitre() }}</h3>
<p class="categorie">Le {{ actualite.date | date('d/m/Y') }} | Catégorie : {{ actualite.translate.actucategorie }}</p>
</div>
{% if actualite.image is not null %}
<div class="col-xs-3 hidden-xs">
<img src="{{ asset('actualite.image') }}" class="img-thumbnail img-shop" alt="{{ actualite.alt }}">
</div>
{% endif %}
</div>
<div class="row content-actualite">
<div class="col-lg-12">
{{ actualite.translate.article }}
</div>
</div>
</div>
</section>
{% endblock %}
Any help would be very appreciated!
Denis

Symfony2 OneToMany relation

I'm doing an AdvertPlatform with Symfony 2.5 and PHP 5.3.
I want to add a feature that is : when a user see(by clicking on it) an advert, we can see a text "Seen by : {{username}}".
I started add a new Entity nammed AdvertReader with a relation OneToMany between Advert and AdvertReader:
Advert.php:
/**
* Advert
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Society\PerfclientBundle\Entity\AdvertRepository")
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(fields="title", message="Une annonce existe déjà avec ce titre.")
*/
class Advert
{
public function __construct()
{
$this->date = new \Datetime();
}
/**
*
* #ORM\OneToMany(targetEntity="Society\PerfclientBundle\Entity\AdvertReader", mappedBy="advert", cascade={"persist"})
*/
private $readers;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255, unique=true)
*
* #Assert\Length(min=10, minMessage="Le titre de l'annonce doit faire au moins {{ limit }} caractères.")
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="category", type="string", length=255)
*/
private $category;
/**
* #var string
*
* #ORM\Column(name="author", type="string", length=255)
*/
private $author;
/**
* #var string
*
* #ORM\Column(name="content", type="text")
* #Assert\Length(min=10, minMessage="Le contenu de l'annonce doit faire au moins {{ limit }} caractères.")
*/
private $content;
/**
* #ORM\Column(name="updated_at", type="datetime", nullable=true)
*/
private $updatedAt;`
AdvertReader.php :
/**
* AdvertReader
*
* #ORM\Table()
* #ORM\Entity
*/
class AdvertReader
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Society\PerfclientBundle\Entity\Advert", inversedBy="readers")
* #ORM\JoinColumn(name="advert_id", referencedColumnName="id")
*/
private $advert;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255)
*/
private $username;
/**
* #var \DateTime
*
* #ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updated_at", type="datetime")
*/
private $updatedAt;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set advert
*
* #param integer $advert
* #return AdvertReader
*/
public function setAdvert($advert)
{
$this->advert = $advert;
return $this;
}
/**
* Get advert
*
* #return integer
*/
public function getAdvert()
{
return $this->advert;
}
/**
* Set username
*
* #param string $username
* #return AdvertReader
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
And my viewAction()
/**
* #param $id
* #return Response
*/
public function viewAction($id)
{
// On récupère le repository
$repository = $this->getDoctrine()
->getManager()
->getRepository('SocietyPerfclientBundle:Advert')
;
$advert = $repository->find($id);
if (null === $advert) {
throw new NotFoundHttpException("L'annonce d'id ".$id." n'existe pas.");
}
$securityContext = $this->container->get('security.context');
$user = $securityContext->getToken()->getUser();
if ($securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
$em = $this->getDoctrine()->getManager();
$queryBuilder = $em->createQueryBuilder();
$query = $queryBuilder->select('count(ar.id)')
->from('SocietyPerfclientBundle:AdvertReader', 'ar')
->where('ar.advert = :advert')
->andWhere('ar.username = :username')
->setParameter('advert', $advert->getId())
->setParameter('username', $user->getUsername())
->getQuery();
$advertReaderCount = $query->getSingleScalarResult();
if ($advertReaderCount <= 0) {
// l'utilisateur lis pour la 1er fois
$advertReader = new AdvertReader;
$advertReader->setAdvert($advert->getId());
$advertReader->setUpdatedAt(new \DateTime);
$advertReader->setUsername($user->getUsername());
$advertReader->setCreatedAt(new \DateTime);
$em->persist($advertReader);
$em->flush();
}
}
return $this->render('SocietyPerfclientBundle:Default:view.html.twig', array(
'advert' => $advert,
));
}
doctrine:schema:validate -> [Mapping] OK [Database] OK
Error500 ORM Exception : Found entity of type on association Society\PerfclientBundle\Entity\AdvertReader#advert, but expecting Society\PerfclientBundle\Entity\Advert
Stack Trace Profiler :
UnitOfWork ->computeAssociationChanges (array('fieldName' => 'advert', 'joinColumns' => array(array('name' => 'advert_id', 'unique' => false, 'nullable' => true, 'onDelete' => null, 'columnDefinition' => null, 'referencedColumnName' => 'id')), 'cascade' => array(), 'inversedBy' => 'readers', 'targetEntity' => 'Society\PerfclientBundle\Entity\Advert', 'fetch' => '2', 'type' => '2', 'mappedBy' => null, 'isOwningSide' => true, 'sourceEntity' => 'Society\PerfclientBundle\Entity\AdvertReader', 'isCascadeRemove' => false, 'isCascadePersist' => false, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false, 'sourceToTargetKeyColumns' => array('advert_id' => 'id'), 'joinColumnFieldNames' => array('advert_id' => 'advert_id'), 'targetToSourceKeyColumns' => array('id' => 'advert_id'), 'orphanRemoval' => false), '26')
What's wrong with my entity relation ?
Please help me :)
I think the problem comes from this code piece of code
$advertReader->setAdvert($advert->getId());
Try this instead:
$advertReader->setAdvert($advert);
Doctrine is expecting an object on that relation and instead you pass some integer.
Hope this helps. Happy coding
Alexandru Cosoi

I can't do update with an entity in my select symfony 2

$builder
->add('tecnicoId', 'entity', array(
'class' => 'MainHomeBundle:Tecnicos',
'property' => 'nombre',
'expanded' => false,
'multiple' => false
))
->add('cambiar', 'submit')
;
controller
$form = $this->createForm(new ServicioseditType(), $datos);
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->render('MainHomeBundle:Admin:editserv.html.twig', array("form"=>$form->createView()));
view twig
{{ form_errors(form.tecnicoId) }}
{{ form_widget(form.tecnicoId) }}
{{ form_widget(form.cambiar, { 'attr': {'class': 'boton'} }) }}
when I click to make the update get the following error
ContextErrorException: Catchable Fatal Error: Object of class
Main\HomeBundle\Entity\Tecnicos could not be converted to string in
C:\xampp\htdocs\digitalfix\vendor\doctrine\dbal\lib\Doctrine\DBAL\Connection.php
line 784
when I see the detail of sql, I see the value of tecnico_id is empty
An exception occurred while executing 'UPDATE servicios SET tecnico_id
= ? WHERE id = ?' with params [{}, 1]:
the technical entity is a string name
class Tecnicos
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #Assert\NotBlank()
* #Assert\Length(
* min = 8,
* max = 55,
* minMessage = "{{ limit }} caracteres minimo",
* maxMessage = "{{ limit }} caracteres maximo"
* )
*
* #ORM\Column(name="nombre", type="string", length=55, nullable=false)
*/
private $nombre;
public function __toString()
{
return $this->nombre;
}
the service entity is an integer because only the technical id no name is inserted .
class Servicios
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="cliente_id", type="integer", nullable=false)
*/
private $clienteId;
/**
* #var integer
*
* #ORM\Column(name="tecnico_id", type="integer", nullable=true)
*/
private $tecnicoId = 1;
Add this method to your Tecnicos entity:
public function __toString()
{
return $this->name; // could be anything that returns a string, even a string itself (but wouldn't be relevant).
}
Your error is not related to your SQL.
It seems like the Object MainHomeBundle:Tecnicos misses a __toString() method to display the selected entity in your form.
This is what your first error says.
Add a __toString() method to this entity.

Show only user with a specific role in FormFields sonata

Here I am on a project for my studies and I use symfony fosUser and sonata, I have a Book entity that I administer with sonata.
The problem is that I want to give an user to a book, but it becomes complicated when I want to find in my field user only the user whose role ROLE_MyRole, I search on forums for several hours without finding.
I'm sorry for my incompetence I learn symfony recently and does not yet have enough experience.
This is my BookAdmin
class BookAdmin extends Admin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
static $options = array();
$currentBook = $this->getSubject();
if (null !== $currentBook->getFileName())
$options = array(
'required' => false,
'help' => 'getWebPath().'">Download File : '.$currentBook->getFileName().'',
);
$formMapper
->add('title', null, array('label' => 'Titre : '))
->add('summary', null, array('label' => 'Résumé : '))
->add('category', null, array('label' => 'Catégorie : '))
->add('readers', null, array('label' => 'Lecteur(s) : '))
->add('file', 'file', $options)
;
}
And this is my Book entity with readers field
class Book
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
protected $title;
/**
* #var string
*
* #ORM\Column(name="summary", type="text")
*/
protected $summary;
/**
* #Assert\File(
* mimeTypes={"application/pdf", "application/x-pdf"},
* mimeTypesMessage="Only PDF"
* )
*/
protected $file;
/**
* #var string
*
* #ORM\Column(name="file_path", type="string", length=255)
*/
protected $fileName;
/**
* #var \DateTime
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(name="created_at", type="datetime")
*/
protected $createdAt;
/**
* #var \DateTime
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(name="updated_at", type="datetime")
*/
protected $updatedAt;
/**
* #var bool
*
* #ORM\Column(name="enabled", type="boolean", nullable=true)
*/
protected $enabled;
/**
* #var bool
*
* #ORM\Column(name="received_by_reader", type="boolean", nullable=true)
*/
protected $receivedByReader;
/**
* #var bool
*
* #ORM\Column(name="download_by_reader", type="boolean", nullable=true)
*/
protected $downloadByReader;
/**
* #var bool
*
* #ORM\Column(name="send_by_reader", type="boolean", nullable=true)
*/
protected $sendByReader;
/**
* #var bool
*
* #ORM\Column(name="reader_validation", type="boolean", nullable=true)
*/
protected $readerValidation;
/**
* #var bool
*
* #ORM\Column(name="edited", type="boolean", nullable=true)
*/
protected $edited;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User")
*/
protected $author;
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Application\Sonata\UserBundle\Entity\User", cascade={"persist"})
*/
protected $readers;
Thanks You
You can do something like this in your admin class:
$formMapper
->add('readers', null, array(
'label' => 'Lecteur(s) : ',
'code' => 'getReadersWithMyRole'
))
and define in your User entity the following method:
/**
* Returns readers with "ROLE_MyRole" role
*
* #return array
*/
public function getReadersWithMyRole()
{
$result = array();
foreach ($this->getReaders() as $reader) {
if ($reader->hasRole('ROLE_MyRole')) {
$result[] = $reader;
}
}
return $result;
}
Hope it helps.
it doesn't work too but we have find a solution, we can do that like this :
->add('reader', null, array(
'class' => 'ApplicationSonataUserBundle:User',
'label' => 'Lecteur : ',
'query_builder' => function (EntityRepository $er) {
$qb = $er->createQueryBuilder('u');
$qb->where($qb->expr()->like('u.roles', $qb->expr()->literal('%ROLE_READER%')));
return $qb;
}))
if it can help someone

Symfony2 Doctrine2 trouble with optional one to many relation

I have a problem with Doctrine2 and two relationed entities.
There is a user-entity that can (not must) have one or a collection of social-entity referenced which contains a social network link.
I do not control Doctrine and I'm still learning relationship.
I want to add a user with/without adding social network link.
After several researches and testing, I am still unable to find a solution.
Here is my user-entity
<?php
//...
/**
* User
*
* #ORM\Table(name="admin_users")
* #ORM\Entity(repositoryClass="UserRepository")
* #ORM\HasLifecycleCallbacks()
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=25, unique=true)
*/
private $username;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=40)
*/
private $password;
/**
*
* #var string
*
* #Assert\NotBlank
*/
private $plainPassword;
//...
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Social", mappedBy="user", cascade={"persist","remove"})
* #ORM\JoinColumn(nullable=true)
*/
private $socials;
public function __construct()
{
$this->socials = new ArrayCollection();
}
//Some getters setters
/**
* Add socials
*
* #param Social $socials
* #return User
*/
public function addSocials(Social $socials)
{
$this->socials[] = $socials;
$socials->setUser($this);
return $this;
}
/**
* Remove socials
*
* #param Social $socials
*/
public function removeSocials(Social $socials)
{
$this->socials->removeElement($socials);
}
/**
* Get socials
*
* #return Collection
*/
public function getSocials()
{
return $this->socials;
}
}
Here is the social-entity
<?php
/**
* Social
*
* #ORM\Table(name="admin_social")
* #ORM\Entity(repositoryClass="SocialRepository")
*/
class Social
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=20, nullable=true)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="url", type="string", length=255, nullable=true)
*/
private $url;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="socials", cascade={"persist","remove"})
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true)
*/
private $user;
//getters setters
/**
* Set user
*
* #param User $user
* #return Social
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return User
*/
public function getUser()
{
return $this->user;
}
}
The userType code looks like this:
$builder
->add('username', 'text', array(
'attr'=> array('class' => 'span6',),
'label_attr' => array('class' => 'control-label'),
)
)
// ....
->add('sociaux', 'collection', array('type' => new SocialType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,))
;
Finally the controller code :
public function addAction()
{
$user = new User;
// Create the form
$form = $this->createForm( new UserType, $user );
// Gets the request
$request = $this->getRequest();
// Checks if the request have type POST
if ( $request->getMethod() == 'POST' ) {
// Links the request and the form
$form->bind( $request );
// Checks if all input values are correct
if ( $form->isValid() ) {
// Save user object in database
$em = $this->getDoctrine()->getManager();
// Persist entity user
$em->persist( $user );
$em->flush();
//...
}
}
//...
}
When I try to add a user without social-entity I have no error, but in the database I have in social table a row with null values. Please help.
UPDATE
In user-entity I added this :
if( !( $socials->getName() === null && $socials->getUrl() === null ) )
{
$this->socials[] = $socials;
$socials->setUser($this);
}
Now there is no row inserted in social table, but when I try editing the user, I have two collection field (duplicated).
See the screenshot
Here my template file (Twig) :
<div class="widget-body">
{{ form_start(form, { 'action': path('acme_admin_edit_user', {'id': userId}), 'attr': {'class': 'form-horizontal'} }) }}
<div class="control-group">
{{ form_errors(form.username) }}
{{ form_label(form.username) }}
<div class="controls">
{{ form_widget(form.username) }}
</div>
</div>
<!-- ... -->
<div id="acme_adminbundle_useredittype_socials" data-prototype="{{ form_row(form.socials.vars.prototype) | escape }}">
{% for social in form.socials %}
<div>
<label class="required text-primary lead">Lien n°{{ loop.index }}</label>
<div id="acme_adminbundle_useredittype_socials_{{ loop.index0 }}">
<div class="control-group">
{{ form_errors(social.name) }}
{{ form_label(social.name) }}
<div class="controls">
{{ form_widget(social.name) }}
</div>
</div>
<div class="control-group">
{{ form_errors(social.url) }}
{{ form_label(social.url) }}
<div class="controls">
{{ form_widget(social.url) }}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="txt-center well">
<input type="submit" class="auto-margin btn btn-primary btn-large" />
</div>
{{ form_end(form) }}
</div>
Try removing:
#ORM\JoinColumn(nullable=true)
from your User class. #JoinColumn should be defined only on one side of relationship and since Social entity contains name and referencedColumnName it is unnecessary inside the User.

Resources