feat: base travel info on product and provide date via url
This commit is contained in:
@@ -173,16 +173,26 @@ routeEnhancers:
|
||||
- 2712
|
||||
routes:
|
||||
-
|
||||
routePath: '/{travelinfo}'
|
||||
routePath: '/{travelinfo}/{traveldate}'
|
||||
_controller: 'Travelinfo::index'
|
||||
_arguments:
|
||||
travelinfo: travelinfo
|
||||
traveldate: travelDate
|
||||
-
|
||||
routePath: '/{busproid}'
|
||||
_controller: 'Travelinfo::myep'
|
||||
_arguments:
|
||||
busproid: busProId
|
||||
defaultController: 'Travelinfo::index'
|
||||
aspects:
|
||||
travelinfo:
|
||||
type: PersistedAliasMapper
|
||||
tableName: tx_epproducts_domain_model_travelinfo
|
||||
routeFieldName: path_segment
|
||||
traveldate:
|
||||
type: PassthroughMapper
|
||||
busproid:
|
||||
type: PassthroughMapper
|
||||
ContingentsIcalPlugin:
|
||||
type: Extbase
|
||||
extension: EpProducts
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
use EP\EpProducts\Domain\Model\Date;
|
||||
use EP\EpProducts\Domain\Model\Travelinfo;
|
||||
use EP\EpProducts\Domain\Repository\DateRepository;
|
||||
use EP\EpProducts\Domain\Repository\TravelInfoRepository;
|
||||
use TYPO3\CMS\Core\Http\ImmediateResponseException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
@@ -16,24 +18,49 @@ class TravelinfoController extends ActionController
|
||||
*/
|
||||
private $dateRepository;
|
||||
|
||||
public function __construct(DateRepository $dateRepository)
|
||||
/**
|
||||
* @var TravelInfoRepository
|
||||
*/
|
||||
private $travelInfoRepository;
|
||||
|
||||
public function __construct(DateRepository $dateRepository, TravelInfoRepository $travelInfoRepository)
|
||||
{
|
||||
$this->dateRepository = $dateRepository;
|
||||
$this->travelInfoRepository = $travelInfoRepository;
|
||||
}
|
||||
|
||||
public function indexAction(Travelinfo $travelinfo)
|
||||
public function myepAction(int $busProId)
|
||||
{
|
||||
$today = new \DateTimeImmutable();
|
||||
$date = $this->dateRepository->findOneByCode($travelinfo->getTravelCode());
|
||||
/** @var Date $date */
|
||||
$date = $this->dateRepository->findOneByBusProId($busProId);
|
||||
$travelinfo = $this->travelInfoRepository->findOneByProduct($date->getProduct());
|
||||
|
||||
if (null === $date || $date->getDateEnd() < $today) {
|
||||
if (null === $travelinfo) {
|
||||
$response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
|
||||
$GLOBALS['TYPO3_REQUEST'],
|
||||
'Reiseinformationen nicht gefunden oder Termin abgelaufen'
|
||||
'Reiseinformationen nicht gefunden'
|
||||
);
|
||||
throw new ImmediateResponseException($response, 1731071856);
|
||||
}
|
||||
|
||||
$this->redirect(
|
||||
'index',
|
||||
null,
|
||||
null,
|
||||
[
|
||||
'travelinfo' => $travelinfo,
|
||||
'travelDate' => $date->getDateStart()->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function indexAction(Travelinfo $travelinfo, string $travelDate)
|
||||
{
|
||||
$product = $travelinfo->getProduct();
|
||||
|
||||
/** @var Date $date */
|
||||
$date = $this->dateRepository->findForProductAndDate($product, $travelDate)->getFirst();
|
||||
|
||||
$this->view->assign('travelinfo', $travelinfo);
|
||||
$this->view->assign('date', $date);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,16 @@ class Travelinfo extends AbstractEntity
|
||||
*/
|
||||
protected $travelCode;
|
||||
|
||||
/**
|
||||
* @var Product
|
||||
*/
|
||||
protected $product;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hideAddress = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->initStorageObjects();
|
||||
@@ -259,5 +269,27 @@ class Travelinfo extends AbstractEntity
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProduct()
|
||||
{
|
||||
return $this->product;
|
||||
}
|
||||
|
||||
public function setProduct($product)
|
||||
{
|
||||
$this->product = $product;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isHideAddress()
|
||||
{
|
||||
return $this->hideAddress;
|
||||
}
|
||||
|
||||
public function setHideAddress($hideAddress)
|
||||
{
|
||||
$this->hideAddress = $hideAddress;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,5 +2,20 @@
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
use EP\EpProducts\Domain\Model\Product;
|
||||
|
||||
class DateRepository extends AbstractRepository
|
||||
{}
|
||||
{
|
||||
public function findForProductAndDate(Product $product, string $date)
|
||||
{
|
||||
$query = $this->createQuery();
|
||||
|
||||
return $query
|
||||
->matching($query->logicalAnd([
|
||||
$query->equals('product', $product),
|
||||
$query->equals('dateStart', $date),
|
||||
]))
|
||||
->execute()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Repository;
|
||||
|
||||
class TravelInfoRepository extends AbstractRepository
|
||||
{}
|
||||
+33
-6
@@ -27,7 +27,8 @@ return [
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'basics' => ['showitem' => 'title,path_segment,--linebreak--,travel_code,--linebreak--,links,--linebreak--,teasers'],
|
||||
'basics' => ['showitem' => 'title,path_segment,--linebreak--,product,hide_address,--linebreak--,links,
|
||||
--linebreak--,teasers'],
|
||||
'text' => ['showitem' => 'subline,headline,--linebreak--,intro_text,--linebreak--,footer_text,--linebreak--,
|
||||
self_arranged_text,--linebreak--,additional_info,--linebreak--,important_phone_numbers,--linebreak--,
|
||||
important_links'],
|
||||
@@ -190,13 +191,39 @@ return [
|
||||
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
|
||||
),
|
||||
],
|
||||
'travel_code' => [
|
||||
'product' => [
|
||||
'exclude' => false,
|
||||
'label' => 'Reisecode des Termins',
|
||||
'label' => 'Produkt',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 30,
|
||||
'eval' => 'trim,required'
|
||||
'type' => 'group',
|
||||
'internal_type' => 'db',
|
||||
'allowed' => 'tx_epproducts_domain_model_product',
|
||||
'minitems' => 1,
|
||||
'maxitems' => 1,
|
||||
'size' => 1,
|
||||
'fieldControl' => [
|
||||
'elementBrowser' => [
|
||||
'disabled' => true,
|
||||
],
|
||||
],
|
||||
'fieldWizard' => [
|
||||
'recordsOverview' => [
|
||||
'disabled' => true,
|
||||
],
|
||||
],
|
||||
'suggestOptions' => [
|
||||
'default' => [
|
||||
'additionalSearchFields' => 'code,name,keywords',
|
||||
'orderBy' => 'code',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'hide_address' => [
|
||||
'exclude' => 0,
|
||||
'label' => 'Adresse ausblenden',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
],
|
||||
],
|
||||
'intro_text' => [
|
||||
|
||||
@@ -252,7 +252,7 @@ $boot = function () {
|
||||
'EP.ep_products',
|
||||
'travelinfo',
|
||||
[
|
||||
'Travelinfo' => 'index',
|
||||
'Travelinfo' => 'index,myep',
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -1370,6 +1370,8 @@ CREATE TABLE tx_epproducts_domain_model_travelinfo
|
||||
footer_image int(11) DEFAULT '0' NOT NULL,
|
||||
links int(11) DEFAULT '0' NOT NULL,
|
||||
teasers int(11) DEFAULT '0' NOT NULL,
|
||||
product int(11) unsigned DEFAULT '0',
|
||||
hide_address tinyint(4) unsigned DEFAULT '0' NOT NULL,
|
||||
travel_code varchar(255) DEFAULT '' NOT NULL,
|
||||
path_segment varchar(255) DEFAULT '' NOT NULL,
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
alt="Reiseinformationen"
|
||||
class="block w-full h-full object-cover object-center" />
|
||||
</div>
|
||||
<div class="absolute top-16 left-1/2 -translate-x-1/2 w-full max-w-screen-sm lg:left-0 lg:-translate-x-0 lg:max-w-none px-8 lg:px-24 h-64 lg:h-128 flex flex-col justify-between">
|
||||
<div class="hidden lg:block text-3xl lg:text-6xl text-white uppercase font-bold">
|
||||
<div class="absolute top-8 lg:top-16 left-1/2 -translate-x-1/2 w-full max-w-screen-sm lg:left-0 lg:-translate-x-0 lg:max-w-none px-8 lg:px-24 h-64 lg:h-128 flex flex-col justify-between">
|
||||
<div class="text-2xl pb-4 lg:pb-0 md:text-3xl lg:text-6xl text-ep-secondary uppercase font-bold">
|
||||
Reiseinformation
|
||||
</div>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4">
|
||||
@@ -26,18 +26,18 @@
|
||||
data-controller="scroll-to"
|
||||
data-scroll-to-target-value="goodtoknow"
|
||||
data-action="scroll-to#scroll"
|
||||
class="flex flex-col space-y-4 items-center justify-center px-8 py-8 lg:py-16 text-white {bgColors.{linksCount}}">
|
||||
<div class="w-12 h-12 lg:w-24 lg:h-24">
|
||||
class="flex flex-col space-y-4 items-center justify-center px-4 py-4 lg:py-16 text-white {bgColors.{linksCount}}">
|
||||
<div class="w-10 h-10 lg:w-24 lg:h-24">
|
||||
<f:render section="Icon" arguments="{icon: 'chat'}" />
|
||||
</div>
|
||||
<div class="uppercase text-lg lg:text-xl text-center leading-tight">
|
||||
<div class="uppercase lg:text-xl text-center leading-tight">
|
||||
Wissens­wertes
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-32 pt-52 -mt-24 bg-ep-primary-bg">
|
||||
<div class="pb-32 pt-32 lg:pt-52 -mt-24 bg-ep-primary-bg">
|
||||
<div class="container px-8 lg:px-24" data-rte-content>
|
||||
<h1 class="headline--underlined headline--has-subline">
|
||||
<span class="subline">{travelinfo.subline}</span>
|
||||
@@ -60,14 +60,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:w-3/4 pt-8 lg:pt-0 lg:px-8 text-white" data-rte-content>
|
||||
<h3 class="text-white">
|
||||
Adresse
|
||||
</h3>
|
||||
<p>
|
||||
{date.hotel.name}
|
||||
<br>
|
||||
{date.hotel.address -> f:format.nl2br()}
|
||||
</p>
|
||||
<f:if condition="{travelinfo.hideAddress}">
|
||||
<f:else>
|
||||
<h3 class="text-white">
|
||||
Adresse
|
||||
</h3>
|
||||
<p>
|
||||
{date.hotel.name}
|
||||
<br>
|
||||
{date.hotel.address -> f:format.nl2br()}
|
||||
</p>
|
||||
</f:else>
|
||||
</f:if>
|
||||
<f:if condition="{date.pickups -> f:count()} > 0">
|
||||
<h3 class="text-white">
|
||||
Bus-Zustiege
|
||||
@@ -87,7 +91,7 @@
|
||||
<f:for each="{date.pickups}" as="pickup">
|
||||
<tr class="odd:bg-zinc-50 align-top">
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2">
|
||||
{pickup.city}<br><span class="text-xs">{pickup.street} {f:if(condition: pickup.price, then: ', Aufpreis {pickup.price -> f:format.currency(currencySign: \'€\')}')}</span>
|
||||
{pickup.city}<br><span class="text-xs">{pickup.street}</span>
|
||||
</td>
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2">
|
||||
{pickup.date}
|
||||
@@ -205,11 +209,11 @@
|
||||
</f:section>
|
||||
|
||||
<f:section name="Link">
|
||||
<f:link.typolink parameter="{item.link}" class="flex flex-col space-y-4 items-center justify-center px-8 py-8 lg:py-16 text-white {color}">
|
||||
<div class="w-12 h-12 lg:w-24 lg:h-24">
|
||||
<f:link.typolink parameter="{item.link}" class="flex flex-col space-y-4 items-center justify-center px-4 py-4 lg:py-16 text-white {color}">
|
||||
<div class="w-10 h-10 lg:w-24 lg:h-24">
|
||||
<f:render section="Icon" arguments="{icon: item.icon}" />
|
||||
</div>
|
||||
<div class="uppercase text-lg lg:text-xl text-center leading-tight">
|
||||
<div class="uppercase lg:text-xl text-center leading-tight">
|
||||
{item.title -> f:format.raw()}
|
||||
</div>
|
||||
</f:link.typolink>
|
||||
|
||||
Reference in New Issue
Block a user