reuse select menu with different ids' and names' in twig - twig

I would like to reuse a select menu, but change every time the id and the name for it in Twig. How could it be done?
I thought of a wrapper block about the select menu and then extend it each time of reuse. But how to set the values for id and name using {{ parent() }}?

I do this by storing and creating the keys in my custom Twig_Extension class, here is a small setup for it. By keeping it global I can ensure unique id's in every view/macro/include ...
example.twig
{% for i in 1..5 %}
<ul id="{{ get_unique_key('my_menu') }}">
<li>Foo</li>
</ul>
{% endfor %}
ProjectTwigExtension
class ProjectTwigExtension extends Twig_Extension {
private $keys = array();
public function getFunctions() {
return array(
new Twig_SimpleFunction('get_unique_key', array($this, 'getUniqueKey')),
);
}
/**
* Create an unique HTML identifier
*
* #param $name String to make unique
*
* #returns String
*/
public function getUniqueKey($name) {
if (!in_array($name, $this->keys)) {
$this->keys[] = $name;
return $name;
}
$i = 0;
while(in_array($name.++$i,$this->keys)) {}
$this->keys[] = $name.$i;
return $name.$i;
}
public function getName() {
return 'ProjectTwigExtension';
}
}
Register extension
$twig = new Twig_Environment($loader);
$twig->addExtension(new ProjectTwigExtension());

Related

Can't render dateTime

I make an entity "comment" with fields id, pseudo, email, comment and published_at.
My entity :
/**
* #ORM\Column(type="datetime")
*/
private $published_at;
public function __construct()
{
$this->published_at= new \DateTime();
}
public function getPublishedAt(): ?\DateTimeInterface
{
return $this->published_at;
}
public function setPublishedAt(\DateTime $published_at): self
{
$this->published_at = $published_at;
return $this;
}
My migration:
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE comment (id INT AUTO_INCREMENT NOT NULL, pseudo VARCHAR(25) NOT NULL, email VARCHAR(255) NOT NULL, comment LONGTEXT NOT NULL, published_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
I make a controller :
$comments = $commentRepo->findBy([], ['published_at' => 'desc']);
// dd($comments);
return $this->render('comment/comments.html.twig', [
'commentForm' => $form->createView(),
'comments' => $comments,
]);
My render twig :
<div>
{% for comment in comments %}
<div class="text-light">
{{ comment.pseudo }}
{{ comment.published_at|date('d/m/Y H:i:s')}}
{{ comment.comment | raw }}
</div>
{% endfor %}
</div>
For {{comment.pseudo}} and {{comment.comment}} display well
But for {{comment.published_at}} I have this error :
Neither the property "published_at" nor one of the methods "published_at()", "getpublished_at()"/"ispublished_at()"/"haspublished_at()" or "__call()" exist and have public access in class "App\Entity\Comment".

TWIG form template: call variable in attr

In a twig form template in Symfony 4 app I need to have an attribute with a variable.
Exemple:
{{ form_widget(myform.field, {'attr': {'class': 'bidding-slider','data-slider-value': '800'}}) }}
I need to put a variable in 'data-slider-value' instead of a manual value.
I tried :
{{ form_widget(myform.field, {'attr': {'class': 'bidding-slider','data-slider-value': '{{ variable }}'}}) }}
but it do not work...
{{ variable }} alone return well the value I need to put in 'data-slider-value'.
Second tried:
I have Extended form class 'TextType' method buildView.
To do that I added this file : src/Form/Extension/TextTypeExtension.php
// src/Form/Extension/TextTypeExtension.php
namespace App\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class TextTypeExtension extends AbstractTypeExtension
{
/**
* Return the class of the type being extended.
*/
public static function getExtendedTypes(): iterable
{
// return FormType::class to modify (nearly) every field in the system
return [TextType::class];
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$tjm = $form->get('dailyrate')->getData();
$view->vars['attr']['data-slider-value'] = $tjm;
}
}
But now I am not sure of the way to use that in my form template...
Thank you very much for helping me.
Alex
Extend your form's class method buildView:
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['attr']['data-slider-value'] = ...//
}

Get URL in twig

Need to get the URL in a template.
I have tried using get.request.url and it always returns blank. I've tried get.request.attributes.get('_route') and it always returns blank. Since I'm new to twig I'm sure I'm missing something fairly basic and easy.
As you are working with twig standalone, u'd need to pass the information yourself. You could create a small wrapper class to solve this for you though.
Request.php
class Request {
public function __construct() {}
public function get($key) {
return isset($_GET[$key]) ? $_GET[$key] : null;
}
public function post($key) {
return isset($_POST[$key]) ? $_POST[$key] : null;
}
public function url() {
$http = 'http'.(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 's': '');
return $http.'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
}
}
And register the class as a global into twig:
<?php
require_once __DIR__.'/vendor/autoload.php';
$loader = new Twig_Loader_Filesystem(__DIR__.'/../views');
$twig = new Twig_Environment($loader);
$twig->addGlobal('request', new Request());
Now you can use your wrapper inside twig
{{ request.url }}{# output current url #}
{{ request.get('variable') }}{# contents of $_GET['variable'] when set or null #}
{{ request.post('variable') }}{# contents of $_POST['variable'] when set or null #}

PUGXMultiUserBundle get type of current user

How can I get the type of current user with PUGXMultiUserBundle ?
This code returns this error
{% if app.user.type == 'user_one' %}
//...
{% endif %}
This is the error
Method "type" for object "AppBundle\Entity\UserOne" does not exist
This is entity User
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="user")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"user_one" = "UserOne", "user_two" = "UserTwo"})
*
*/
abstract class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
after updating database there is a new field named type created in table user
Ah, I see the problem. In the twig file, you are calling:
{% if app.user.type == 'user_one' %}
Where "app.user" specifies the object, and "type" specifies the method. But you don't have a "method" defined in the Class. But instead you have the DiscriminatorColumn.
A method would be something like:
public function type(){
...
}
Hopefully that makes sense.

Symfony2 - Entire child entity in form and Twig template

In a Sonata admin form, I'd like to display all images related to the current object. Don't need to edit them.
I managed to get this working with an entity field type and its property option to select the image URL as label so I can call all pictures in the template :
->add('image', 'entity', array(
'class' => 'Hop\HopBundle\Entity\Image',
'property' => 'image_url',
'query_builder' => function($er) use ($object) {
return $er->createQueryBuilder('i')
->where('i.object = :object')
->setParameter('object', $object)
;
},
'expanded' => true,
))
.
{% for child in form %}
<img src="{{ child.vars.label }}" alt="{{ child.vars.label }}" />
{% endfor %}
It's because it seems that the entity type only give label and one value to the template.
But I'd like to get also image width, descriptions, date, ... In other word : how can we get each entire related image object in the Twig template ?
Thanks.
So I googled it a lot and here's what worked for me (Symfony 2.2)
Updated as #flu suggested in a comment
{% for key, child in form %}
<div>
{% set entity = form.vars.choices[key].data %}
{{ form_widget(child) }}
{{ form_label(child) }}
</div>
{% endfor %}
and entity is the child object.
As of Symfony 2.3 there will be just form.vars.data, if I understand correctly: https://github.com/symfony/symfony/pull/5023
I´ve spend the whole day to get a solution for this problem.
First I created a new FormType which extends the ChoiceType:
class NomineesType extends AbstractType
{
protected $em;
public function __construct(EntityManager $em) {
$this->em = $em;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$submissionRepository = $this->em->getRepository('BundleName:Submission');
$choices = $submissionRepository->findBy(array(
'nominee' => true
));
$resolver->setDefaults(array(
'choices' => $choices
));
}
public function getName()
{
return 'nominees';
}
public function getParent()
{
return 'choice';
}
}
Than I had to register the service:
services:
form.type.nominees:
class: Bundle\Form\Type\NomineesType
arguments:
entityManager: "#doctrine.orm.entity_manager"
tags:
- { name: form.type, alias: nominees }
After that I added the new type to my form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$game = $this->game;
$builder->add('submission', 'nominees', array(
'expanded' => true,
'multiple' => false
));
$builder->add('email');
}
Now I am able to get all properties in my twig-template:
{% block nominees_widget %}
{% spaceless %}
{% if expanded %}
<ul {{ block('widget_container_attributes') }}>
{% for child in form %}
<li>
{{ child.get('form').get('label').firstname }}
{{ child.get('form').get('label').lastname }}
{{ form_widget(child) }}
{{ form_label(child) }}
</li>
{% endfor %}
</ul>
{% else %}
{# just let the choice widget render the select tag #}
{{ block('choice_widget') }}
{% endif %}
{% endspaceless %}
{% endblock %}
Because the choice list is returning only integer values I´ve created a new data transformer to transform the id of the choice into an entity:
class IntToEntityTransformer implements DataTransformerInterface
{
/**
* #var ObjectManager
*/
private $om;
/**
* #param ObjectManager $om
*/
public function __construct(ObjectManager $om)
{
$this->om = $om;
}
/**
* Transforms an object (issue) to a string (number).
*
* #param Issue|null $issue
* #return string
*/
public function transform($issue)
{
if (null === $issue) {
return "";
}
return $issue->getNumber();
}
/**
* Transforms a string (number) to an object (issue).
*
* #param string $number
* #return Issue|null
* #throws TransformationFailedException if object (issue) is not found.
*/
public function reverseTransform($number)
{
if (!$number) {
return null;
}
$issue = $this->om
->getRepository('BundleName:Submission')
->findOneBy(array('id' => $number))
;
if (null === $issue) {
throw new TransformationFailedException(sprintf(
'An Submission with number "%s" does not exist!',
$number
));
}
return $issue;
}
}
This data transformer is initialized in the build form method:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new IntToEntityTransformer($this->em);
$builder->add($builder->create('submission', 'nominees', array(
'expanded' => true,
'multiple' => false
))->addModelTransformer($transformer));
$builder->add('email');
}
I've been fighting this problem with Symfony 2.3. Don't know how it works in 2.1.
In my case I had a entity choice (expanded and multiple) for which I needed to add the entitie's 'descripcion' field, next to the label of each choice.
I solved as follows:
1- created a custom type, whose parent is EntityType, and name 'xxxxxxx_form_reparacionnormalizada'
class ReparacionNormalizadaType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'class' => 'xxxxxxxxx\Entity\TipoReparacion',
));
}
public function getName()
{
return 'xxxxxxx_form_reparacionnormalizada';
}
public function getParent()
{
return 'entity';
}
}
2- register the form type as service as usual
3- created a custom template as follows:
{% block xxxxxxx_form_reparacionnormalizada_widget %}
<ul {{ block('widget_container_attributes_choice_widget') }}>
{% for id, child in form.children %}
<li>
{{ form_label(child, child.vars.label|default(null), { 'in_list_checkbox' : true, 'widget' : form_widget(child) } ) }}
<span>{{ choices[id].data.descripcion }}</span>
</li>
{% endfor %}
</ul>
{% endblock %}
4- in your sonata admin you use your custom type instead of 'entity'
hope it helps
regards
javier

Resources