Skip to content

Commit

Permalink
Pimcore Redirect Modifier (cp from #34) (#35)
Browse files Browse the repository at this point in the history
* Pimcore Redirect Modifier (#34)
* improve site determination
  • Loading branch information
solverat authored Aug 22, 2019
1 parent 5146e78 commit 7c9b7d2
Show file tree
Hide file tree
Showing 16 changed files with 1,104 additions and 344 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Does actually the same as the update command and preferred in CI-Workflow:
- [Localized Error Documents](docs/40_LocaleErrorDocument.md): Learn how to create localized error documents.
- [Custom Locale Adapter](docs/50_CustomLocaleAdapter.md): Learn how to create a custom locale adapter.
- [Redirector Adapter](docs/51_RedirectorAdapter.md): Learn more about redirector adapter and how to implement a custom one.
- [Pimcore Redirects with I18n](docs/52_PimcoreRedirects.md): Learn how to create localized pimcore redirects.
- [Code Examples](docs/60_CodeExamples.md): See some examples.
- [Context Switch Event](docs/70_ContextSwitch.md): Detect zone/language/country switches.
- [Canonical Links](docs/80_CanonicalLinks.md): Canonical links in hardlinks.
Expand Down
3 changes: 3 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
After every update you should check the pimcore extension manager.
Just click the "update" button or execute the migration command to finish the bundle update.

#### Update from Version 3.0.0 to Version 3.1.0
- **[NEW FEATURE]**: Allow [pimcore redirect modification](https://github.com/dachcom-digital/pimcore-i18n/issues/33).

#### Update from Version 2.x to Version 3.0.0
- **[NEW FEATURE]**: Pimcore 6.0.0 ready

Expand Down
32 changes: 32 additions & 0 deletions docs/52_PimcoreRedirects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Pimcore Redirects with I18n

![Pimcore Redirects](https://user-images.githubusercontent.com/700119/63445786-4917fe80-c439-11e9-8007-e19576cdf8bc.png)

If you want to implement the i18n redirect guesser, you need to add `{i18n_localized_target_page=4}` instead of the document path in the `target` section.

## Facts
- Be sure that your documents are connected, otherwise the detection won`t work.
- If you want to redirect an unknown host (Example A), be sure you set the redirect `priority` to `99`.

## Example

### Given Structure
**Domain**: `mydomain.com`
**Document Tree**:
- de
- kollektion
- kampagne
- en
- collection
- landingpage

## Example A:
- Enter host `my-old-collection-domain.com`
- i18n should redirect to `mydomain.com/de/kollektion` if user is german
- i18n should redirect to `mydomain.com/en/collection` if user is english

## Example B:
- Enter host `mydomain.com/landingpage`
- i18n should redirect to `mydomain.com/de/kampagne` if user is german
- i18n should redirect to `mydomain.com/en/landingpage` if user is english

316 changes: 316 additions & 0 deletions src/I18nBundle/EventListener/ContextSwitchDetectorListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
<?php

namespace I18nBundle\EventListener;

use I18nBundle\Helper\RequestValidatorHelper;
use Pimcore\Logger;
use I18nBundle\I18nEvents;
use I18nBundle\Helper\DocumentHelper;
use I18nBundle\Event\ContextSwitchEvent;
use I18nBundle\Manager\ZoneManager;
use Pimcore\Model\Document;
use Pimcore\Http\Request\Resolver\DocumentResolver;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ContextSwitchDetectorListener implements EventSubscriberInterface
{
/**
* @var Document
*/
private $document = null;

/**
* @var null
*/
private $documentLocale = null;

/**
* @var null
*/
private $documentLanguage = null;

/**
* @var null
*/
private $documentCountry = null;

/**
* @var Request
*/
private $request;

/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;

/**
* @var DocumentResolver
*/
protected $documentResolver;

/**
* @var ZoneManager
*/
protected $zoneManager;

/**
* @var DocumentHelper
*/
protected $documentHelper;

/**
* @var RequestValidatorHelper
*/
protected $requestValidatorHelper;

/**
* @param EventDispatcherInterface $eventDispatcher
* @param DocumentResolver $documentResolver
* @param ZoneManager $zoneManager
* @param DocumentHelper $documentHelper
* @param RequestValidatorHelper $requestValidatorHelper
*/
public function __construct(
EventDispatcherInterface $eventDispatcher,
DocumentResolver $documentResolver,
ZoneManager $zoneManager,
DocumentHelper $documentHelper,
RequestValidatorHelper $requestValidatorHelper
) {
$this->eventDispatcher = $eventDispatcher;
$this->documentResolver = $documentResolver;
$this->zoneManager = $zoneManager;
$this->documentHelper = $documentHelper;
$this->requestValidatorHelper = $requestValidatorHelper;
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => [
['onKernelRequest', 1] // after i18n detector listener
]
];
}

/**
* Apply this method after the pimcore context resolver.
*
* @param GetResponseEvent $event
*
* @throws \Exception
*/
public function onKernelRequest(GetResponseEvent $event)
{
if ($event->isMasterRequest() === false) {
return;
}

$this->request = $event->getRequest();
$this->document = $this->documentResolver->getDocument($this->request);

if ($this->isValidRequest() === false) {
return;
}

$this->setDocumentLocale();

// check if zone, language or country has been changed,
// trigger event for 3th party.
$this->detectContextSwitch();

// update session
$this->updateSessionData();
}

/**
* Important: ContextSwitch only works in same domain levels.
* Since there is no way for simple cross-domain session ids,
* the zone switch has no relevance.
*
* @throws \Exception
*/
private function detectContextSwitch()
{
$session = $this->getSessionData();
$currentZoneId = $this->zoneManager->getCurrentZoneInfo('zone_id');

$localeHasSwitched = false;
$languageHasSwitched = false;
$countryHasSwitched = false;
$zoneHasSwitched = false;

if (is_null($session['lastLocale']) || (!is_null($session['lastLocale']) && $this->documentLocale !== $session['lastLocale'])) {
$localeHasSwitched = true;
}

if (is_null($session['lastLanguage']) || (!is_null($session['lastLanguage']) && $this->documentLanguage !== $session['lastLanguage'])) {
$languageHasSwitched = true;
}

if ($session['lastCountry'] !== false && (!is_null($session['lastCountry']) && $this->documentCountry !== $session['lastCountry'])) {
$countryHasSwitched = true;
$localeHasSwitched = true;
}

if ($currentZoneId !== $session['lastZoneId']) {
$zoneHasSwitched = true;
}

if ($zoneHasSwitched || $localeHasSwitched || $languageHasSwitched || $countryHasSwitched) {
$params = [
'zoneHasSwitched' => $zoneHasSwitched,
'zoneFrom' => $session['lastZoneId'],
'zoneTo' => $currentZoneId,
'localeHasSwitched' => $localeHasSwitched,
'localeFrom' => $session['lastLocale'],
'localeTo' => $this->documentLocale,
'languageHasSwitched' => $languageHasSwitched,
'languageFrom' => $session['lastLanguage'],
'languageTo' => $this->documentLanguage,
'countryHasSwitched' => $countryHasSwitched,
'countryFrom' => $session['lastCountry'],
'countryTo' => $this->documentCountry
];

if ($zoneHasSwitched === true) {
Logger::log(
sprintf(
'switch zone: from %s to %s. triggered by: %s',
$session['lastZoneId'],
$currentZoneId,
$this->request->getRequestUri()
)
);
}

if ($localeHasSwitched === true) {
Logger::log(
sprintf(
'switch locale: from %s to %s. triggered by: %s',
$session['lastLocale'],
$this->documentLocale,
$this->request->getRequestUri()
)
);
}

if ($languageHasSwitched === true) {
Logger::log(
sprintf(
'switch language: from %s to %s. triggered by: %s',
$session['lastLanguage'],
$this->documentLanguage,
$this->request->getRequestUri()
)
);
}

if ($countryHasSwitched === true) {
Logger::log(
sprintf(
'switch country: from %s to %s. triggered by: %s',
$session['lastCountry'],
$this->documentCountry,
$this->request->getRequestUri()
)
);
}

$this->eventDispatcher->dispatch(I18nEvents::CONTEXT_SWITCH, new ContextSwitchEvent($params));
}
}

/**
* @return array
*/
protected function getSessionData()
{
/** @var NamespacedAttributeBag $bag */
$bag = $this->request->getSession()->getBag('i18n_session');

$data = [
'lastLocale' => null,
'lastLanguage' => null,
'lastCountry' => null,
'lastZoneId' => null
];

if ($bag->has('lastLocale')) {
$data['lastLocale'] = $bag->get('lastLocale');
}

if ($bag->has('lastLanguage')) {
$data['lastLanguage'] = $bag->get('lastLanguage');
}

if ($bag->get('lastCountry')) {
$data['lastCountry'] = $bag->get('lastCountry');
}

//if no zone as been defined, zone id is always NULL.
$data['lastZoneId'] = $bag->get('lastZoneId');

return $data;
}

/**
* @throws \Exception
*/
protected function updateSessionData()
{
$currentZoneId = $this->zoneManager->getCurrentZoneInfo('zone_id');

/** @var NamespacedAttributeBag $bag */
$bag = $this->request->getSession()->getBag('i18n_session');

if (!empty($this->documentLocale)) {
$bag->set('lastLocale', $this->documentLocale);
}

if (!empty($this->documentLanguage)) {
$bag->set('lastLanguage', $this->documentLanguage);
}

if (!empty($this->documentCountry)) {
$bag->set('lastCountry', $this->documentCountry);
}

$bag->set('lastZoneId', $currentZoneId);
}

/**
* @return bool
*/
protected function isValidRequest()
{
if (empty($this->document)) {
return false;
}

return $this->requestValidatorHelper->isValidForRedirect($this->request, false);
}

/**
* @throws \Exception
*/
protected function setDocumentLocale()
{
$i18nType = $this->zoneManager->getCurrentZoneInfo('mode');

$documentLocaleData = $this->documentHelper->getDocumentLocaleData($this->document, $i18nType);

$this->documentLocale = $documentLocaleData['documentLocale'];
$this->documentLanguage = $documentLocaleData['documentLanguage'];
$this->documentCountry = $documentLocaleData['documentCountry'];
}
}
Loading

0 comments on commit 7c9b7d2

Please sign in to comment.