output variables from doctrine in twig - symfony

Im new to symfony and what im trying is next:
Select everything from the table and count the number of rows.
Access and display this informations in a twig template.
This is part from my code in the controler dedicated to fetch data from datatabase :
.
.
.
$em=$this->getDoctrine()->getManager();
$query=$em->createQuery('SELECT b,COUNT(b.id) FROM AcmeWebBundle:baza b ORDER BY b.id DESC');
$users = $query->getResult();
if (!$em) {
throw $this->createNotFoundException('Something went wrong!');
}
return $this->render('AcmeWebBundle:Default:index.html.twig',array('users'=>$users));
}
in the table named baza i have the fields: id,username,date..etc
And part from the twig file named index.html.twig
{% extends 'AcmeWebBundle:Default:master.html.twig' %}
{% block body %}
<h1> something</h1><br></br>
{% for user in users %}
{{ ...how to access to the number of rows and other data...}}
{% endfor %}
{% endblock %}

Queries:
$query = $this->createQueryBuilder()
->from('AcmeWebBundle:baza', 'b')
->getQuery();
$user = $query->select('b')
->getQuery()
->getResult();
$total = $query->select('COUNT(b)')
->getQuery()
->getSingleScalarResult();
.....
return $this->render('AcmeWebBundle:Default:index.html.twig',array('users' => $users, 'count' => $total));
Template:
{% extends 'AcmeWebBundle:Default:master.html.twig' %}
{% block body %}
<h1> something</h1><br></br>
{% for user in users %}
{{ user.id }}
{{ user.name }}
{% endfor %}
{% endblock %}
Total users: {{ count }}
Where id and name fields in your DB.

You could try the following:
{{ user.id }}
{{ user.username }}
{{ user.date }}
...etc...

Related

EasyAdmin: Error on change formTypeOptions property field in twig

I've an User entity and EasyAdmin (EA) UserCrudController for manage to them.
The User entity has active boolean field. And I want that field will be disabled for current user in admin interface.
I got a working solution:
{% extends '#EasyAdmin/crud/index.html.twig' %}
{% block table_body %}
...
{% for field in entity.fields %}
{# disable active field for current uset #}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{% if app.user.id == entity.instance.id and field.property == 'active' %}
{% set templatePath = 'admin/crud/field/_boolean_disabled.html.twig' %}
{% else %}
{% set templatePath = field.templatePath %}
{% endif %}
{% endif %}
<td data-label="{{ field.label|e('html_attr') }}" class="{{ field.property == sort_field_name ? 'sorted' }} text-{{ field.textAlign }} {{ field.cssClass }}" dir="{{ ea.i18n.textDirection }}">
{{ include(templatePath, { field: field, entity: entity }, with_context = false) }}
</td>
{% endfor %}
...
with override EA boolean template.
But I wouldn't want to override EA boolean template and only complete field.formTypeOptions by element 'disabled': 'true'
{% for field in entity.fields %}
{# disable active field for current uset #}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{% if app.user.id == entity.instance.id and field.property == 'active' %}
{% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
{% endif %}
{% endif %}
<td data-label="{{ field.label|e('html_attr') }}" class="{{ field.property == sort_field_name ? 'sorted' }} text-{{ field.textAlign }} {{ field.cssClass }}" dir="{{ ea.i18n.textDirection }}">
{{ include(field.templatePath, { field: field, entity: entity }, with_context = false) }}
</td>
{% endfor %}
But for this path I get an error: "Uncaught PHP Exception Twig\Error\SyntaxError: "Unexpected token "punctuation" of value "." ("end of statement block" expected)." at /home/vagrant/code/blog.local/templates/admin/crud/user/index.html.twig line 27"
line 27: {% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
When I do:
{% set x = field.formTypeOptions|merge({'disabled': 'true'}) %}
{{ dump(x) }}
array:7 [▼
"required" => false
"row_attr" => array:1 [▶]
"attr" => array:1 [▶]
"label" => "Active"
"label_translation_parameters" => []
"label_attr" => array:1 [▶]
"disabled" => "true"
]
I get the required array, but I get the same error when I try to assign a new value
{% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
What am I doing wrong? Thanks
I think its because the merge function does not like punctuations. Try to set the value to a variable before:
Change:
{% set field.formTypeOptions = field.formTypeOptions|merge({'disabled': 'true'}) %}
To:
{% set options = field.formTypeOptions %}
{% set field.formTypeOptions = options|merge({'disabled': 'true'}) %}
You could already do that in UserCrudController and avoid that logic in Twig:
public function configureFields(string $pageName): iterable
{
// ...
// check user/roles
$isInputDisabled = true;
if($this->isGranted('ROLE_ADMIN')){
$isInputDisabled = false;
}
// ...
$active = BooleanField::new('active', 'Active')
->setFormTypeOption('disabled', $isInputDisabled);
// ...
}

How can I do to view all items in the twig?

I am trying to display the information like this:
Controller:
public function index(RestaurantRepository $restaurantRepository)
{
$restaurant = $restaurantRepository->findAll();
return $this->render('restaurant/index.html.twig', [
'restaurant' => $restaurant
]);
}
twig:
{% for restaurants in restaurant %}
{{ restaurant.name }}
{% endfor %}
Error "Key" name "for array with keys" 0, 1, 2, ..... "does not exist. But if I type in twig restaurant [0] .name etc it will show me the name in the given index.
What am I doing wrong?
It is a problem of plurals.
In your controller, restaurant is a collection, you should replace
$restaurant by $restaurants and 'restaurant' => $restaurant
by 'restaurants' => $restaurants
In twig the problem is here {{ restaurant.name }} instead {{ restaurants.name }}
So you should replace
{% for restaurants in restaurant %}
{{ restaurant.name }}
{% endfor %}
by
{% for restaurant in restaurants %}
{{ restaurant.name }}
{% endfor %}

EasyAdmin 3.X - How to see related entities `toString` instead of the number of association in the list?

I have an entity Product with a ManyToMany relation to an entity Category
/**
* #ORM\ManyToMany(targetEntity="App\Domain\Category", inversedBy="stalls")
*/
private $categories;
//...
/**
* #return Collection|Category[]
*/
public function getCategories(): Collection
{
return $this->categories;
}
In the ProductCrudController class I have the following configureFields method:
public function configureFields(string $pageName): iterable
{
return [
Field::new('name'),
Field::new('description'),
AssociationField::new('categories'),
];
}
When creating/editing a Product everything works as expected in the relation, but in the list of products instead of showing the related categories I see the number of categories the product has. How can I change this behaviour?
In the following image the first product has 1 category and the second one in the list has 2 different categories. I would like the name of the categories to be shown here.
As a side note: Category class has a __toString method returning the name of the category.
EDIT:
The behaviour I am looking for is the same as the Tags column in the following image:
You can make a template for that like so:
// somewhere here templates/admin/field/category.html.twig
{% for category in field.value %}
{%- set url = ea_url()
.setController('Path\\To\\Your\\CategoryCrudController')
.setAction('detail')
.setEntityId(category.id)
-%}
<a href="{{ url }}">
{{ category.name }}{% if not loop.last %}, {% endif %}
</a>
{% else %}
<span class="badge badge-secondary">None</span>
{% endfor %}
And just add it to the field
// in ProductCrudController
AssociationField::new('categories')->setTemplatePath('admin/field/category.html.twig'),
You can format the value using the method formatValue like this :
->formatValue(function ($value, $entity) {
$str = $entity->getCategories()[0];
for ($i = 1; $i < $entity->getCategories()->count(); $i++) {
$str = $str . ", " . $entity->getCategories()[$i];
}
return $str;
})
I had the same issue on my detail page. So instead of a template, I change the field type depending on the pagename
if (Crud::PAGE_DETAIL === $pageName) {
$field = ArrayField::new('field')->setLabel('label');
} else {
$field = AssociationField::new('field')->setLabel('label');
}
I will do that way :
->formatValue(function ($value, $entity) {
return implode(",",$entity->getCategories()->toArray());
})
Building on top of the most upvoted answer, you could make the Twig snippet universal like this:
{% for member in field.value %}
{%- if field.customOption('crudControllerFqcn') is not empty -%}
{%- set url = ea_url()
.setController(field.customOption('crudControllerFqcn'))
.setAction('detail')
.setEntityId(member.id)
-%}
<a href="{{ url }}">
{{ member }}
</a>
{%- else -%}
{{ member }}
{%- endif -%}
{%- if not loop.last %}, {% endif -%}
{% else %}
<span class="badge badge-secondary">None</span>
{% endfor %}
This way you could set the link destination in your CRUD controller and use the template everywhere. When no CRUD controller is not set, you will still have the individual items enumerated, but not as links.
In my TeamCrudController, I'm doing this:
public function configureFields(string $pageName): \Generator
{
yield TextField::new('name')
->setDisabled()
;
$members = AssociationField::new('members')
->hideOnForm()
;
if (Crud::PAGE_DETAIL === $pageName) { // I want to see the number on INDEX, but the list on DETAIL
$members
->setCrudController(EmployeeCrudController::class)
->setTemplatePath('admin/field/expanded_association_field.html.twig')
;
}
yield $members;
}
Alternatively, if you would like to become the default behaviour, override the EasyAdminBundle template by placing the following content in templates/bundles/EasyAdminBundle/crud/field/association.html.twig:
{# #var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #}
{# #var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #}
{# #var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #}
{% if 'toMany' == field.customOptions.get('associationType') %}
{% if ea.crud.currentPage == 'detail' %}
{% for member in field.value %}
{%- if field.customOption('crudControllerFqcn') is not empty -%}
{%- set url = ea_url()
.setController(field.customOption('crudControllerFqcn'))
.setAction('detail')
.setEntityId(member.id)
-%}
<a href="{{ url }}">
{{- member -}}
</a>
{%- else -%}
{{ member }}
{%- endif -%}
{%- if not loop.last %}, {% endif -%}
{% else %}
<span class="badge badge-secondary">None</span>
{% endfor %}
{% else %}
<span class="badge badge-secondary">{{ field.formattedValue }}</span>
{% endif %}
{% else %}
{% if field.customOptions.get('relatedUrl') is not null %}
{{ field.formattedValue }}
{% else %}
{{ field.formattedValue }}
{% endif %}
{% endif %}

Phalcon count in volt

I have a counting problem in phalcon volt. I have a table named category and there I have two columns id and cname, and also have a table blog and there is a column category. I want to show how many post have in each category.
When I insert a post into blog table, in category column I'm inserting its category id. First of I just retrieve list of all category like this:
[controller]
$categories = Category::find();
$this->view->setVar('category', $categories);
$cx = Blogs::find();
$this->view->setVar('cates',$cx);
[Volt]
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
{% for cx in cates %}
{%if cx.category === categories.id %}
<?php echo(count($cx->category)); ?>
{% endif %}
{% endfor %}
]</span></a>
{% endfor %}
Its render like "1 1 1" or "1 1" or "1" but it should render like "3" or "2" or "1" whats my wrong?
I also tried like this but did not get the expected output:
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
{% for cx in cates %}
{%if cx.category === categories.id %}
{% if loop.first %} {{ loop.length }} {% endif %}
{% endif %}
{% endfor %}
]</span></a>
{% endfor %}
Have you defined your relationships between your models in Phalcon?
If so, you can use the built in commands to query the total amount of posts for each category
Example from the documentation:
You can also use “count” prefix to return an integer denoting the count of the related records:
$robot = Robots::findFirst(2);
echo "The robot has ", $robot->countRobotsParts(), " parts\n";
I don't have much experience with Volt templating, but I guess it will be something like:
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
{{ categories.countBlogs }}
]</span></a>
{% endfor %}
Refer to: https://docs.phalconphp.com/en/latest/reference/models.html#taking-advantage-of-relationships
UPDATE - model relations
[model: Category]
public function initialize()
{
// id => primary key name of the Category table
// Blogs => name of the table you want to create a relationship with
// category => name of the foreign key column in your relationship table
$this->hasMany('id', 'Blogs', 'category');
}
[model: Blogs]
public function initialize()
{
// category => blog column name which refers to the ID in the Category table
// Category => name of the Category table
// id => name of the primary key column in the Category table
$this->belongsTo('category', 'Category', 'id');
}
No Sir, its not working. But i just solved my problem like this :
[controller]
$categories = Category::find();
$this->view->setVar('category', $categories);
[volt]
{% for categories in category %}
<a href="blog/category/{{categories.cname}}" class="tags">{{ categories.cname }}
<span>[
<?php
$catcount = $this->modelsManager->executeQuery("SELECT Blogs.category FROM Blogs WHERE Blogs.category = $categories->id");echo(count($catcount));
?>
]</span></a>
{% endfor %}
Now its working as expected. and here i dont make any relations ion model.Is it ok Sir. Please! Thnx

Error message customization in file upload

Using the guide http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html i'm trying to customize error message, but i've a problem: variable errors is not defined, as we don't validate an entity and we are not calling $this->get('validator')->validate($entity).
{% block field_errors %}
{% spaceless %}
{# errors is undefined here #}
{% endspaceless %}
{% endblock field_errors %}
This is the sample code:
public function uploadAction()
{
$document = new Document();
$form = $this->createFormBuilder($document)
->add('name')
->add('file')
->getForm()
;
if ($this->getRequest()->getMethod() === 'POST') {
$form->bindRequest($this->getRequest());
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($document);
$em->flush();
$this->redirect($this->generateUrl('...'));
}
}
// Variable 'errors' is not assigned
return array('form' => $form->createView());
}
Not sure I understand. If you are following the example then $document has validation rules on it which will be tested by $form->isValid(). {{ form_errors(form) }} should output any errors.
If it is just a template customization question then you need to test for the existence of errors before trying to process them:
{% block field_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<span style="color:red">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators') }}<br />
{% endfor %}
{% endif %}
{% endspaceless %}
{% endblock field_errors %}

Resources