Собственно основные события происходят по созданию сего аккордеона происходят в контроллере - entity подстанций в данном случае, но это не принципиально в каком. И в шаблоне, который у меня включаемый, потому-что общий для нескольких видов других шаблонов. По нажатию по ссылке на аккордеоне в контенте шаблона должна выводиться таблица с подстанциями. Загвоздка в том, что после обновления страницы надо воспроизвести аккордеон в том виде в каком он был развернут пользователем. Код из контроллера подстанций:
............ protected $pos; protected $em; public function init() { $this->em = $this->getDoctrine() ->getManager(); $this->pos = $this->em->getRepository('BpBundle:Po') ->findAll(); } protected function getPo($po_id) { $em = $this->getDoctrine() ->getManager(); $po = $em->getRepository('BpBundle:Po')->find($po_id); if (!$po) { throw $this->createNotFoundException('Не найдено ПО.'); } return $po; } protected function getGP($gp_id) { $em = $this->getDoctrine() ->getManager(); $gp = $em->getRepository('BpBundle:GroupsPodst')->find($gp_id); if (!$gp) { throw $this->createNotFoundException('Не найдено ПО.'); } return $gp; } .......... public function indexAction($po_id, $is_po) { $this->init(); // $em = $this->getDoctrine()->getManager(); $repository = $em->getRepository('BpBundle:Podst'); if ($is_po) { $po = $this->getPo($po_id); $queryBuilder = $repository->createQueryBuilder('p') ->leftJoin('p.groupPodst', 'g') ->leftJoin('g.po', 'po') ->where('po = :po') ->orderBy('p.name') ->setParameter('po', $po); $podsts = $queryBuilder->getQuery()->getResult(); } else { $gp = $this->getGP($po_id); $po = $this->getPo($gp->getPo()->getId()); $podsts = $repository->findBy(array('groupPodst' => $gp),array('name' => 'ASC')); } ........ return $this->render('BpBundle:Podst:index.html.twig', array( 'podsts' => $podsts, 'po' => $is_po?$po:$gp, 'pos' => $this->pos, 'is_po' => $is_po, 'dostup' => $ok, )); } ............
Смотрим функцию indexAction($po_id, $is_po), в которой формируются данные для шаблона. Тут $is_po - сигнализирует нажата ли ссылка ПО - тогда надо выводить все подстанции ПО, если нет, то подстанции относящиеся к выбранной группе. Но главное, что важно для нашего аккордеона - мы для него передали в шаблон массив объектов $pos - то есть все ПО.
А теперь рассмотрим шаблон, который у нас сделан на twig.
{% extends '::base.html.twig' %} {% block sidebar %} <div class="bs-docs-sidebar"> {# Po accordion #} <div class="accordion" id="accordion1"> {% for po in pos %} <div class="accordion-group"> <div class="accordion-heading"> <a class="accordion-toggle btn btn-inverse" data-toggle="collapse" data-parent="#accordion1" href="http://demiware.ru/#collapse{{po.id}}"> {{po.name}} <i class=" icon-chevron-down icon-white"></i> </a> </div> <div id="collapse{{po.id}}" class="accordion-body collapse"> <div class="accordion-inner"> <div class="btn-group btn-group-vertical" data_toggle="radio-button"> <a id="b1_{{po.id}}" type="button" class="inv sbar btn btn-inverse" href="http://demiware.ru/{{ path('po_edit', { 'id': po.id }) }}"> Редактировать ПО <i class="icon-chevron-right icon-white"></i> </a> <a id="b2_{{po.id}}" type="button" class="inv sbar btn btn-inverse" href="http://demiware.ru/{{ path('podst', { 'po_id': po.id, 'is_po': 1 }) }}"> Все подстанции <i class="icon-chevron-right icon-white"></i> </a> </div> <br> <div class="btn-group btn-group-vertical" data_toggle="radio-button"> {% for gp in po.gps %} <a id="b_{{gp.id}}" class="sbar accordion-toggle btn btn-small btn-primary" href="http://demiware.ru/{{ path('podst', { 'po_id': gp.id, 'is_po': 0 }) }}" > {{gp.name}} <i class="icon-chevron-right icon-white"></i> </a> {% else %} <p>в {{po.name}} нет групп подстанций...</p> {% endfor %} </div> </div> </div> </div> {% else %} <p>таблица Po пуста...</p> {% endfor %} </div> </div> {% endblock %} {% block javascripts %} <script src="http://demiware.ru/{{ asset('js/bp.js') }}"></script> {% endblock %}
Первой строкой он расширяется базовым шаблоном, в котором хранятся все подключения основных CSS, главное меню, шапка, подвал и прочее. В свою очередь этот шаблон сам расширяет уже шаблоны в которых выводятся таблицы с подстанциями и другие некоторые. Цикл вывода содержимого аккордеона разбирать не будем, он понятен. Обратим внимание, что за скрипт подключен внизу в файле bp.js, в этом файле есть код касающийся данного аккордеона. Именно этот ява-скрипт позволяет сохранять его состояние в куки и выделять активный пункт.
$(document).ready(function() { .......................... //////////////////////Играем на аккордеоне////////////////////////////////// var last=$.cookie('activeAccordionGroup'); var pth=window.location.pathname; //alert(pth); if (last!==null && !(pth=="/" || pth=="/app_dev.php/")) { //remove default collapse settings $("#accordion1 .collapse").removeClass('in'); //show the last visible group $("#"+last).collapse("show"); } last=$.cookie('activeButton'); if (last!==null) { //$("a.sbar").removeClass('btn-info'); $("#"+last).removeClass('btn-inverse btn-primary'); $("#"+last).addClass('btn-info'); } //when a group is shown, save it as the active accordion group $("#accordion1 .collapse").on('show', function() { var active=$(this).attr('id'); $.cookie('activeAccordionGroup', active, { expires: 7, path: '/' }); }); $("a.sbar").on('click', function() { var last=$.cookie('activeButton'); if (last!==null) { $("#"+last).removeClass('btn-info'); if ($("#"+last).hasClass('inv')) { $("#"+last).addClass('btn-inverse'); } else { $("#"+last).addClass('btn-primary'); } } var active=$(this).attr('id'); $(this).removeClass('btn-inverse btn-primary'); $(this).addClass('btn-info'); $.cookie('activeButton', active, { expires: 7, path: '/' }); }); ........ });