📜 ⬆️ ⬇️

Work with Doctrine dates 2. Navigation in Symfony 2. And, I hope, other usefulness

Greetings to all! And let's do a top-cheat sheet on Symfony and Doctrine.

Introduction


I am an ordinary Siberian developer, the main task in life is to take over the world and make people happier. On symfony made several projects. When developing, sometimes there are tasks for which there is absolutely no information on the Internet, or very little and not completely clear. Therefore, I wanted to create this discussion, where I will show you how to solve some of your tasks, and you, I hope, will lead me on the right path or join and share your hacks too. This topic is intended for those people who use the above mentioned framework or its components. And also for those who want to talk about solving various problems, share their experience with other developers.

Closer to the point


Date and Doctrine functions

Imagine a small personal blog. You need to display navigation for posts grouped by year and month. Very simple task. You create a method in the BlogRepository class, and call it for example getArchiveByMonths (). On the machine, write code similar to:
')
$qb = $this->createQueryBuilder('p'); return $qb ->addSelect('MONTHNAME(p.created) as month') ->addSelect('YEAR(p.created) as year') ->addSelect('COUNT(p) as cnt') ->groupBy('month, year') ->orderBy('p.created', 'DESC') ->getQuery() ->getArrayResult(); 


And you get the error: Expected known function, got 'MONTHNAME'
The fact is that Doctrine does not know all the functions for working with dates. So you need to add them. The official documentation has a couple of lines on how to add these features ( tyts )

Solution: there is a wonderful repository: github.com/simukti/DoctrineExtensions , there we are interested in 2 classes:
DoctrineExtensions\Query\Mysql\Month;
DoctrineExtensions\Query\Mysql\Year;

Why not use them? We copy them into our bundle, for example, in the Dql folder, change the namespace to Acme\BlogBundle\Dql and rejoice that there is such a wonderful repository. The function Monthname done by the example of Month . And according to the link , it remains for us to tell doctrine about these functions.

In the config.yml add:
 # Doctrine Configuration doctrine: orm: dql: datetime_functions: month: Acme\BlogBundle\Dql\Month monthname: Acme\BlogBundle\Dql\Monthname year: Acme\BlogBundle\Dql\Year 


After that, our functions will work.

It was unexpected for me that Doctrine does not know about these functions. But you can forgive her for other advantages.

Navigation and bread crumbs

To create navigation, I use KnpMenuBundle . How to use it read on githabe. So, we read, made our first menu, for example:
 namespace Acme\BlogBundle\Menu; use Knp\Menu\FactoryInterface; use Knp\Menu\MenuItem; use Symfony\Component\DependencyInjection\ContainerAware; class Builder extends ContainerAware { public function mainMenu (FactoryInterface $factory, array $options) { $menu = $factory->createItem('root'); $request = $this->container->get('request'); $menu ->addChild('Homepage', array( 'route' => 'homepage', )); $blog = $menu->addChild('Blog', array( 'route' => 'blog' )); $blog->addChild('BlogView',array( 'route' => 'blog_post_view', 'routeParameters' => array('id' => $request->get('id', 1)), 'display' => false )); return $menu; } 


Brought this menu somewhere on the left / right side of the site. And now we need to bring out bread crumbs. And here I do not have a beautiful and wonderful decision, I hope someone will tell me how to do it. In the meantime, I will give my decision.

First we need to find the active menu item. The standard method is no longer in Knp’s bundle. Expand our MenuBuilder:
 namespace Acme\BlogBundle\Menu; use Knp\Menu\FactoryInterface; use Knp\Menu\Iterator\CurrentItemFilterIterator; use Knp\Menu\Iterator\RecursiveItemIterator; use Knp\Menu\MenuItem; use Symfony\Component\DependencyInjection\ContainerAware; class Builder extends ContainerAware { public function mainMenu (FactoryInterface $factory, array $options) { $menu = $factory->createItem('root'); $request = $this->container->get('request'); $menu ->addChild('Homepage', array( 'route' => 'homepage', )); $blog = $menu->addChild('Blog', array( 'route' => 'blog' )); $blog->addChild('BlogView',array( 'route' => 'blog_view', 'routeParameters' => array('id' => $request->get('id', 1)), 'display' => false )); return $menu; } public function getCurrentItem (FactoryInterface $factory, array $options) { $menu = $this->mainMenu($factory, $options); $matcher = $this->container->get('knp_menu.matcher'); $voter = $this->container->get('knp_menu.voter.router'); $matcher->addVoter($voter); $treeIterator = new \RecursiveIteratorIterator( new RecursiveItemIterator( new \ArrayIterator(array($menu)) ), \RecursiveIteratorIterator::SELF_FIRST ); $iterator = new CurrentItemFilterIterator($treeIterator, $matcher); // Set Current as an empty Item in order to avoid exceptions on knp_menu_get $current = new MenuItem('', $factory); foreach ($iterator as $item) { $current = $item; break; } return $current; } 


We have added a method for finding the current menu item. Now we need to pull it out. To do this, in our submission we write:
 {% set breadcrumbs = knp_menu_get('AcmeBlogBundle:Builder:getCurrentItem').getBreadcrumbsArray() %} <ul class="breadcrumb"> <li> <i class="icon-home"></i> <a href="{{ path('homepage') }}">Home</a> <span class="icon-angle-right"></span> </li> {% for link in breadcrumbs %} {% if link.label != 'root' %} <li> <a href="{{ link.uri }}">{{ link.label|trans }}</a> {% if not loop.last %} <span class="icon-angle-right"></span> {% endif %} </li> {% endif %} {% endfor %} </ul> 


Here we use the getBreadCrumbsArray() method, which will return what we need.

On this perhaps all. Hope was helpful. On errors, please request in PM, because the Chukchi is not a writer, the Chukchi developer. Add your own solutions to make the topic even more useful. Thanks for attention.

Source: https://habr.com/ru/post/177257/


All Articles