📜 ⬆️ ⬇️

Creating a CRUD Application on Symfony 2, Part 2

Continuing introductory article on symfony 2 . In the first part , the process of modifying the form for editing records was described, in the second part we will modify the interface of the list of records. In the template template and the record list controller, which is generated by the doctrine: generate: crud command, at least there is not enough record search form and page-by-page navigation.

Classes for search form


Start by adding a search form. To create a search form, you need to create a class of the domain object in which the parameters for the search will be stored. For example, for a list of news it will be “search by substring”, a choice from the list of categories and search by date for news. You also need to create a search form class. The placement of such classes in symfony is unregulated; I use namespaces for search classes
The directory structure of the bundle (the beginning of the creation of the bundle, see the first part ) turns out the following:



Domain object with news search options


Data is transferred to the domain object after the form is submitted. Then the data from this object are used in drawing up the conditions for selecting records in the list.
')
<?php namespace Test\NewsBundle\Entity\Search; use Symfony\Component\Validator\Constraints as Assert; class News { /** *   * @var string */ public $search; /** *    * @var integer */ public $category; /** *      * @var DateTime * @Assert\DateTime */ public $dateFrom; /** * ,     * @var DateTime * @Assert\DateTime */ public $dateTo; } 


News Search Form


Because for the domain object used to store the search parameters, the connection with the database tables is not specified, for the category field (drop-down list), you must explicitly specify the entity that will be used to populate the list. Fields in which dates are entered are displayed as text fields (widget = single_text parameter). The text field attribute is added to the text field, which is used as a selector in jQueryUI (further described in the template). The form has CSRF protection disabled so that there is no additional parameter in the URL after submitting the form.

 <?php namespace Test\NewsBundle\Form\Search; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class NewsType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('search', 'search', array('required' => false, 'label' => ' ')) ->add('category', 'entity', array( 'label' => '', 'required' => false, 'class' => 'Test\\NewsBundle\\Entity\\NewsCategory')) ->add('dateFrom', 'date', array( 'label' => '', 'widget' => 'single_text', 'format' => 'yyyy-MM-dd', 'attr' => array('class' => 'date'), 'required' => false)) ->add('dateTo', 'date', array( 'label' => '', 'widget' => 'single_text', 'format' => 'yyyy-MM-dd', 'attr' => array('class' => 'date'), 'required' => false)); } public function getDefaultOptions(array $options) { return array( 'csrf_protection' => false, ); } function getName() { return 'searchorg'; } } 


Controller


In the Test / NewsBundle / Controller / NewsController controller, add the created classes to the indexAction () method.

 .. use Test\NewsBundle\Entity\Search\News as SearchNews; use Test\NewsBundle\Form\Search\NewsType as SearchNewsType; /** * News controller. * * @Route("/news") */ class NewsController extends Controller { /** *   * * @Route("/", name="news") * @Template() */ public function indexAction() { //  ,      $searchNews = new SearchNews(); //   $searchForm = $this->createForm(new SearchNewsType(), $searchNews); $searchForm->bindRequest($this->getRequest()); //   Doctrine $qb = $this->getDoctrine()->getEntityManager()->getRepository('TestNewsBundle:News') ->createQueryBuilder('n'); //   left join c  "" //          $qb->select('n,c')->leftJoin('n.newsCategory', 'c')->orderBy('n.pubDate'); //    -    LIKE   title, announce, text if ($searchNews->search) { foreach (array('n.title', 'n.announce', 'n.text') as $field) $qb->orWhere($qb->expr()->like($field, $qb->expr()->literal('%' . $searchNews->search . '%'))); } //  if ($searchNews->category) $qb->andWhere($qb->expr()->eq('c.id', $searchNews->category)); //     if ($searchNews->dateFrom) $qb->andWhere($qb->expr()->gt('n.pubDate', $qb->expr()->literal($searchNews->dateFrom->format('Ym-d')))); //     if ($searchNews->dateTo) $qb->andWhere($qb->expr()->lt('n.pubDate', $qb->expr()->literal($searchNews->dateTo->format('Ym-d')))); $entities = $qb->getQuery()->getResult(); return array('entities' => $entities, 'search_form' => $searchForm->createView()); } .... } 


Search form and record list template


Next, we modify the Test / NewsBundle / Resources / views / News / index.html.twig template to which we add the form display code.

 {% extends '::base.html.twig' %} {% block body %} <h1></h1> {% form_theme search_form 'form_table_layout.html.twig' %} <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script> <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/redmond/jquery-ui.css"> <script> $(function() { $("form input.date").datepicker({ dateFormat: 'yy-mm-dd'}); }); </script> <form action="{{ path('news') }}" method="get"> {{ form_errors(search_form) }} <table> {{ form_row(search_form.search) }} {{ form_row(search_form.category)}} <tr> <td colspan="2"> </td> </tr> {{ form_row(search_form.dateFrom)}} {{ form_row(search_form.dateTo)}} {{ form_rest(search_form) }} </table> <button type="submit"></button> </form> <table class="records_list"> <thead> <tr> <th>Id</th> <th></th> <th></th> <th></th> <th></th> <th></th> </tr> </thead> <tbody> {% for entity in entities %} <tr> <td><a href="{{ path('news_show', { 'id': entity.id }) }}">{{ entity.id }}</a></td> <td>{{ entity.title }}</td> <td>{{ entity.announce }}</td> <td>{{ entity.newsCategory }}</td> <td>{{ entity.pubDate|date('Ym-d') }}</td> <td> <ul> <li><a href="{{ path('news_show', { 'id': entity.id }) }}"></a></li> <li><a href="{{ path('news_edit', { 'id': entity.id }) }}"></a></li> </ul> </td> </tr> {% endfor %} </tbody> </table> <ul> <li> <a href="{{ path('news_new') }}">   </a> </li> </ul> {% endblock %} 

Now the list of news looks like this:



Installing the bundle for page navigation


Now you need to add pagination. You can of course write your own code, but it is much easier to use a ready-made bundle, for example, KnpPaginatorBundle . To install this bundle you need to add to the deps file:

 [knp-components] git=http://github.com/KnpLabs/knp-components.git [KnpPaginatorBundle] git=http://github.com/KnpLabs/KnpPaginatorBundle.git target=bundles/Knp/Bundle/PaginatorBundle 

To download you need to type in the command line:
 php bin/vendors install --reinstall 

The script bin / vendors uses Git , to download new bundles it must be installed on your system.
Add to the app / autoload.php file:
 $loader->registerNamespaces(array( 'Knp\\Component' => __DIR__.'/../vendor/knp-components/src', 'Knp\\Bundle' => __DIR__.'/../vendor/bundles', // ... )); 

To app / AppKernel.php
 public function registerBundles() { return array( // ... new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), // ... ); } 


Controller modification


In the Test / NewsBundle / Controller / NewsController controller, add the use of KnpPaginator to the indexAction () method after generating a query to the database in the QueryBuilder object. Instead of the standard list of entries in the template, we return an object of the Paginator class.

  $paginator = $this->get('knp_paginator'); $pagination = $paginator->paginate( $qb->getQuery(), $this->get('request')->query->get('page', 1)/*page number*/, 10/*limit per page*/ ); return array('entities' => $pagination, 'search_form' => $searchForm->createView()); 


Template modification


In the Test / NewsBundle / Resources / views / News / index.html.twig template below the table with the list of records, add the paginate tag call:

 <div id="navigation"> {{ entities.render()|raw }} </div> 

Now the list of news looks like this:



In the interface of the list of records now there is a search form and page navigation. It should be noted that a significant part of the presented code has already been generated automatically, so that the amount of code dobrabotki not very large.

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


All Articles