symfony2 get property values from form - symfony

i have a symfony entity called Config
class Config
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="key_name", type="string", length=255)
*/
private $keyName;
/**
* #var string
*
* #ORM\Column(name="key_value", type="text", nullable=true)
*/
private $keyValue;
/**
* #var string
*
* #ORM\Column(name="key_type", type="string", length=255)
*/
private $keyType;
/**
* #var string
*
* #ORM\Column(name="key_tab", type="string", length=255)
*/
private $keyTab;
controller :
class ConfigController extends Controller
{
/**
* Lists all Config entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('MyBundle:Config')->findAll();
$configCollection = array('configs'=>$entities);
$collection = $this->createForm(new ConfigsType, $configCollection);
return $this->render('MyBundle:Config:index.html.twig', array(
'edit_form' => $collection->createView(),
));
}
view :
{% macro config_row(elem) %}
<div class="form-group">
{{ form_label(elem.keyValue, 'fff', { 'label_attr': { 'class': 'col-md-3 control-label' }}) }}
{# elem.keyName|humanize #}
<div class="col-md-4">
{{ form_widget(elem.keyValue, {'attr': { 'class': 'form-control input-large' }}) }}
{{ form_errors(elem.keyValue) }}
</div>
</div>
{% endmacro %}
<form action="{{ path('my_config') }}" method="post" {{ form_enctype(edit_form) }} >
{% for conf in edit_form.configs %}
{{ _self.config_row(conf) }}
{% endfor %}
</div>
{{ form_rest(edit_form) }}
</form>
what i need is for each config row i can get properties values in the config_row template to customize html rows structure based on their values
any idea please ?
thank you.

If I understand you correct you want to retrieve the value of each property of instance of entity Config, right?
If so, properties should be accessible by doing this:
{{ conf.vars.data.id }}
{{ conf.vars.data.keyName }}
{{ conf.vars.data.keyValue }}

Related

Twig extension disable auto escape

I made a twig extension to be able to call functions in the templates, but unfortunately now the rendered html content of these functions is escaped. Do you have any idea how I could disable that?
FrontendTwigExtension.php
class FrontendTwigExtension extends Twig_Extension
{
/**
* #var DataProviderService
*/
private $dataProvider;
/**
* FrontendTwigExtension constructor.
* #param DataProviderService $dataProvider
*/
public function __construct(DataProviderService $dataProvider)
{
$this->dataProvider = $dataProvider;
}
/**
* #return array
*/
public function getFunctions(): array
{
return array(
new Twig_Function('getProductDetailData',
[$this, 'getProductDetailData'],
['needs_environment' => true]
),
new Twig_Function('getPageHeader',
[$this, 'getPageHeader'],
['needs_environment' => true]
)
);
}
/**
* #param Twig_Environment $env
* #return string
* #throws Twig_Error_Loader
* #throws Twig_Error_Runtime
* #throws Twig_Error_Syntax
*/
public function getPageHeader(Twig_Environment $env): string
{
return $env->render('Component/PageHeader/pageHeader.html.twig');
}
/**
* #param Twig_Environment $env
* #return string
* #throws Twig_Error_Loader
* #throws Twig_Error_Runtime
* #throws Twig_Error_Syntax
*/
public function getProductDetailData(Twig_Environment $env): string
{
$service = new ProductDetailDataService($this->dataProvider);
return $env->render('Module/ProductDetailPage/productDetailData.html.twig',
[
'productData' => $service->getData()
]
);
}
}
template.html.twig
{% extends 'base.html.twig' %}
{% block pageHeader %}
{{ getPageHeader() }}
{{ getProductDetailData() }}
{% endblock %}
services.yaml
App\Extension\FrontendTwigExtension:
arguments:
- '#App\DataProvider\DataProviderService'
tags:
- { name: 'twig.extension' }
You nedd to set the is_safe option:
['needs_environment' => true, 'is_safe' => ['html']]
Try using raw function in twig.
{% extends 'base.html.twig' %}
{% block pageHeader %}
{{ getPageHeader()|raw }}
{{ getProductDetailData()|raw }}
{% endblock %}
source: https://twig.symfony.com/doc/2.x/filters/raw.html

NestedTree Symfony2 Gedmo annotation show list with Tree

i have a simple probleme but i dont know how to fix it,
Here we go,
I already have a table that contains all menu registred on database, like this
http://snapplr.com/snap/hbch
But, the entity with title A is parent of entity B, so all i want to do now is to tree my list as dependencies with parent and children Tree Gedmo annotation.
this is my index.html.twig page
{% block tbody %}
{% for entity in entities %}
<tr>
<td>{{ entity.title|title }}</td>
<td>{% if entity.type == 'javascript:void(0)' %}
Groupe
{% else %}
{{ entity.type|title }}
{% endif %}</td>
<td>{{ entity.value|title }}</td>
<td>
{% render(controller('MenuBundle:Backend/MenuExtends:createDelete', {'id' : entity.id, 'menu' : id})) %}
</td>
</tr>
{% endfor %}
{% endblock %}
Ok
here my entity
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Menu", inversedBy="extends")
*/
private $menu;
/**
* #var string
* #Gedmo\TreePathSource
* #ORM\Column(name="type", type="string", length=255, nullable=false)
*/
private $type;
/**
* #var string
* #ORM\Column(name="value", type="string", length=255, nullable=false)
*/
private $value;
/**
* #Gedmo\TreeLeft
* #ORM\Column(name="submenu_left", type="integer")
*/
private $lft;
/**
* #Gedmo\TreeRoot
* #ORM\Column(name="submenu_root", type="integer", nullable=true)
*/
private $root;
/**
* #Gedmo\TreeLevel
* #ORM\Column(name="submenu_level", type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeRight
* #ORM\Column(name="submenu_right", type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="MenuExtends", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="MenuExtends", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
what i want to do is :
if an entity have a children, in the same line , open x lines for the x children ...

multiple not mapped hidden input symfony2

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.

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.

Symfony2 error on render controller with relation OneToOne on same table

I have a problem to get a object from a controller called by the render controller method.
This is my Entity with the self OneToOne relation :
class Family
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Family")
* #ORM\JoinColumn(name="brother_id", referencedColumnName="id")
**/
private $brother;
/**
* #ORM\Column(type="string", length=100)
*/
private $label;
}
This is my action:
/**
* #Template()
*/
public function testAction()
{
$em = $this->getDoctrine()->getManager();
$brothers = $em->getRepository('FifaAdminBundle:Family')->findAll();
return array(
'brothers' => $brothers,
);
}
My view
{% for brother in brothers %}
{{ brother.id }} - {{ brother.label }}
<hr />
{% render controller('AdminBundle:Test:show', {'brother': brother}) %}
<hr />
{{ render(controller('AdminBundle:Test:show', { 'brother': brother })) }}
<hr />
{% endfor %}
My other controller
public function showAction($brother)
{
if (is_object($brother))
{
return new \Symfony\Component\HttpFoundation\Response('OK');
}
else
{
var_dump($brother);
return new \Symfony\Component\HttpFoundation\Response('KO');
}
}
The first element isgood.
But if it has a brother_id, this brother in not load by the showAction.
It gives me this:
array(1) { ["__isInitialized__"]=> string(1) "1" }
Please help me.
You probably want to use the #ParamConverter annotation in your case.
Your controller would go as follow:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Admin\Bundle\Entity\Family;
/**
* #Route("/show/{id}")
* #ParamConverter("family", class="AdminBundle:Family")
*/
public function showAction(Family $brother)
{
//Do your stuff
}
And the view:
{% for brother in brothers %}
{{ brother.id }} - {{ brother.label }}
<hr />
{{ render(controller('AdminBundle:Test:show', { 'brother': brother.id })) }}
<hr />
{% endfor %}
Note that if no Family object is found, a 404 Response is generated. So you don't need to check if $brother is an object or not in your controller.
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
Thank you cheesemacfly
Indeed, it's work with the #ParamConverter
But it is wird because if I remove the OneToOne relation, it works without #ParamConverter

Resources