diff --git a/trunk/app/Resources/views/base.html.twig b/trunk/app/Resources/views/base.html.twig index 9f46a2c5..81f15918 100644 --- a/trunk/app/Resources/views/base.html.twig +++ b/trunk/app/Resources/views/base.html.twig @@ -74,6 +74,8 @@ {% block breadcrumb %} {% if page is defined %} {{ render(controller('AppBundle:Default:breadcrumb', {'page': page})) }} + {% elseif breadcrumb_entries is defined %} + {{ include('default/components/breadcrumb.html.twig') }} {% endif %} {% endblock %} @@ -81,7 +83,8 @@
{% include 'default/components/sidebar.html.twig' with { - nav_sidebar_widget_block: block('nav_sidebar_widget') + nav_sidebar_widget_block: block('nav_sidebar_widget'), + search_sidebar_widget_block: block('search_sidebar_widget'), } %}
diff --git a/trunk/app/Resources/views/default/components/breadcrumb.html.twig b/trunk/app/Resources/views/default/components/breadcrumb.html.twig index 3c7b4d20..7df019ab 100644 --- a/trunk/app/Resources/views/default/components/breadcrumb.html.twig +++ b/trunk/app/Resources/views/default/components/breadcrumb.html.twig @@ -8,9 +8,13 @@ {% for breadcrumb_entry in breadcrumb_entries %} {# @var breadcrumb_entry \AppBundle\Entity\BreadcrumbEntry #}
  • - + {% if not loop.last %} + + {{ breadcrumb_entry.title }} + + {% else %} {{ breadcrumb_entry.title }} - + {% endif %}
  • {% endfor %} diff --git a/trunk/app/Resources/views/default/components/footer.html.twig b/trunk/app/Resources/views/default/components/footer.html.twig index f98169e6..63332552 100644 --- a/trunk/app/Resources/views/default/components/footer.html.twig +++ b/trunk/app/Resources/views/default/components/footer.html.twig @@ -117,11 +117,11 @@
    diff --git a/trunk/app/Resources/views/default/components/header.html.twig b/trunk/app/Resources/views/default/components/header.html.twig index 62e97195..d74937bf 100644 --- a/trunk/app/Resources/views/default/components/header.html.twig +++ b/trunk/app/Resources/views/default/components/header.html.twig @@ -4,9 +4,21 @@
    diff --git a/trunk/app/Resources/views/default/components/pageBox.html.twig b/trunk/app/Resources/views/default/components/pageBox.html.twig index 62c8397c..6b1c4f02 100644 --- a/trunk/app/Resources/views/default/components/pageBox.html.twig +++ b/trunk/app/Resources/views/default/components/pageBox.html.twig @@ -14,19 +14,23 @@
    {{ child_page.boxDiscount|raw }}
    {% endif %} - {% if child_page.travelProgram is not empty and child_page.travelProgram.previewImage is not empty %} - {{ child_page.title }} + + {% if child_page.boxImageUrl is not empty %} + {% set image_url = child_page.boxImageUrl %} + {% set image_alt = child_page.travelProgram.title|default(child_page.title) %} + {% elseif child_page.boxImageUrl is not empty %} + {% set image_url = '/uploads/travel_program/' ~ child_page.travelProgram.previewImage.fileNameWithExtension %} + {% set image_alt = child_page.title %} {% else %} - {{ child_page.title }} + {% set image_url = '/bundles/app/images/no-picture.png' %} + {% set image_alt = 'Kein Vorschaubild vorhanden' %} {% endif %} + {{ image_alt  }} +
    {{ child_page.title }}
    -

    {{ child_page.description }}

    +

    {{ child_page.boxBody ?? child_page.description }}

    {{ child_page.title }} diff --git a/trunk/app/Resources/views/default/components/sidebar.html.twig b/trunk/app/Resources/views/default/components/sidebar.html.twig index 430e0594..a1118011 100644 --- a/trunk/app/Resources/views/default/components/sidebar.html.twig +++ b/trunk/app/Resources/views/default/components/sidebar.html.twig @@ -1,5 +1,17 @@ {%- endblock %} +{% block date_widget -%} + {% set attr = attr|merge({class: (attr.class|default('') ~ ' datepicker')|trim}) -%} +
    + {{ parent() -}} +
    +
    +{%- endblock %} + {% block checkbox_widget -%} {{- block('base_checkbox_widget') -}} {%- endblock checkbox_widget %} diff --git a/trunk/app/Resources/views/default/pages/booking.html.twig b/trunk/app/Resources/views/default/pages/booking.html.twig index d1db97a3..3faa8e5e 100644 --- a/trunk/app/Resources/views/default/pages/booking.html.twig +++ b/trunk/app/Resources/views/default/pages/booking.html.twig @@ -20,10 +20,6 @@ {% endjavascripts %} {% endblock %} -{% block breadcrumb %} - {{ include('default/components/breadcrumb.html.twig') }} -{% endblock %} - {% block body %}
    diff --git a/trunk/app/Resources/views/default/pages/overview.html.twig b/trunk/app/Resources/views/default/pages/overview.html.twig index d80de99b..1e8d0059 100644 --- a/trunk/app/Resources/views/default/pages/overview.html.twig +++ b/trunk/app/Resources/views/default/pages/overview.html.twig @@ -8,7 +8,7 @@ {% block body %}
    -
    {{ page.pagetitle ?? page.title }}
    +
    {{ page.pagetitle|default(page.title) }}
    {#{% for i in 0..page.children|length//3 %}#}
    diff --git a/trunk/app/Resources/views/default/pages/search.html.twig b/trunk/app/Resources/views/default/pages/search.html.twig index 9308b5bd..5d53a97e 100644 --- a/trunk/app/Resources/views/default/pages/search.html.twig +++ b/trunk/app/Resources/views/default/pages/search.html.twig @@ -15,11 +15,11 @@
    - {% for travel_program in travel_programs %} + {% for travel_program in travel_programs if travel_program.travelDates is not empty %}
    - p.P. ab {{ travel_program.lowestPrice|number_format }} €
    - {# #TODO #} - @@ -99,7 +98,7 @@ {# #TODO Bad performance #} - Details + Details {% endfor %} diff --git a/trunk/app/Resources/views/default/pages/travelProgram.html.twig b/trunk/app/Resources/views/default/pages/travelProgram.html.twig index bb408635..211dcc55 100644 --- a/trunk/app/Resources/views/default/pages/travelProgram.html.twig +++ b/trunk/app/Resources/views/default/pages/travelProgram.html.twig @@ -1,14 +1,31 @@ +{# @var travel_program \AppBundle\Entity\TravelProgram #} {% extends 'base.html.twig' %} +{% block javascripts %} + {{ parent() }} + {% javascripts '@AppBundle/Resources/public/js/travelProgram.js' %} + + {% endjavascripts %} +{% endblock %} + {% block body %}
    -

    {{ travel_program.title }}

    +

    {{ travel_program.title|default(page.pagetitle)|default(page.title) }}

    + + {# + ********* SLIDER ********* + #}
    - +
    -
    + {# + ********* TAB BAR ********* + #} + + {% block travel_program_tab_bar %}
    -
    + {% endblock travel_program_tab_bar %}
    -
    + {# + ********* REISEABLAUF ********* + #} + +
    {{ travel_program.htmlDescription|raw }} + {% if travel_program.advices is not empty %} +

    Hinweise

    +
      + {% for travel_program_advice in travel_program.advices|trim|split('\n') %} +
    • {{ travel_program_advice|raw }}
    • + {% endfor %} +
    + {% endif %} +
    -
    + {# + ********* LEISTUNGEN ********* + #} + +
    + +

    Eingeschlossene Leistungen

      {% for travel_program_service in travel_program.included|replace({'*': ''})|split('\n') %}
    • {{ travel_program_service|raw }}
    • {% endfor %}
    - {# -

    Unser Video

    -
    -

    Video Headline

    -
    - - - - - - -
    -
    - #} + + {% if travel_program.excluded is not empty or travel_program.classDescription is not empty %} +

    Nicht eingeschlossene Leistungen

    + {{ travel_program.classDescription|replace({'*': ''})|raw }} +
      + {% for travel_program_service in travel_program.excluded|replace({'*': ''})|split('\n') %} +
    • {{ travel_program_service|raw }}
    • + {% endfor %} +
    + {% endif %} +
    -
    + {# + ********* TERMINE UND PREISE ********* + #} + +

    {{ travel_program.subtitle }}

    @@ -194,21 +264,47 @@
    + + {# + ********* LANDKARTE ********* + #} + + {% if travel_program.hasMap %} +
    + + {% if travel_program.mapHtml is not empty %} + {{ travel_program.mapHtml|raw|stripslashes }} + {% else %} + + Karte zum Reiseablauf + + {% endif %} + +
    + {% endif %} + + {# + ********* LANDINFOS ********* + #} + +
    + + {% for country in travel_program.countries %} + +

    {{ country.name }}

    + {{ country.htmlInformation|raw }} + + {% endfor %} + +
    +
    - + {{ block('travel_program_tab_bar') }} +
    {% endblock body %} \ No newline at end of file diff --git a/trunk/app/Resources/views/default/pages/travelProgramOverview.html.twig b/trunk/app/Resources/views/default/pages/travelProgramOverview.html.twig index 30e6842a..c322e560 100644 --- a/trunk/app/Resources/views/default/pages/travelProgramOverview.html.twig +++ b/trunk/app/Resources/views/default/pages/travelProgramOverview.html.twig @@ -2,16 +2,33 @@ {% block body %}
    -
    {{ page.pagetitle ?? page.title }}
    +
    {{ page.pagetitle|default(page.title) }}
    {#{% for i in 0..page.children|length//3 %}#}
    - {% for child_page in child_pages if child_page.status == 1 and child_page.travelProgram is defined %} + {% for child_page in child_pages if child_page.status == 1 and child_page.travelProgram is not empty %} {% include 'default/components/pageBox.html.twig' %} {% endfor %}
    + + {% if mediated_child_pages is not empty %} + +

    + Vermittelte Rundreisen vom {{ page.country is not empty ? (page.country.name ~ '-') }}Spezialisten + STERN TOURS aus Berlin +

    + +
    + {% for child_page in mediated_child_pages %} + + {% include 'default/components/pageBox.html.twig' %} + + {% endfor %} +
    + {% endif %} +
    diff --git a/trunk/app/config/config_dev.yml b/trunk/app/config/config_dev.yml index 0709acc5..aeda918b 100644 --- a/trunk/app/config/config_dev.yml +++ b/trunk/app/config/config_dev.yml @@ -23,7 +23,7 @@ monolog: channels: [!event, !doctrine] browser_console: type: browser_console - level: debug + level: warning # uncomment to get logging in your browser # you may have to allow bigger header sizes in your Web server configuration #firephp: diff --git a/trunk/src/AppBundle/Controller/BookingController.php b/trunk/src/AppBundle/Controller/BookingController.php index 9b7f8b5d..4b9d19a6 100644 --- a/trunk/src/AppBundle/Controller/BookingController.php +++ b/trunk/src/AppBundle/Controller/BookingController.php @@ -83,7 +83,7 @@ class BookingController extends Controller if ($action == '/buchen') { $breadcrumbEntries = Util::createBreadcrumb($travelProgramPage); - $breadcrumbEntries[] = new BreadcrumbEntry('Buchen', $travelProgramPage->getUrlPath() .'/buchen'); + $breadcrumbEntries[] = new BreadcrumbEntry('Buchen'); if ($request->getMethod() == 'POST' && $form->isValid()) { diff --git a/trunk/src/AppBundle/Controller/DefaultController.php b/trunk/src/AppBundle/Controller/DefaultController.php index f4ac617b..7080c230 100644 --- a/trunk/src/AppBundle/Controller/DefaultController.php +++ b/trunk/src/AppBundle/Controller/DefaultController.php @@ -2,8 +2,10 @@ namespace AppBundle\Controller; +use AppBundle\Entity\BreadcrumbEntry; use AppBundle\Entity\Page; use AppBundle\Entity\TravelProgram; +use AppBundle\Form\SearchRequestType; use AppBundle\Util; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Query\Expr; @@ -74,10 +76,35 @@ class DefaultController extends Controller $childPages = $this->getEntityManager()->getRepository('AppBundle:Page')->getChildrenWithTravelProgramsAndDates($page); + $nonMediated = []; + $mediated = []; + foreach ($childPages as $childPage) + { + if ($childPage->getStatus() == 1 && $childPage->getTravelProgram() && + $childPage->getTravelProgram()->getIsMediated()) + { + $mediated[] = $childPage; + } + else + { + $nonMediated[] = $childPage; + } + } + // We only need a separation if there are mediated AND non mediated travel programs + if (empty($nonMediated) && !empty($mediated)) + { + $childPages = $mediated; + } + else + { + $childPages = $nonMediated; + } + return $this->render('default/pages/travelProgramOverview.html.twig', [ - 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, - 'page' => $page, - 'child_pages' => $childPages + 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, + 'page' => $page, + 'child_pages' => $childPages, + 'mediated_child_pages' => $mediated, ]); } @@ -98,28 +125,38 @@ class DefaultController extends Controller */ public function searchAction(Request $request) { - $stopwatch = $this->get('debug.stopwatch'); $em = $this->getEntityManager(); - $destinationIds = null; - $destination = $em->getRepository('AppBundle:TravelCountry')->find($request->query->get('c')); - if ($destination) - { - $destinationsIds = [$destination->getId()]; - } - $startDate = $request->query->has('b') - ? \DateTime::createFromFormat('d.m.Y', $request->query->get('b')) - : new \DateTime(); - $endDate = \DateTime::createFromFormat('d.m.Y', $request->query->get('e')); + $form = $this->createForm(SearchRequestType::class); + $form->handleRequest($request); - $stopwatch->start('search'); - $r = $this->getDoctrine()->getRepository('AppBundle:TravelPeriod')->getTravelProgramsWithTravelDatesForTimePeriod( - $startDate, $endDate, $destinationIds, true); - $stopwatch->stop('search'); + if ($form->isValid()) + { + $data = $form->getData(); + + $destinationIds = []; + if (!empty($data['c'])) + { + $destinationIds = [$data['c']->getId()]; + } + if (!empty($destinationIds) && !empty($data['c2'])) + { + $destinationIds[] = $data['c2']->getId(); + } + + $r = $this->getDoctrine()->getRepository('AppBundle:TravelPeriod')->getTravelProgramsWithTravelDatesForTimePeriod( + $data['b'], $data['e'], $destinationIds, count($destinationIds) > 1); + } + else + { + $r = []; + } return $this->render('default/pages/search.html.twig', [ - 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, - 'travel_programs' => $r + 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, + 'breadcrumb_entries' => [new BreadcrumbEntry('Suchen')], + 'search_form' => $form->createView(), + 'travel_programs' => $r, ]); } @@ -139,8 +176,8 @@ class DefaultController extends Controller ->execute() ; return $this->render('default/components/header.html.twig', [ - 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, - 'nav_pages' => $navPages + 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, + 'nav_pages' => $navPages, ]); } @@ -148,7 +185,7 @@ class DefaultController extends Controller { return $this->render('default/components/breadcrumb.html.twig', [ 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, - 'breadcrumb_entries' => Util::createBreadcrumb($page) + 'breadcrumb_entries' => Util::createBreadcrumb($page), ]); } @@ -200,6 +237,32 @@ class DefaultController extends Controller return $this->render('default/components/sidebar/navSidebarWidget.html.twig', $view); } + public function searchSidebarWidgetAction(Page $page) + { + $combinedDestination = null; + if ($page->getTravelProgram()) + { + $countries = $page->getTravelProgram()->getCountries(); + $destination = $countries->first(); + if (count($countries) > 1) + { + $combinedDestination = $countries[1]; + } + } + else + { + $destination = $page->getCountry(); + } + return $this->render('default/components/sidebar/searchSidebarWidget.html.twig', [ + 'search_form' => $this->createForm(SearchRequestType::class, [ + 'b' => new \DateTime('+5 day'), + 'e' => new \DateTime('+19 day'), + 'c' => $destination, + 'c2' => $combinedDestination, + ])->createView() + ]); + } + /* Suche Kindknoten Für jeden Kindknoten diff --git a/trunk/src/AppBundle/Entity/BreadcrumbEntry.php b/trunk/src/AppBundle/Entity/BreadcrumbEntry.php index f6044c75..e68767dc 100644 --- a/trunk/src/AppBundle/Entity/BreadcrumbEntry.php +++ b/trunk/src/AppBundle/Entity/BreadcrumbEntry.php @@ -18,7 +18,7 @@ class BreadcrumbEntry * @param $title * @param $url */ - public function __construct($title, $url) + public function __construct($title, $url = null) { $this->title = $title; $this->url = $url; diff --git a/trunk/src/AppBundle/Entity/TravelCountry.php b/trunk/src/AppBundle/Entity/TravelCountry.php index 714ae6ec..e1e6ac21 100644 --- a/trunk/src/AppBundle/Entity/TravelCountry.php +++ b/trunk/src/AppBundle/Entity/TravelCountry.php @@ -174,4 +174,11 @@ class TravelCountry { return $this->programs; } + + function __toString() + { + return $this->name; + } + + } diff --git a/trunk/src/AppBundle/Entity/TravelProgram.php b/trunk/src/AppBundle/Entity/TravelProgram.php index 11fa2c33..523da2e8 100644 --- a/trunk/src/AppBundle/Entity/TravelProgram.php +++ b/trunk/src/AppBundle/Entity/TravelProgram.php @@ -792,7 +792,7 @@ class TravelProgram /** * Get showMap * - * @return boolean + * @return int 1 for mapHtml, 2 for mapImage */ public function getShowMap() { @@ -1365,7 +1365,7 @@ class TravelProgram /** * Get countries * - * @return \Doctrine\Common\Collections\Collection + * @return \AppBundle\Entity\TravelCountry[]|\Doctrine\Common\Collections\Collection */ public function getCountries() { @@ -1551,4 +1551,9 @@ class TravelProgram { return $this->page; } + + public function getHasMap() + { + return ($this->showMap ?? 0) > 0 && ($this->mapHtml or $this->mapHtml); + } } diff --git a/trunk/src/AppBundle/Form/SearchRequestType.php b/trunk/src/AppBundle/Form/SearchRequestType.php new file mode 100644 index 00000000..e40099f0 --- /dev/null +++ b/trunk/src/AppBundle/Form/SearchRequestType.php @@ -0,0 +1,54 @@ + + * @date 02/16/2017 + */ + +namespace AppBundle\Form; + + +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class SearchRequestType extends AbstractType +{ + /** + * @param FormBuilderInterface $builder + * @param array $options + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->setMethod('GET'); + $builder + ->add('b', StDateType::class, ['required' => false]) + ->add('e', StDateType::class, ['required' => false]) + ->add('c', EntityType::class, [ + 'required' => false, + 'placeholder' => 'beliebiges Reiseziel', + 'class' => 'AppBundle\Entity\TravelCountry', + ]) + ->add('c2', EntityType::class, [ + 'required' => false, + 'placeholder' => 'Bitte wählen (optional)', + 'class' => 'AppBundle\Entity\TravelCountry', + ]) + ; + } + + /** + * @param OptionsResolver $resolver + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'csrf_protection' => false, + )); + } + + public function getBlockPrefix() + { + return null; + } +} \ No newline at end of file diff --git a/trunk/src/AppBundle/Form/StDateType.php b/trunk/src/AppBundle/Form/StDateType.php new file mode 100644 index 00000000..b9177a2c --- /dev/null +++ b/trunk/src/AppBundle/Form/StDateType.php @@ -0,0 +1,29 @@ + + * @date 02/16/2017 + */ + +namespace AppBundle\Form; + + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class StDateType extends AbstractType +{ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'placeholder' => 'TT.MM.JJJJ', + 'widget' => 'single_text', + 'format' => 'dd.MM.yyyy' + ]); + } + + public function getParent() + { + return DateType::class; + } +} \ No newline at end of file diff --git a/trunk/src/AppBundle/Listener/KernelControllerListener.php b/trunk/src/AppBundle/Listener/KernelControllerListener.php index 7bf0bc9f..aa451e62 100644 --- a/trunk/src/AppBundle/Listener/KernelControllerListener.php +++ b/trunk/src/AppBundle/Listener/KernelControllerListener.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\Routing\Router; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class KernelControllerListener { @@ -89,6 +90,15 @@ class KernelControllerListener $node = $childNode; ++$i; } + if ($node && $node->getRealUrlPath() && $node->getRealUrlPath() != '/'. $path) + { + // If there realUrlPath is set and the slug path differs from realUrlPath, then the slug path is + // not a valid URL. Otherwise, there would be two different URLs representing the same page. + $event->setController(function() { + throw new NotFoundHttpException('Invalid URL'); + }); + return; + } } if (!$node) diff --git a/trunk/src/AppBundle/Resources/public/images/no-picture.png b/trunk/src/AppBundle/Resources/public/images/no-picture.png new file mode 100644 index 00000000..bad2c085 Binary files /dev/null and b/trunk/src/AppBundle/Resources/public/images/no-picture.png differ diff --git a/trunk/src/AppBundle/Resources/public/js/travelProgram.js b/trunk/src/AppBundle/Resources/public/js/travelProgram.js new file mode 100644 index 00000000..e8ec5ee8 --- /dev/null +++ b/trunk/src/AppBundle/Resources/public/js/travelProgram.js @@ -0,0 +1,82 @@ +$(document).ready(function() { + + function scrollToTabContent(tabSelector) + { + $(document.body).animate({ + scrollTop: $(tabSelector).offset().top - 220 + }, 1000); + } + + function activateTravelDatesTab() + { + $('[href=\'#travel-dates-content-tab\']').tab('show'); + scrollToTabContent('#travel-dates-content-tab'); + } + + $('.nav-tabs > li > a').click(function() { + scrollToTabContent($(this).attr('href')); + }); + + $('.st-slider-booking-btn').click(activateTravelDatesTab); + + if (location.hash === '#travel-dates-content-tab') + { + activateTravelDatesTab(); + } + + + + var videos$ = $('a[id^="video_"]'); + + videos$.each(function() { + + var el$ = $(this); + + var text = el$.text(); + var length = text.length - 11; + var caption = text.substring(0, length); + var expl = this.id.substring(6, this.id.length); + + $('