diff --git a/plugin.php b/plugin.php index ae1dbf2da..ec0b32c1a 100644 --- a/plugin.php +++ b/plugin.php @@ -279,10 +279,15 @@ function customFieldCallback( $pDI, $format, $limitEllipsis, $meta_key ) { } -add_filter('wpml_ls_language_url', function($url) use ($pDI){ +add_filter('wpml_ls_language_url', function($url, $data) use ($pDI) { + /** @var EstateIdRequestGuard $pEstateIdGuard */ + $pEstateIdGuard = $pDI->get(EstateIdRequestGuard::class); + $pEstateDetailUrl = $pDI->get(EstateDetailUrl::class); + $oldUrl = $pDI->get(Redirector::class)->getCurrentLink(); $pWPQueryWrapper = $pDI->get(WPQueryWrapper::class); $estateId = (int) $pWPQueryWrapper->getWPQuery()->get('estate_id', 0); - return $pDI->get(EstateDetailUrl::class)->createEstateDetailLink($url, $estateId); + + return $pEstateIdGuard->createEstateDetailLinkForSwitchLanguageWPML($url, $estateId, $pEstateDetailUrl, $oldUrl, $data['default_locale']); }, 10, 2); register_activation_hook(__FILE__, [Installer::class, 'install']); diff --git a/plugin/Controller/EstateDetailUrl.php b/plugin/Controller/EstateDetailUrl.php index 648223e62..1d336676f 100644 --- a/plugin/Controller/EstateDetailUrl.php +++ b/plugin/Controller/EstateDetailUrl.php @@ -34,6 +34,7 @@ class EstateDetailUrl * @param int $estateId * @param string|null $title * @param string|null $oldUrl + * @param bool $flag * * @return string */ @@ -42,7 +43,8 @@ public function createEstateDetailLink( string $url, int $estateId, string $title = null, - string $oldUrl = null ): string + string $oldUrl = null, + bool $flag = false): string { $urlLsSwitcher = $url; $slashChar = ''; @@ -58,7 +60,7 @@ public function createEstateDetailLink( if ( ! is_null( $oldUrl ) ) { $oldUrlElements = parse_url( $oldUrl ); $oldUrlPathArr = explode( '/', $oldUrlElements['path'] ); - if ( empty( end( $oldUrlPathArr ) ) ) { + if ( empty( end( $oldUrlPathArr ) ) || $flag ) { $slashChar = '/'; } } @@ -66,7 +68,7 @@ public function createEstateDetailLink( $urlTemp = $estateId; if ( ! empty( $title ) && $this->isOptionShowTitleUrl() ) { - $urlTemp .= $this->getSanitizeTitle( $title ); + $urlTemp .= $this->getSanitizeTitle( $title, $flag ); } $urlLsSwitcher = $urlElements['scheme'] . '://' . $urlElements['host'] . $urlElements['path'] . $urlTemp . $slashChar; @@ -94,12 +96,13 @@ public function isOptionShowTitleUrl() /** * @param string $title + * @param bool $flag * @return string */ - public function getSanitizeTitle(string $title): string + public function getSanitizeTitle(string $title, bool $flag = false): string { - $sanitizeTitle = sanitize_title($title); + $sanitizeTitle = $flag ? sanitize_title(remove_accents($title)) : sanitize_title($title); $arrSanitizeTitle = explode('-', $sanitizeTitle); if (count($arrSanitizeTitle) > self::MAXIMUM_WORD_TITLE) { $sanitizeTitle = implode('-', array_splice($arrSanitizeTitle, 0, self::MAXIMUM_WORD_TITLE)); diff --git a/plugin/Record/EstateIdRequestGuard.php b/plugin/Record/EstateIdRequestGuard.php index 420df0048..3d3bdd406 100644 --- a/plugin/Record/EstateIdRequestGuard.php +++ b/plugin/Record/EstateIdRequestGuard.php @@ -23,8 +23,15 @@ namespace onOffice\WPlugin\Record; +use DI\Container; +use DI\ContainerBuilder; +use onOffice\SDK\onOfficeSDK; +use onOffice\WPlugin\API\APIClientActionGeneric; use onOffice\WPlugin\ArrayContainerEscape; +use onOffice\WPlugin\Controller\EstateDetailUrl; use onOffice\WPlugin\Factory\EstateListFactory; +use onOffice\WPlugin\Language; +use onOffice\WPlugin\SDKWrapper; use onOffice\WPlugin\ViewFieldModifier\EstateViewFieldModifierTypes; use onOffice\WPlugin\Utility\Redirector; @@ -42,16 +49,28 @@ class EstateIdRequestGuard /** * @var ArrayContainerEscape */ private $_estateData; + /** @var array */ + private $_estateDataWPML = []; + + /** @var Container */ + private $_pContainer = null; + + /** @var array */ + private $_activeLanguages = []; /** * * @param EstateListFactory $pEstateDetailFactory + * @param Container|null $pContainer * */ - public function __construct(EstateListFactory $pEstateDetailFactory) + public function __construct(EstateListFactory $pEstateDetailFactory, Container $pContainer = null) { $this->_pEstateDetailFactory = $pEstateDetailFactory; + $pContainerBuilder = new ContainerBuilder; + $pContainerBuilder->addDefinitions(ONOFFICE_DI_CONFIG_PATH); + $this->_pContainer = $pContainer ?? $pContainerBuilder->build(); } @@ -67,6 +86,14 @@ public function isValid(int $estateId): bool $pEstateDetail = $this->_pEstateDetailFactory->createEstateDetail($estateId); $pEstateDetail->loadEstates(); $this->_estateData = $pEstateDetail->estateIterator(EstateViewFieldModifierTypes::MODIFIER_TYPE_DEFAULT, true); + + if ($this->isActiveWPML()) { + $this->_activeLanguages = apply_filters('wpml_active_languages', null); + if ($estateId > 0 && !empty($this->_estateData) && count($this->_activeLanguages) > 1) { + $this->estateDataForWPML($estateId); + } + } + return $this->_estateData !== false; } @@ -84,4 +111,107 @@ public function estateDetailUrlChecker( int $estateId, Redirector $pRedirector, $estateTitle = $this->_estateData->getValue( 'objekttitel' ); $pRedirector->redirectDetailView($estateId, $estateTitle, $pEstateRedirection); } + + /** + * @param string $url + * @param int $estateId + * @param EstateDetailUrl $pEstateDetailUrl + * @param string $oldUrl + * @param string $switchLocale + * + * @return string + */ + public function createEstateDetailLinkForSwitchLanguageWPML(string $url, int $estateId, EstateDetailUrl $pEstateDetailUrl, string $oldUrl, string $switchLocale): string + { + $estateDetailTitle = ''; + $currentLocale = get_locale(); + if ($estateId > 0 && !empty($this->_estateData)) { + if ($switchLocale !== $currentLocale) { + $this->addSwitchFilterToLocaleHook($switchLocale); + $estateDetailTitle = $this->_estateDataWPML[$switchLocale]; + } else { + $estateDetailTitle = $this->_estateData->getValue('objekttitel'); + } + } + $detailLinkForWPML = $pEstateDetailUrl->createEstateDetailLink($url, $estateId, $estateDetailTitle, $oldUrl, true); + $this->addSwitchFilterToLocaleHook($currentLocale); + + return $detailLinkForWPML; + } + + /** + * @param array $locales + * @param int $estateId + * @return array + * @throws \DI\DependencyException + * @throws \DI\NotFoundException + */ + private function getEstateTitleByLocales(array $locales, int $estateId): array + { + $pApiClientActionClone = null; + $estateTitleByLocales = []; + $listRequestInQueue = []; + + $pSDKWrapper = $this->_pContainer->get(SDKWrapper::class); + $pApiClientAction = new APIClientActionGeneric + ($pSDKWrapper, onOfficeSDK::ACTION_ID_READ, 'estate'); + foreach ($locales as $locale) { + $isoLanguageCode = Language::LOCALE_MAPPING[$locale] ?? 'DEU'; + $estateParameters = [ + 'data' => ['objekttitel'], + 'estatelanguage' => $isoLanguageCode, + 'outputlanguage' => $isoLanguageCode, + ]; + $pApiClientActionClone = clone $pApiClientAction; + $pApiClientActionClone->setResourceId((string)$estateId); + $pApiClientActionClone->setParameters($estateParameters); + $pApiClientActionClone->addRequestToQueue(); + $listRequestInQueue[$locale] = $pApiClientActionClone; + } + $pApiClientActionClone->sendRequests(); + + if (empty($pApiClientActionClone->getResultRecords())) { + return []; + } + + foreach($listRequestInQueue as $key => $pApiClientAction) { + $estateTitleByLocales[$key] = $pApiClientAction->getResultRecords()[0]['elements']['objekttitel']; + } + + return $estateTitleByLocales; + } + + /** + * @param int $estateId + * @return void + */ + private function estateDataForWPML(int $estateId) + { + $defaultLocales = []; + foreach ($this->_activeLanguages as $language) { + if (isset($language['default_locale']) && $language['default_locale'] !== get_locale()) { + $defaultLocales[] = $language['default_locale']; + } + } + + $this->_estateDataWPML = $this->getEstateTitleByLocales($defaultLocales, $estateId); + } + + /** + * @return bool + */ + private function isActiveWPML(): bool + { + return in_array('sitepress-multilingual-cms/sitepress.php', get_option('active_plugins')); + } + + /** + * @param string $locale + */ + private function addSwitchFilterToLocaleHook(string $locale) + { + add_filter('locale', function () use ($locale) { + return $locale; + }); + } } diff --git a/tests/TestClassEstateIdRequestGuard.php b/tests/TestClassEstateIdRequestGuard.php index 3848d1be3..87c1affcb 100644 --- a/tests/TestClassEstateIdRequestGuard.php +++ b/tests/TestClassEstateIdRequestGuard.php @@ -23,12 +23,17 @@ namespace onOffice\tests; +use DI\Container; +use DI\ContainerBuilder; use Generator; +use onOffice\SDK\onOfficeSDK; use onOffice\WPlugin\ArrayContainerEscape; +use onOffice\WPlugin\Controller\EstateDetailUrl; use onOffice\WPlugin\DataView\DataDetailView; use onOffice\WPlugin\EstateDetail; use onOffice\WPlugin\Factory\EstateListFactory; use onOffice\WPlugin\Record\EstateIdRequestGuard; +use onOffice\WPlugin\SDKWrapper; use WP_UnitTestCase; /** @@ -38,6 +43,37 @@ class TestClassEstateIdRequestGuard extends WP_UnitTestCase { + + /** @var Container */ + private $_pContainer = null; + + /** + * @before + */ + public function prepare() + { + $switchLocale = 'DEU'; + $pSDKWrapperMocker = new SDKWrapperMocker(); + $pSDKWrapperMocker->addResponseByParameters + (onOfficeSDK::ACTION_ID_READ, 'estate', '3', [ + 'data' => ['objekttitel'], + 'estatelanguage' => $switchLocale, + 'outputlanguage' => $switchLocale + ], null, $this->prepareMockerForEstateDetailOne()); + + $pSDKWrapperMocker->addResponseByParameters + (onOfficeSDK::ACTION_ID_READ, 'estate', '9', [ + 'data' => ['objekttitel'], + 'estatelanguage' => $switchLocale, + 'outputlanguage' => $switchLocale + ], null, $this->prepareMockerForEstateDetailTwo()); + + $pContainerBuilder = new ContainerBuilder; + $pContainerBuilder->addDefinitions(ONOFFICE_DI_CONFIG_PATH); + $this->_pContainer = $pContainerBuilder->build(); + $this->_pContainer->set(SDKWrapper::class, $pSDKWrapperMocker); + } + /** * * @dataProvider dataProvider @@ -66,6 +102,50 @@ public function testIsValid(int $estateId, $iterator, bool $result) } + /** + * + * @dataProvider dataProvider + * + * @param int $estateId + * @param bool|ArrayContainerEscape $iterator + * @param bool $result + * + */ + public function testCreateEstateDetailLinkForSwitchLanguageWPML(int $estateId, $iterator, bool $result) + { + add_option('onoffice-detail-view-showTitleUrl', true); + $this->run_activate_plugin_for_test( 'sitepress-multilingual-cms/sitepress.php' ); + add_filter('wpml_active_languages', function () { + return [ + 'en' => ['default_locale' => 'en_US'], + 'de' => ['default_locale' => 'de_DE'], + ]; + }); + + $url = 'https://www.onoffice.de/detail/'; + $title = $iterator ? '-' . $iterator['objekttitel'] : ''; + $oldUrl = 'https://www.onoffice.de/detail/' . $estateId . $title . '/'; + $expectedUrl = 'https://www.onoffice.de/detail/' . $estateId . $title . '/'; + + $pEstateDetailFactory = $this->getMockBuilder(EstateListFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $pEstateDetail = $this->getMockBuilder(EstateDetail::class) + ->setConstructorArgs([new DataDetailView()]) + ->setMethods(['loadEstates', 'estateIterator']) + ->getMock(); + $pEstateDetail->expects($this->once())->method('estateIterator') + ->will($this->returnValue($iterator)); + + $pEstateDetailFactory->method('createEstateDetail')->will($this->returnValue($pEstateDetail)); + $pSubject = new EstateIdRequestGuard($pEstateDetailFactory, $this->_pContainer); + $pSubject->isValid($estateId); + $pEstateDetailUrl = new EstateDetailUrl(); + + $result = $pSubject->createEstateDetailLinkForSwitchLanguageWPML($url, $estateId, $pEstateDetailUrl, $oldUrl, 'en_US'); + $this->assertEquals($expectedUrl, $result); + } + /** * * @return Generator @@ -75,10 +155,96 @@ public function testIsValid(int $estateId, $iterator, bool $result) public function dataProvider(): Generator { yield from [ - [3, new ArrayContainerEscape(['Id' => 3]), true], + [3, new ArrayContainerEscape(['Id' => 3, 'objekttitel' => 'title-3']), true], [5, false, false], [7, false, false], - [9, new ArrayContainerEscape(['Id' => 9]), true], + [9, new ArrayContainerEscape(['Id' => 9, 'objekttitel' => 'title-9']), true], + ]; + } + + /** + * @param $plugin + * @return null + */ + private function run_activate_plugin_for_test($plugin) { + $current = get_option('active_plugins'); + $plugin = plugin_basename(trim($plugin)); + + if (!in_array($plugin, $current)) { + $current[] = $plugin; + sort($current); + do_action('activate_plugin', trim($plugin)); + update_option('active_plugins', $current); + do_action('activate_' . trim($plugin)); + do_action('activated_plugin', trim($plugin)); + } + + return null; + } + + /** + * + */ + private function prepareMockerForEstateDetailOne() + { + $response = [ + 'actionid' => 'urn:onoffice-de-ns:smart:2.5:smartml:action:read', + 'resourceid' => '3', + 'resourcetype' => 'estate', + 'identifier' => '', + 'data' => [ + 'meta' => [ + 'cntabsolute' => 1, + ], + 'records' => [ + 0 => [ + 'id' => 3, + 'type' => 'estate', + 'elements' => [ + "objekttitel" => "title-3" + ], + ], + ], + ], + 'status' => [ + 'errorcode' => 0, + 'message' => 'OK', + ], + ]; + + return $response; + } + + /** + * + */ + private function prepareMockerForEstateDetailTwo() + { + $response = [ + 'actionid' => 'urn:onoffice-de-ns:smart:2.5:smartml:action:read', + 'resourceid' => '9', + 'resourcetype' => 'estate', + 'identifier' => '', + 'data' => [ + 'meta' => [ + 'cntabsolute' => 1, + ], + 'records' => [ + 0 => [ + 'id' => 9, + 'type' => 'estate', + 'elements' => [ + "objekttitel" => "title-9" + ], + ], + ], + ], + 'status' => [ + 'errorcode' => 0, + 'message' => 'OK', + ], ]; + + return $response; } } \ No newline at end of file