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
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
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 ...
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.
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.
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