i have two tables:
products products_images
-id -id
-name -product_id
-image_name
There is one to many relation from product to products_images table
I have created two entities with its relation defined as: Product and ProductImage
I need to get list of products and its images but the limiting the record of no of images to 1.
Currently, I did this :
$product = $this->getDoctrine()
->getRepository('TestBundle:Product');
Then in the twig template:
{% for image in product.images if loop.first %}
{% endfor %}
I used this loop to fetch one image for that product. I dont think this is efficient way to do since i have fetching all the images for that product.
What I want to do is just fetch only one image per product from the database? How can i do this ?
I'd add another method to the Product-entity, something like getThumbnail. This encapsulates the logic of which image is considered the thumbnail (i.e your view does not contain any logic of whether to display the first, last or any other product image, it just asks the product for its thumbnail):
in the view
{% if product.thumbnail %}
{{ // Output the product.thumbnail-entity }}
{% endif %}
In the entity
public function getThumbnail ()
{
return $this->getImages()->first();
}
Now, after profiling, if you're concerned that the full image collection is loaded when only a single image/product is shown, then I'd update the repository DQL to only fetch-join a single image, or make sure that the association to the images is EXTRA_LAZY
Related
I am new to drupal and I tried to add a simple image as static in the html.html.twig page.
To display this image in the home page only I added this condition
{% if is_front %}
{% endif %}
What is the condition to add it in another specific page example /contact/
I tried this code inside the page but it does not work, should I wrap it with some codes?
if(drupal_valid_path('contacts') == 1) //this exists
{
print_r('Exists!');
}
Please help! Many thanks.
Your question is mixing twig with a drupal 7 function. I suppose anyway you're on D8/D9.
I also suppose the "contacts" page is a node. If it is somethings else - e.g. a view page - instead of checking for the node, you may have to check the route.
There are various approach, two possible would be:
A hook preprocess where you load the node if exists
function hook_preprocess_html(&$variables) {
$node = \Drupal::routeMatch()->getParameter('node');
if ($node instanceof \Drupal\node\NodeInterface) {
$variables['node'] = $node;
}
}
And the in the twig check the id of the node is the right one
override the html.html.twig for the specific node, e.g. html--node--10.html.twig. In this case I'd suggest not to duplicate all the content of the base html.html.twig, but to use the embed tag to override only the appropriate block.
I am wondering if there is a easy way to implement a group view for datasets grouped by its "root" element.
Lets say i have a "person" entity. Many persons can have a "root" person they belong to. So i would add a reference to the person entity itself.
Now i don't want to show every person in the flat list view. Instead i want to display only every root-person and with clicking this dataset a accordion opens with the subordinated person entities ... how is that possible?
It would also be fine without a accordion, it can be enough if the subordinated entities are indented a bit ...
Can somebody give me a clue which approach i should follow? I would be the if i can reuse the most of the sonata admin functionality, especially the templates ...
Thanks
Was solving something similar in past. Got that working in few steps:
Override first field in your Datagrid
With this code you say that you want use my_custom_template.html.twig to render this field (in your admin class).
protected function configureListFields(ListMapper $list)
{
$list->add('yourFirstField', null, ['template' => 'my_custom_template.html.twig'])
}
Enable filtering for yourFirstField
Prepare filtering for your parent field (in your admin class)
protected function configureDatagridFilters(DatagridMapper $filter)
{
$filter->add('parent');
}
Write custom template for first field
Then in your custom template you use to set up filter value on click on link.
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
{% if object.isRoot %}
{{ object.name }}
{% else %}
{{ object.name }}
{% endif %}
{% endblock %}
Later on you can override break breadcrumbs builder service (https://sonata-project.org/bundles/admin/master/doc/reference/breadcrumbs.html) and create nice path in breadcrumbs, so user can go navigate.
I have a layout included in another one that display my menu. The labels of my menu items need to be dynamic (like the unread messages number of a mailbox). Then I did this :
My orders
(
{{ render(controller('MyController', {'etat':2})) }}
<span style="color:red">with {{ render(controller('MyController', {'etat':2})) }} in late</span>
)
I would like to display labels according to the number that return my controller. I don't know how to get it in a variable.
When rendering your template in your controller
return $this->render('twig_template_name.html.twig', array('variable_name' => $variable);
you pass a variable to the twig template in the array of options as I showed. Your code
{{ path('mypath',{'etat': '2' }) }}
prints a path defined in the routing.yml under the 'mypath' section and ends up adding a GET request variable to the link ('?etat=2'), if 'mypath' showed an absolute route 'www.website.com/yourpath',
{{ path('mypath',{'etat': '2' }) }} would produce 'www.website.com/yourpath?etat=2', which would send your controller for a route /yourpath/{etat} a variable etat with a value of 2 so all you need to do now is change 2 with an actual dynamic value which you receive from another controller.
I am not sure what etat is but lets say it's an article and it has it's id, you have a blog page with lots of articles and the controller that prints them all out sends an array of articles to the twig template, on your twig template you do something like:
{% foreach article in articles %}
{{ article.title }}
{{ article.story }}
read more
{% endforeach %}
And you end up something like:
Catchy Title
Awesome story about code without bugs and where deadlines depend on how creative and well designed and implemented the solutions are
[read more]
and you ofcourse click on "read more" and end up on the url ~/article/2 because the article had an id of 2, your controller for that url receives a variable id in the request, you do a $id = $_GET['id']; and grab the article from the repository and send it to the template.
Hopefully this answered your question, I am very tiered so forgive me if i was confusing which I surely was.
I am new to Symfony and am finally beginning to understand how to query a database using a Doctrine. However, I am lost as far understanding how to use the database object content in a Twig template.
Lets say my database object contains product Id's, names, prices, for 50 different products. After I am done querying the database in the controller, I do the following, to pass the database object into the Twig template:
public function searchAction($word)
{
//query database using the $word slug and prepare database object accordingly
$dataObject; // contains query results
return $this->render('GreatBundle:Default:search.html.twig', array('word' => $word));
}
This is where I am stuck. Now I have a Twig template, I would like to pass the DB object from the controller and then print out the database data in my Twig template.
I appreciate any suggestions as to how I can accomplish this.
Many thanks in advance!
I'll respond with an example (more easier for me to explain)
You want to search something with a slug (the var $word in your example). Let's say you want to find a article with that.
So your controller :
public function searchAction($word)
{
//query database using the $word slug and prepare database object accordingly
// Search the list of articles with the slug "$word" in your model
$articleRepository = $this->getDoctrine()->getRepositoy('GreatBundle:Article');
$dataObject = $articleRepository->findBySlug($word);
// So the result is in $dataObject and to print the result in your twig, your pass the var in your template
return $this->render('GreatBundle:Default:search.html.twig', array('result' => $dataObject));
}
The twig template 'GreatBundle:Default:search.html.twig'
{% for item in result %}
{{ item.title }} : {{ item.content }}
{% endfor %}
Just look the second example in the Symfony2 Book (Sf2 Book - templating), you have to use the function "for" to parse your object (like an array in php !)
Example in your twig template :
{% for item in word %}
{{ item.id }} - {{ item.name }} - {{ item.description }}{# etc... #}<br>
{% else %}
<h2>Aoutch ! No data !</h2>
{% endfor %}
Ah, and it's not the good var in your render method (but it's was for your example !)
public function searchAction($word)
{
//query database using the $word slug and prepare database object accordingly
$dataObject; // contains query results
return $this->render('GreatBundle:Default:search.html.twig', array('word' => $dataObject));
}
In a Symfony2.1 project, how to call custom entity functions inside template? To elaborate, think the following scenario; there are two entities with Many-To-Many relation: User and Category.
Doctrine2 have generated such methods:
$user->getCategories();
$category->getUsers();
Therefore, I can use these in twig such as:
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for user in category.users %}
{{ user.name }}
{% endfor %}
{% endfor %}
But how can I get users with custom functions? For example, I want to list users with some options and sorted by date like this:
{% for user in category.verifiedUsersSortedByDate %}
I wrote custom function for this inside UserRepository.php class and tried to add it into Category.php class to make it work. However I got the following error:
An exception has been thrown during the rendering of
a template ("Warning: Missing argument 1 for
Doctrine\ORM\EntityRepository::__construct(),
It's much cleaner to retrieve your verifiedUsersSortedByDate within the controller directly and then pass it to your template.
//...
$verifiedUsersSortedByDate = $this->getYourManager()->getVerifiedUsersSortedByDate();
return $this->render(
'Xxx:xxx.xxx.html.twig',
array('verifiedUsersSortedByDate' => $verifiedUsersSortedByDate)
);
You should be very carefull not to do extra work in your entities. As quoted in the doc, "An entity is a basic class that holds the data". Keep the work in your entities as basic as possible and apply all the "logic" within the entityManagers.
If you don't want get lost in your code, it's best to follow this kind of format, in order (from Entity to Template)
1 - Entity. (Holds the data)
2 - Entity Repositories. (Retrieve data from database, queries, etc...)
3 - Entity Managers (Perform crucial operations where you can use some functions from your repositories as well as other services.....All the logic is in here! So that's how we can judge if an application id good or not)
4 - Controller(takes request, return responses by most of the time rendering a template)
5 - Template (render only!)
You need to get the users inside your controller via repository
$em = $this->getDoctrine()->getEntityManager();
$verifiedusers = $em->getRepository('MYBundle:User')->getVerifiedUsers();
return array(
'verifiedusers' => $verifiedusers,
);
}