src/Controller/PackageController.php line 242

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Service\CanonicalRedirectHelper;
  4. use App\Service\FormHelper;
  5. use App\Service\RecaptchaExtension;
  6. use Carbon\Carbon;
  7. use Elements\Bundle\HashCashBundle\Service\HashCashService;
  8. use Knp\Component\Pager\PaginatorInterface;
  9. use Pimcore\Translation\Translator;
  10. use Symfony\Component\HttpFoundation\RedirectResponse;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Pimcore\Model\DataObject;
  13. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  14. use Symfony\Component\Routing\Annotation\Route;
  15. use Pimcore\Db;
  16. class PackageController extends AbstractController
  17. {
  18.     private Translator $translator;
  19.     private FormHelper $formHelper;
  20.     public function __construct(Translator $translatorFormHelper $formHelper) {
  21.         $this->translator $translator;
  22.         $this->formHelper $formHelper;
  23.     }
  24.     public function overviewAction(Request $requestPaginatorInterface $paginator)
  25.     {
  26.         $selectedRegion null;
  27.         if ($this->document->getProperty('region') instanceof DataObject\Region && !$this->document->getProperty('region')->getIsMainRegion()) {
  28.             $selectedRegion $this->document->getProperty('region')->getId();
  29.         }
  30.         $selectedRegion $request->get("regions"$selectedRegion);
  31.         $regions = new DataObject\Region\Listing();
  32.         $regionsSelect = [[
  33.             "label" => "",
  34.             "value" => "",
  35.             "disabled" => true,
  36.             "selected" => $selectedRegion false true,
  37.             "class" => "sr-only",
  38.         ]];
  39.         foreach ($regions as $key => $region) {
  40.             $regionsSelect[] = [
  41.                 "label" => $region->getName(),
  42.                 "value" => $region->getId(),
  43.                 "class" => "",
  44.                 "selected" => $selectedRegion && $selectedRegion == $region->getId()
  45.             ];
  46.         }
  47.         $condition = [];
  48.         $optionCategories $baseCategories = [];
  49.         if($this->getDocumentEditable('relations''basecategories') && !empty($this->getDocumentEditable('relations''basecategories')->getData())) {
  50.             foreach($this->getDocumentEditable('relations''basecategories') as $basecategory) {
  51.                 $baseCategories[$basecategory->getId()] =  $basecategory->getId();
  52.             }
  53.             $allBaseCategoryIds $this->getChildObjectIds($baseCategories, ['packageCategory'], true);
  54.         }
  55.         if($this->getDocumentEditable('relations''optioncategories') && !empty($this->getDocumentEditable('relations''optioncategories')->getData())) {
  56.             foreach($this->getDocumentEditable('relations''optioncategories') as $optioncategory) {
  57.                 $optionCategories[$optioncategory->getId()] =  $optioncategory;
  58.             }
  59.         }
  60.         $selectedCategory $request->get("category");
  61.         $packageCategories = new DataObject\PackageCategory\Listing();
  62.         if(!empty($allBaseCategoryIds)) {
  63.             $packageCategories->addConditionParam('o_id IN (:ids)', ['ids' => $allBaseCategoryIds ]);
  64.         }
  65.         $packageCategories->setOrderKey('name');
  66.         $packageCategories->addConditionParam("name != '' ");
  67.         $categoriesSelect = [[
  68.             "label" => "",
  69.             "value" => "",
  70.             "disabled" => true,
  71.             "selected" => $selectedCategory == null,
  72.             "class" => "sr-only",
  73.         ]];
  74.         foreach ($packageCategories as $key => $packageCategory) {
  75.             if(array_key_exists($packageCategory->getId(),  $optionCategories) ){
  76.                 $categoriesSelect[] = [
  77.                     "label" => $packageCategory->getName(),
  78.                     "value" => $packageCategory->getId(),
  79.                     "class" => "",
  80.                     "selected" => $selectedCategory && $selectedCategory == $packageCategory->getId()
  81.                 ];
  82.             }
  83.         }
  84.         $selectedPrice $request->get('price');
  85.         $priceIntervals $this->getDocumentEditable('input''priceintervals') != '' explode(','$this->getDocumentEditable('input''priceintervals')) : [];
  86.         $priceRanges $this->getPriceRanges($priceIntervals);
  87.         $priceSelect = [[
  88.             "label" => "",
  89.             "value" => "",
  90.             "disabled" => true,
  91.             "selected" => $selectedPrice == null,
  92.             "class" => "sr-only",
  93.         ]];
  94.         foreach ($priceRanges as $key => $priceRange) {
  95.             if($priceRange['from'] != '' && $priceRange['to'] != '') {
  96.                 $label $priceRange['from'] . ' - ' $priceRange['to'] . ' €';
  97.             } elseif($priceRange['from'] != '') {
  98.                 $label =  '> ' $priceRange['from'] . ' €';
  99.             } elseif($priceRange['to'] != '') {
  100.                 $label '< ' $priceRange['to'] . ' €';
  101.             }
  102.             $priceSelect[] = [
  103.                 "label" => $label ?? '',
  104.                 "value" => $key,
  105.                 "class" => "",
  106.                 "selected" => $selectedPrice && $selectedPrice == $key
  107.             ];
  108.         }
  109.         $dateFrom $request->get('from');
  110.         if($dateFrom) {
  111.             $dateFrom Carbon::createFromFormat('Y-m-d H:i:s'str_replace('T'' '$request->get('from')) );
  112.         }
  113.         $dateTo $request->get('to');
  114.         if($dateTo) {
  115.             $dateTo Carbon::createFromFormat('Y-m-d H:i:s'str_replace('T'' '$request->get('to')) );
  116.         }
  117.         $offers = new DataObject\Package\Listing();
  118.         //alle 82, busreisen: 4, ys 1
  119.         $packageTypes $this->getDocumentEditable('multiselect''packageTypes')->getData();
  120.         $packageSubQueries = [];
  121.         foreach ($packageTypes as $packageType) {
  122.             if($packageType === 'styriaPackages') {
  123.                 $packageSubQueries[] = '(isBusTour is null OR isBusTour = 0) AND (isYoungStyria is null OR isYoungStyria = 0)';
  124.             } elseif($packageType === 'busTour') {
  125.                 $packageSubQueries[] = 'isBusTour is not null AND isBusTour = 1';
  126.             } elseif($packageType === 'isYoungStyria') {
  127.                 $packageSubQueries[] = 'isYoungStyria is not null AND isYoungStyria = 1';
  128.             }
  129.         }
  130.         if(!empty($packageSubQueries)) {
  131.             $offers->addConditionParam(implode(' OR '$packageSubQueries));
  132.         }
  133.         if($selectedRegion && ($region DataObject\Region::getById($selectedRegion))) {
  134.             $regionsAndCommunitiesIds $this->getChildRegionAndCommunityIds($regiontrue);
  135.             $subRegionCondition = [];
  136.             foreach ($regionsAndCommunitiesIds as $id) {
  137.                 $subRegionCondition[] = "regions LIKE '%,object|" $id ",%'";
  138.             }
  139.             if(!empty($subRegionCondition)) {
  140.                 $offers->addConditionParam('('.  implode(' OR '$subRegionCondition) . ')');
  141.             }
  142.         }
  143.         if($selectedCategory) {
  144.             $offers->addConditionParam("categories LIKE :cat", ['cat' => '%,' $selectedCategory ',%']);
  145.         } elseif(!empty($allBaseCategoryIds)) {
  146.             $subconditions = [];
  147.             foreach($allBaseCategoryIds as $baseCategoryId) {
  148.                 $subconditions[] = 'categories LIKE "%,' $baseCategoryId ',%"';
  149.             }
  150.             if(!empty($subconditions)) {
  151.                 $offers->addConditionParam('(' implode(' OR '$subconditions) . ')');
  152.             }
  153.         }
  154.         $offerBeginDate = [];
  155.         $offerCount 0;
  156.         if($this->getDocumentEditable('checkbox''datefilter')->isChecked() && $dateFrom && $dateFrom instanceof Carbon) {
  157.             #also considering the min. nights the guest has to stay
  158.             $offerBeginDate[] = '(beginDate <= ' $dateFrom->getTimestamp() . ' OR beginDate >= ' $dateFrom->getTimestamp() . ')';
  159.             $offerBeginDate[] = 'endDate >= ' $dateFrom->getTimestamp();
  160.         }
  161.         if($this->getDocumentEditable('checkbox''datefilter')->isChecked() && $dateTo && $dateTo instanceof Carbon) {
  162.             #also considering the min. nights the guest has to stay
  163.             $offerBeginDate[] = 'beginDate <= ' $dateTo->getTimestamp();
  164.         } else { // if no timerange is used => show only packages that are not in the past
  165.             $offerBeginDate[] = 'endDate >= ' Carbon::now()->getTimestamp();
  166.         }
  167.         if(!empty($offerBeginDate)){
  168.             $packagePeriod Db::get()->createQueryBuilder();
  169.             $packagePeriod->select('o_id')->from('object_collection_PackagePeriod_78')->where(implode(' AND '$offerBeginDate));
  170.             $ids $packagePeriod->execute()->fetchAll();
  171.             $ids array_map(function($a){return $a['o_id'];}, $ids);
  172.             $offerCount count($ids);
  173.             if($offerCount 0) {
  174.                 $offers->addConditionParam('o_id IN (' implode(','$ids) . ')');
  175.             }
  176.         }
  177.         if($selectedPrice) {
  178.             if($priceRanges[$selectedPrice]['from'] != '' && $priceRanges[$selectedPrice]['to'] != '') {
  179.                 $offers->addConditionParam("price != '' and price >= :priceFrom and price <= :priceTo", ['priceFrom' => $priceRanges[$selectedPrice]['from'], 'priceTo' => $priceRanges[$selectedPrice]['to']]);
  180.             } elseif($priceRanges[$selectedPrice]['from'] != '' ) {
  181.                 $offers->addConditionParam("price != '' and price > :priceFrom", ['priceFrom' => $priceRanges[$selectedPrice]['from']]);
  182.             } elseif($priceRanges[$selectedPrice]['to'] != '') {
  183.                 $offers->addConditionParam("price != '' and price < :priceTo", ['priceTo' => $priceRanges[$selectedPrice]['to']]);
  184.             }
  185.         }
  186.         // p_r($offers->getCondition()); die();
  187.         $limit = (int) $this->getDocumentEditable('numeric''numTeasers')->getData();
  188.         if ($limit <= 0) {
  189.             $limit 8;
  190.         }
  191.         if($this->getDocumentEditable('checkbox''randomize-package')->isChecked()) {
  192.             $offers->setOrderKey("Rand(" Carbon::today()->unix() . ")"false);
  193.         }
  194.         if($offerCount == 0){
  195.             $offers =  [];
  196.         }
  197.         $paginator $paginator->paginate($offers, (int)$request->get('page',1), $limit);
  198.         $paginator->setPageRange(3);
  199.         if ($request->isXmlHttpRequest()) {
  200.             return $this->json([
  201.                 'success' => true,
  202.                 'html' => $this->renderView('Package/Includes/top-offers-list.html.twig', ['paginator' => $paginator])
  203.             ]);
  204.         }
  205.         return $this->renderTemplate('Package/overview.html.twig', [
  206.             'regionsSelect'  => $regionsSelect,
  207.             'packageCategories' => $categoriesSelect,
  208.             'paginator' => $paginator,
  209.             'top-offers' => $offers,
  210.             'priceSelect' => $priceSelect,
  211.             'dateTo' => $dateTo,
  212.             'dateFrom' => $dateFrom,
  213.         ]);
  214.     }
  215.     public function detailAction(Request $requestHashCashService $hashCashServiceCanonicalRedirectHelper $redirectHelper)
  216.     {
  217.         if($request->isMethod('post')) {
  218.             $res $this->inquiry($request$hashCashService);
  219.             if($res instanceof RedirectResponse) {
  220.                 return $res;
  221.             }
  222.         }
  223.         $package DataObject\Package::getById($request->get('id'0));
  224.         if (!$package){
  225.             throw new NotFoundHttpException("the requested object doesn't exist anymore");
  226.         }
  227.         if (CanonicalRedirectHelper::ENABLE_CANONICAL_REDIRECT && $redirect $redirectHelper->canonicalRedirect($package)) {
  228.             return $redirect;
  229.         }
  230.         $topicSelect = [[
  231.             "label" => "",
  232.             "value" => "",
  233.             "disabled" => true,
  234.             "selected" => true,
  235.             "class" => "sr-only",
  236.         ]];
  237.         foreach ($package->getCategories() as $cat) {
  238.             $topicSelect[] = [
  239.                 "label" => $cat->getName(),
  240.                 "value" => $cat->getId(),
  241.                 "class" => ""
  242.             ];
  243.         }
  244.         $regionSelect = [[
  245.             "label" => "",
  246.             "value" => "",
  247.             "disabled" => true,
  248.             "selected" => true,
  249.             "class" => "sr-only",
  250.         ]];
  251.         foreach ($package->getRegions() as $reg) {
  252.             $regionSelect[] = [
  253.                 "label" => $reg->getName(),
  254.                 "value" => $reg->getId(),
  255.                 "class" => ""
  256.             ];
  257.         }
  258.         $adultsSelect = [[
  259.             "label" => "",
  260.             "value" => "",
  261.             "disabled" => true,
  262.             "selected" => true,
  263.             "class" => "sr-only",
  264.         ]];
  265.         $childrenSelect = [[
  266.             "label" => "",
  267.             "value" => "",
  268.             "disabled" => true,
  269.             "selected" => true,
  270.             "class" => "sr-only",
  271.         ]];
  272.         for($i 0$i <= 10$i++) {
  273.             $val = [
  274.                 "label" => $i,
  275.                 "value" => $i,
  276.                 "class" => ""
  277.             ];
  278.             if ($i 0$adultsSelect[] = $val;
  279.             $childrenSelect[] = $val;
  280.         }
  281.         [$packageDatesTK$packageDates] = $this->getPackageDatesTK($package$request->getLocale());
  282.         return $this->renderTemplate('Package/detail.html.twig', [
  283.             'package' => $package,
  284.             'packageDates' => $packageDates,
  285.             'packageDatesTK' => $packageDatesTK,
  286.             'topicSelect' => $topicSelect,
  287.             'regionSelect' => $regionSelect,
  288.             'adultsSelect' => $adultsSelect,
  289.             'childrenSelect' => $childrenSelect,
  290.             'errors' => $res ?? []
  291.         ]);
  292.     }
  293.     /**
  294.      * @Route("/contact-modal", name="contact-modal")
  295.      * @param Request $request
  296.      */
  297.     private function inquiry(Request $requestHashCashService $hashCashService) {
  298.         $params = [];
  299. //        p_r($hashCashService->validateProcessFrom()); die();
  300.         if ($hashCashService->validateProcessFrom()) {
  301.             $requiredParams = [
  302.                 'packageId',
  303.                 'packageName',
  304.                 'salutation',
  305.                 'firstname',
  306.                 'lastname',
  307.                 'email',
  308.                 'arrival',
  309.                 'departure',
  310.             ];
  311.             $package DataObject\Package::getById($request->get('packageId'));
  312.             $optionalParams = [
  313.                 'phone',
  314.                 'title',
  315.             ];
  316.             if($package->getIsBusTour()) {
  317.                 $requiredParams[] = 'persons';
  318.                 $optionalParams[] = 'doublerooms';
  319.                 $optionalParams[] = 'singlerooms';
  320.             } else {
  321.                 $requiredParams[] = 'adults';
  322.                 $optionalParams[] = 'children';
  323.             }
  324.             $errors = [];
  325.             if(!$package) {
  326.                 $errors[] = 'no valid package';
  327.             }
  328.             if($package->getEnableCategoriesInForm()) {
  329.                 $requiredParams[] = 'topic';
  330.             }
  331.             if($package->getEnableRegionsInForm()) {
  332.                 $requiredParams[] = 'region';
  333.             }
  334.             foreach ($requiredParams as $param) {
  335.                 if (!$request->get($paramnull)) {
  336.                     $errors[] = $param;
  337.                     continue;
  338.                 }
  339.                 $params[$param] = $request->get($param);
  340.             }
  341.             if(isset($params['salutation'])) {
  342.                 $params['salutation'] = $this->translator->trans($params['salutation']);
  343.             }
  344.             foreach ($optionalParams as $param) {
  345.                 if ($val $request->get($param)) {
  346.                     $params[$param] = $val;
  347.                 }
  348.             }
  349.             if(array_key_exists('children'$params) && $params['children'] > 0) {
  350.                 $params['childAge'] = $this->formHelper->getTranslatedChildAges($request->get('ca0', []));
  351.             }
  352.             $config $this->document->getProperty('siteConfig');
  353.             if (!$config instanceof DataObject\SiteConfig) {
  354.                 $errors[] = 'config';
  355.             }
  356.         } else {
  357.             $errors[] = 'hashcash not valid';
  358.         }
  359.         if(empty($errors)) {
  360.             $arrivalDate Carbon::createFromFormat('Y-m-d H:i:s'str_replace('T'' '$params['arrival']));
  361.             $params['arrival'] = $arrivalDate $arrivalDate->format('d.m.Y') : null;
  362.             $departureDate Carbon::createFromFormat('Y-m-d H:i:s'str_replace('T'' '$params['departure']));
  363.             $params['departure'] = $departureDate $departureDate->format('d.m.Y') : null;
  364.             $mailDoc $config->getTopOffersMail();
  365.             $mailDocUser $config->getTopOffersMailUser();
  366.             $successPage $config->getTopOffersMailSuccessPage();
  367.             if($package->getIsBusTour()) {
  368.                 if($config->getTopOffersMailBusTravel()) {
  369.                     $mailDoc =$config->getTopOffersMailBusTravel();
  370.                 }
  371.                 if($config->getTopOffersMailUserBusTravel()) {
  372.                     $mailDocUser $config->getTopOffersMailUserBusTravel();
  373.                 }
  374.                 if($config->getTopOffersMailSuccessPageBusTravel()) {
  375.                     $successPage $config->getTopOffersMailSuccessPageBusTravel();
  376.                 }
  377.             } elseif($package->getIsYoungStyria()) {
  378.                 if($config->getTopOffersMailYoungStyria()) {
  379.                     $mailDoc $config->getTopOffersMailYoungStyria();
  380.                 }
  381.                 if($config->getTopOffersMailUserYoungStyria()) {
  382.                     $mailDocUser $config->getTopOffersMailUserYoungStyria();
  383.                 }
  384.                 if($config->getTopOffersMailSuccessPageYoungStyria()) {
  385.                     $successPage $config->getTopOffersMailSuccessPageYoungStyria();
  386.                 }
  387.             }
  388.             if($mailDoc) {
  389.                 $notification = new \Pimcore\Mail();
  390.                 //default take from backend settings
  391.                 if(!\Pimcore::inDebugMode() && $package DataObject\Package::getById($request->get('packageId'0))) {
  392.                     if(($poi $package->getPoi()) && ($mail $package->getPoi()->getEmail())) {
  393.                         $notification->addTo($mail);
  394.                     }else{
  395.                         if($mail $package->getEmail()){
  396.                             $notification->addTo($mail);
  397.                         }
  398.                     }
  399.                 }
  400.                 if ($package->getIsBusTour()){
  401.                     $params['items'] = ['packageId''packageName''salutation''firstname''lastname''email''arrival''departure''persons''doublerooms''singlerooms''message'];
  402.                 } else {
  403.                     $params['items'] = ['packageId''packageName''salutation''firstname''lastname''email''arrival''departure''adults''childAge''message'];
  404.                 }
  405.                 $notification->setDocument($mailDoc);
  406.                 $notification->setParams($params);
  407.                 $notification->send();
  408.             } else {
  409.                 $errors[] = 'mail admin';
  410.             }
  411.             if($mailDocUser) {
  412.                 $notification = new \Pimcore\Mail();
  413.                 if($package->getIsBusTour()){
  414.                     $params['items'] = ['packageName''salutation''firstname''lastname''email''arrival''departure''persons''doublerooms''singlerooms''message'];
  415.                 } else {
  416.                     $params['items'] = ['packageName''salutation''firstname''lastname''email''arrival''departure''adults''childAge''message'];
  417.                 }
  418.                 $notification->setDocument($mailDocUser);
  419.                 $notification->addTo($params['email']);
  420.                 $notification->setParams($params);
  421.                 $notification->send();
  422.                 if($successPage $config->getTopOffersMailSuccessPage()) {
  423.                     return $this->redirect($successPage->getFullPath());
  424.                 }
  425.             } else {
  426.                 $errors[] = 'mail user';
  427.             }
  428.             if(empty($errors) && $successPage) {
  429.                 return $this->redirect($successPage->getFullPath());
  430.             }
  431.         }
  432.         return $errors;
  433.     }
  434.     protected function getChildObjectIds($parentIds = [], $filterClasses = [], $includeParents false) {
  435.         $return = [];
  436.         if(!empty($parentIds)) {
  437.             if($includeParents) {
  438.                 $return $parentIds;
  439.             }
  440.             $paths = [];
  441.             foreach($parentIds as $parentId) {
  442.                 $_obj \Pimcore\Model\DataObject::getById($parentId);
  443.                 if ($_obj instanceof \Pimcore\Model\DataObject) {
  444.                     $paths[] = $_obj->getFullPath();
  445.                 }
  446.             }
  447.             if(!empty($paths)) {
  448.                 $condition = [];
  449.                 $subcondition = [];
  450.                 foreach($paths as $path) {
  451.                     $subcondition[] = 'o_path LIKE "'.$path.'/%"';
  452.                 }
  453.                 if(!empty($subcondition)) {
  454.                     $condition[] = '(' implode(' OR '$subcondition) . ')';
  455.                 }
  456.                 if(!empty($filterClasses)) {
  457.                     $subcondition = [];
  458.                     foreach($filterClasses as $filterClass) {
  459.                         $subcondition[] = 'o_className = "'.lcfirst($filterClass).'"';
  460.                     }
  461.                     $condition[] = '('.implode(' OR '$subcondition).')';
  462.                 }
  463.                 if(!empty($condition)) {
  464.                     $list = new \Pimcore\Model\DataObject\Listing();
  465.                     $list->setCondition(implode(' AND ' $condition));
  466.                 }
  467.                 foreach($list as $object) {
  468.                     $return[] = $object->getId();
  469.                 }
  470.             }
  471.         }
  472.         return array_unique($return);
  473.     }
  474.     private function getPriceRanges(array $priceIntervals = []) {
  475.         $normalizedIntervals = [];
  476.         foreach ($priceIntervals as $entry) {
  477.             $e trim($entry);
  478.             if (is_numeric($e) && (int)$e != 0) {
  479.                 $normalizedIntervals[] = (int)$e;
  480.             }
  481.         }
  482.         sort($normalizedIntervals);
  483.         $priceRanges = [];
  484.         $last count($normalizedIntervals ?? []) - 1;
  485.         $preventry 0;
  486.         foreach ($normalizedIntervals as $count => $entry) {
  487.             if ($count == 0) {
  488.                 $priceRanges[$count 1] = ['to' => $entry'from' => ''];
  489.             } else {
  490.                 $priceRanges[$count 1] = ['from' => $preventry'to' => $entry];
  491.             }
  492.             $preventry $entry;
  493.         }
  494.         if ($preventry) {
  495.             $priceRanges[$count 2] = ['from' => $preventry'to' => ''];
  496.         }
  497.         return $priceRanges;
  498.     }
  499.     protected function getChildRegionAndCommunityIds(\Pimcore\Model\DataObject\Region $region$includeParent false) {
  500.         $lifetime 60*30;   #30 minutes
  501.         $cacheKey md5('region-'.$region->getId().($includeParent '-parent' '-children'));
  502.         if(!$ids \Pimcore\Cache::load($cacheKey)) {
  503.             try {
  504.                 $ids $includeParent ? [$region->getId()] : [];
  505.                 $regionList = new \Pimcore\Model\DataObject\Region\Listing();
  506.                 $regionList->setCondition('o_path LIKE "'.$region->getFullPath().'/%"');
  507.                 foreach($regionList as $_region) {
  508.                     $ids[] = $_region->getId();
  509.                 }
  510.                 $communityList = new \Pimcore\Model\DataObject\Community\Listing();
  511.                 $communityList->setCondition('o_path LIKE "'.$region->getFullPath().'/%"');
  512.                 foreach($communityList as $_community) {
  513.                     $ids[] = $_community->getId();
  514.                 }
  515.                 \Pimcore\Cache::save(array_unique($ids), $cacheKey, array("output"), $lifetime);
  516.             } catch (\Exception $e) {
  517.             }
  518.         }
  519.         return $ids;
  520.     }
  521.     private function getPackageDatesTK(DataObject\Package $packageString $lang) : array {
  522.         $packageDatesTK = [];
  523.         $packageDates = [];
  524.         $first true;
  525.         foreach($package->getPeriods() ?: [] as $period) {
  526.             if(Carbon::now()->lte($period->getEndDate()) ) {
  527.                 $date $period->getBeginDate()->format('d.m.Y') . ' - ' $period->getEndDate()->format('d.m.Y');
  528.                 $packageDates[] =  $date ;
  529.                 if($first) {
  530.                     $first false;
  531.                     $date $this->translator->trans('package-detail.Gültig von: ', [], null$lang) . ' '$date;
  532.                 }
  533.                 $packageDatesTK[] =  $date ;
  534.             }
  535.         }
  536.         return [!empty($packageDatesTK) ? "<div>" implode(",</div><div>"$packageDatesTK) . "</div>" ""$packageDates];
  537.     }
  538. }