Initial commit - Typo3 11.5.41
This commit is contained in:
60
typo3conf/ext/tt_address/Classes/Command/GeocodeCommand.php
Normal file
60
typo3conf/ext/tt_address/Classes/Command/GeocodeCommand.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Command;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use FriendsOfTYPO3\TtAddress\Service\GeocodeService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Command for geocoding coordinates
|
||||
*/
|
||||
class GeocodeCommand extends Command
|
||||
{
|
||||
/**
|
||||
* Defines the allowed options for this command
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Geocode tt_address records')
|
||||
->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
'Google Maps key for geocoding'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Geocode all records
|
||||
*
|
||||
* @inheritdoc
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->getGeocodeService($input->getArgument('key'))->calculateCoordinatesForAllRecordsInTable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key Google Maps key
|
||||
* @return GeocodeService
|
||||
*/
|
||||
protected function getGeocodeService(string $key)
|
||||
{
|
||||
return GeneralUtility::makeInstance(GeocodeService::class, $key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Controller;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use FriendsOfTYPO3\TtAddress\Database\QueryGenerator;
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Address;
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Dto\Demand;
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Dto\Settings;
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Repository\AddressRepository;
|
||||
use FriendsOfTYPO3\TtAddress\Seo\AddressTitleProvider;
|
||||
use FriendsOfTYPO3\TtAddress\Utility\CacheUtility;
|
||||
use FriendsOfTYPO3\TtAddress\Utility\TypoScript;
|
||||
use TYPO3\CMS\Core\Pagination\ArrayPaginator;
|
||||
use TYPO3\CMS\Core\Pagination\PaginatorInterface;
|
||||
use TYPO3\CMS\Core\Pagination\SimplePagination;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
|
||||
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
|
||||
|
||||
/**
|
||||
* AddressController
|
||||
*/
|
||||
class AddressController extends ActionController
|
||||
{
|
||||
/** @var AddressRepository */
|
||||
protected $addressRepository;
|
||||
|
||||
/** @var QueryGenerator */
|
||||
protected $queryGenerator;
|
||||
|
||||
/** @var Settings */
|
||||
protected $extensionConfiguration;
|
||||
|
||||
public function initializeAction()
|
||||
{
|
||||
$this->queryGenerator = GeneralUtility::makeInstance(QueryGenerator::class);
|
||||
$this->extensionConfiguration = GeneralUtility::makeInstance(Settings::class);
|
||||
}
|
||||
|
||||
public function showAction(Address $address = null)
|
||||
{
|
||||
if (is_a($address, Address::class) && ($this->settings['detail']['checkPidOfAddressRecord'] ?? false)) {
|
||||
$address = $this->checkPidOfAddressRecord($address);
|
||||
}
|
||||
|
||||
if ($address !== null) {
|
||||
$provider = GeneralUtility::makeInstance(AddressTitleProvider::class);
|
||||
$provider->setTitle($address, (array)($this->settings['seo']['pageTitle'] ?? []));
|
||||
CacheUtility::addCacheTagsByAddressRecords([$address]);
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'address' => $address,
|
||||
'contentObjectData' => $this->configurationManager->getContentObject()->data,
|
||||
]);
|
||||
return $this->htmlResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists addresses by settings in waterfall principle.
|
||||
* singleRecords take precedence over categories which take precedence over records from pages
|
||||
*
|
||||
*/
|
||||
public function listAction(?array $override = [])
|
||||
{
|
||||
$contentData = $this->configurationManager->getContentObject()->data;
|
||||
$demand = $this->createDemandFromSettings();
|
||||
|
||||
if (isset($contentData['first_name'], $contentData['birthday']) && (int)($this->settings['insertRecord'] ?? 0) === 1) {
|
||||
$demand->setSingleRecords((string)$contentData['uid']);
|
||||
}
|
||||
|
||||
if (!empty($override) && $this->settings['allowOverride']) {
|
||||
$this->overrideDemand($demand, $override);
|
||||
}
|
||||
|
||||
if ($demand->getSingleRecords()) {
|
||||
$addresses = $this->addressRepository->getAddressesByCustomSorting($demand);
|
||||
} else {
|
||||
$addresses = $this->addressRepository->findByDemand($demand);
|
||||
}
|
||||
|
||||
$paginator = $this->getPaginator($addresses);
|
||||
$pagination = new SimplePagination($paginator);
|
||||
// @todo remove with version 8
|
||||
$this->view->assign('newPagination', true);
|
||||
$this->view->assign('pagination', [
|
||||
'paginator' => $paginator,
|
||||
'pagination' => $pagination,
|
||||
]);
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'demand' => $demand,
|
||||
'addresses' => $addresses,
|
||||
'contentObjectData' => $contentData,
|
||||
]);
|
||||
|
||||
CacheUtility::addCacheTagsByAddressRecords(
|
||||
$addresses instanceof QueryResultInterface ? $addresses->toArray() : $addresses
|
||||
);
|
||||
return $this->htmlResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the Configuration Manager and is initializing the framework settings
|
||||
*
|
||||
* @param ConfigurationManagerInterface $configurationManager Instance of the Configuration Manager
|
||||
*/
|
||||
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
parent::injectConfigurationManager($configurationManager);
|
||||
$this->configurationManager = $configurationManager;
|
||||
|
||||
// get the whole typoscript (_FRAMEWORK does not work anymore, don't know why)
|
||||
$tsSettings = $this->configurationManager->getConfiguration(
|
||||
ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT,
|
||||
'',
|
||||
''
|
||||
);
|
||||
|
||||
// correct the array to be in same shape like the _SETTINGS array
|
||||
$tsSettings = $this->removeDots((array)($tsSettings['plugin.']['tx_ttaddress.'] ?? []));
|
||||
|
||||
// get original settings
|
||||
// original means: what extbase does by munching flexform and TypoScript together, but leaving empty flexform-settings empty ...
|
||||
$originalSettings = $this->configurationManager->getConfiguration(
|
||||
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS
|
||||
);
|
||||
|
||||
$propertiesNotAllowedViaFlexForms = ['orderByAllowed'];
|
||||
foreach ($propertiesNotAllowedViaFlexForms as $property) {
|
||||
if (isset($tsSettings['settings'][$property])) {
|
||||
$originalSettings[$property] = $tsSettings['settings'][$property];
|
||||
}
|
||||
}
|
||||
|
||||
// start override
|
||||
if (isset($tsSettings['settings']['overrideFlexformSettingsIfEmpty'])) {
|
||||
$typoScriptUtility = GeneralUtility::makeInstance(TypoScript::class);
|
||||
$originalSettings = $typoScriptUtility->override($originalSettings, $tsSettings);
|
||||
}
|
||||
// Re-set global settings
|
||||
$this->settings = $originalSettings;
|
||||
}
|
||||
|
||||
protected function createDemandFromSettings(): Demand
|
||||
{
|
||||
$demand = new Demand();
|
||||
$demand->setCategories((string)($this->settings['groups'] ?? ''));
|
||||
$categoryCombination = (int)($this->settings['groupsCombination'] ?? 1) === 1 ? 'or' : 'and';
|
||||
$demand->setCategoryCombination($categoryCombination);
|
||||
$demand->setIncludeSubCategories((bool)($this->settings['includeSubcategories'] ?? false));
|
||||
|
||||
if ($this->settings['pages'] ?? false) {
|
||||
$demand->setPages($this->getPidList());
|
||||
}
|
||||
$demand->setSingleRecords((string)($this->settings['singleRecords'] ?? ''));
|
||||
$demand->setSortBy((string)($this->settings['sortBy'] ?? ''));
|
||||
$demand->setSortOrder((string)($this->settings['sortOrder'] ?? ''));
|
||||
$demand->setIgnoreWithoutCoordinates((bool)($this->settings['ignoreWithoutCoordinates'] ?? false));
|
||||
|
||||
return $demand;
|
||||
}
|
||||
|
||||
protected function overrideDemand(Demand $demand, array $override = []): Demand
|
||||
{
|
||||
$ignoredValues = ['singleRecords', 'pages'];
|
||||
$ignoredValuesLower = array_map('strtolower', $ignoredValues);
|
||||
|
||||
foreach ($ignoredValues as $property) {
|
||||
unset($override[$property]);
|
||||
}
|
||||
|
||||
// check if field exists
|
||||
if (isset($override['sortBy']) && !isset($GLOBALS['TCA']['tt_address']['columns'][$override['sortBy']])) {
|
||||
unset($override['sortBy']);
|
||||
}
|
||||
|
||||
foreach ($override as $propertyName => $propertyValue) {
|
||||
if (in_array(strtolower($propertyName), $ignoredValuesLower, true)) {
|
||||
continue;
|
||||
}
|
||||
if ($propertyValue !== '' || $this->settings['allowEmptyStringsForOverwriteDemand']) {
|
||||
ObjectAccess::setProperty($demand, $propertyName, $propertyValue);
|
||||
}
|
||||
}
|
||||
return $demand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AddressRepository $addressRepository
|
||||
*/
|
||||
public function injectAddressRepository(AddressRepository $addressRepository)
|
||||
{
|
||||
$this->addressRepository = $addressRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes dots at the end of a configuration array
|
||||
*
|
||||
* @param array $settings the array to transformed
|
||||
* @return array $settings the transformed array
|
||||
*/
|
||||
protected function removeDots(array $settings): array
|
||||
{
|
||||
$conf = [];
|
||||
foreach ($settings as $key => $value) {
|
||||
$conf[$this->removeDotAtTheEnd($key)] = \is_array($value) ? $this->removeDots($value) : $value;
|
||||
}
|
||||
return $conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a dot in the end of a String
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
protected function removeDotAtTheEnd($string): string
|
||||
{
|
||||
return preg_replace('/\.$/', '', (string)$string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves subpages of given pageIds recursively until reached $this->settings['recursive']
|
||||
*
|
||||
* @return array an array with all pageIds
|
||||
*/
|
||||
protected function getPidList(): array
|
||||
{
|
||||
$rootPIDs = explode(',', $this->settings['pages']);
|
||||
$pidList = $rootPIDs;
|
||||
|
||||
// iterate through root-page ids and merge to array
|
||||
foreach ($rootPIDs as $pid) {
|
||||
$result = $this->queryGenerator->getTreeList($pid, (int)($this->settings['recursive'] ?? 0));
|
||||
if ($result) {
|
||||
$subtreePids = explode(',', $result);
|
||||
$pidList = array_merge($pidList, $subtreePids);
|
||||
}
|
||||
}
|
||||
return $pidList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryResultInterface|array $addresses
|
||||
* @return ArrayPaginator|QueryResultPaginator
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
|
||||
*/
|
||||
protected function getPaginator($addresses): PaginatorInterface
|
||||
{
|
||||
$currentPage = $this->request->hasArgument('currentPage') ? (int)$this->request->getArgument('currentPage') : 1;
|
||||
$itemsPerPage = (int)($this->settings['paginate']['itemsPerPage'] ?? 10);
|
||||
if ($itemsPerPage === 0) {
|
||||
$itemsPerPage = 10;
|
||||
}
|
||||
|
||||
if (is_array($addresses)) {
|
||||
$paginator = new ArrayPaginator($addresses, $currentPage, $itemsPerPage);
|
||||
} elseif ($addresses instanceof QueryResultInterface) {
|
||||
$paginator = new QueryResultPaginator($addresses, $currentPage, $itemsPerPage);
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Only array and query result interface allowed for pagination, given "%s"', get_class($addresses)), 1611168593);
|
||||
}
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the address PID could be found in the storagePage settings of the detail plugin and
|
||||
* if the pid is not found null is returned
|
||||
*
|
||||
* @param Address $address
|
||||
* @return Address|null
|
||||
*/
|
||||
protected function checkPidOfAddressRecord(Address $address): ?Address
|
||||
{
|
||||
$allowedStoragePages = array_map('intval', $this->getPidList());
|
||||
if (count($allowedStoragePages) > 0 && !in_array($address->getPid(), $allowedStoragePages, true)) {
|
||||
$address = null;
|
||||
}
|
||||
|
||||
return $address;
|
||||
}
|
||||
}
|
||||
71
typo3conf/ext/tt_address/Classes/Database/QueryGenerator.php
Normal file
71
typo3conf/ext/tt_address/Classes/Database/QueryGenerator.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Database;
|
||||
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Duplication of \TYPO3\CMS\Core\Database\QueryGenerator which has been deprecated
|
||||
*/
|
||||
class QueryGenerator
|
||||
{
|
||||
/**
|
||||
* Recursively fetch all descendants of a given page
|
||||
*
|
||||
* @param int $id uid of the page
|
||||
* @param int $depth
|
||||
* @param int $begin
|
||||
* @return string comma separated list of descendant pages
|
||||
*/
|
||||
public function getTreeList($id, $depth, $begin = 0): string
|
||||
{
|
||||
$depth = (int)$depth;
|
||||
$begin = (int)$begin;
|
||||
$id = (int)$id;
|
||||
if ($id < 0) {
|
||||
$id = abs($id);
|
||||
}
|
||||
if ($begin === 0) {
|
||||
$theList = $id;
|
||||
} else {
|
||||
$theList = '';
|
||||
}
|
||||
if ($id && $depth > 0) {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
|
||||
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
$queryBuilder->select('uid')
|
||||
->from('pages')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, Connection::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq('sys_language_uid', 0)
|
||||
)
|
||||
->orderBy('uid');
|
||||
|
||||
$statement = $queryBuilder->executeQuery();
|
||||
while ($row = $statement->fetchAssociative()) {
|
||||
if ($begin <= 0) {
|
||||
$theList .= ',' . $row['uid'];
|
||||
}
|
||||
if ($depth > 1) {
|
||||
$theSubList = $this->getTreeList($row['uid'], $depth - 1, $begin - 1);
|
||||
if (!empty($theList) && !empty($theSubList) && ($theSubList[0] !== ',')) {
|
||||
$theList .= ',';
|
||||
}
|
||||
$theList .= $theSubList;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (string)$theList;
|
||||
}
|
||||
}
|
||||
674
typo3conf/ext/tt_address/Classes/Domain/Model/Address.php
Normal file
674
typo3conf/ext/tt_address/Classes/Domain/Model/Address.php
Normal file
@@ -0,0 +1,674 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Domain\Model;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use FriendsOfTYPO3\TtAddress\Utility\PropertyModification;
|
||||
use TYPO3\CMS\Extbase\Domain\Model\Category;
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
|
||||
/**
|
||||
* The domain model of a Address
|
||||
*/
|
||||
class Address extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Hidden
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $hidden = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $gender = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $firstName = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $middleName = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $lastName = '';
|
||||
|
||||
/**
|
||||
* @var \DateTime|null
|
||||
*/
|
||||
protected $birthday;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '';
|
||||
|
||||
/** @var string */
|
||||
protected $titleSuffix = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $address = '';
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected $latitude = 0;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected $longitude = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $building = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $room = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $phone = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $fax = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $mobile = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $www = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $slug = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $skype = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $twitter = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $facebook = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $instagram = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tiktok = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $linkedin = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $email = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $company = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $position = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $city = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $zip = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $region = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $country = '';
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '';
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<Category>
|
||||
*/
|
||||
protected $categories;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->image = new ObjectStorage();
|
||||
$this->categories = new ObjectStorage();
|
||||
}
|
||||
|
||||
public function setHidden($hidden): void
|
||||
{
|
||||
$this->hidden = $hidden;
|
||||
}
|
||||
|
||||
public function getHidden(): bool
|
||||
{
|
||||
return $this->hidden;
|
||||
}
|
||||
|
||||
public function setGender(string $gender): void
|
||||
{
|
||||
$this->gender = $gender;
|
||||
}
|
||||
|
||||
public function getGender(): string
|
||||
{
|
||||
return $this->gender;
|
||||
}
|
||||
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setFirstName(string $firstName): void
|
||||
{
|
||||
$this->firstName = $firstName;
|
||||
}
|
||||
|
||||
public function getFirstName(): string
|
||||
{
|
||||
return $this->firstName;
|
||||
}
|
||||
|
||||
public function setMiddleName(string $middleName): void
|
||||
{
|
||||
$this->middleName = $middleName;
|
||||
}
|
||||
|
||||
public function getMiddleName(): string
|
||||
{
|
||||
return $this->middleName;
|
||||
}
|
||||
|
||||
public function setLastName(string $lastName): void
|
||||
{
|
||||
$this->lastName = $lastName;
|
||||
}
|
||||
|
||||
public function getLastName(): string
|
||||
{
|
||||
return $this->lastName;
|
||||
}
|
||||
|
||||
public function setBirthday(?\DateTime $birthday = null): void
|
||||
{
|
||||
$this->birthday = $birthday;
|
||||
}
|
||||
|
||||
public function getBirthday(): ?\DateTime
|
||||
{
|
||||
return $this->birthday;
|
||||
}
|
||||
|
||||
public function setTitle(string $title): void
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleSuffix(): string
|
||||
{
|
||||
return $this->titleSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $titleSuffix
|
||||
*/
|
||||
public function setTitleSuffix(string $titleSuffix): void
|
||||
{
|
||||
$this->titleSuffix = $titleSuffix;
|
||||
}
|
||||
|
||||
public function setAddress(string $address): void
|
||||
{
|
||||
$this->address = $address;
|
||||
}
|
||||
|
||||
public function getAddress(): string
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
|
||||
public function setLatitude(float $latitude): void
|
||||
{
|
||||
$this->latitude = $latitude;
|
||||
}
|
||||
|
||||
public function getLatitude(): float
|
||||
{
|
||||
return $this->latitude;
|
||||
}
|
||||
|
||||
public function setLongitude(float $longitude): void
|
||||
{
|
||||
$this->longitude = $longitude;
|
||||
}
|
||||
|
||||
public function getLongitude(): float
|
||||
{
|
||||
return $this->longitude;
|
||||
}
|
||||
|
||||
public function setBuilding(string $building): void
|
||||
{
|
||||
$this->building = $building;
|
||||
}
|
||||
|
||||
public function getBuilding(): string
|
||||
{
|
||||
return $this->building;
|
||||
}
|
||||
|
||||
public function setRoom(string $room): void
|
||||
{
|
||||
$this->room = $room;
|
||||
}
|
||||
|
||||
public function getRoom(): string
|
||||
{
|
||||
return $this->room;
|
||||
}
|
||||
|
||||
public function setPhone(string $phone): void
|
||||
{
|
||||
$this->phone = $phone;
|
||||
}
|
||||
|
||||
public function getPhone(): string
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
public function getCleanedPhone(): string
|
||||
{
|
||||
return PropertyModification::getCleanedNumber($this->phone);
|
||||
}
|
||||
|
||||
public function setFax(string $fax): void
|
||||
{
|
||||
$this->fax = $fax;
|
||||
}
|
||||
|
||||
public function getFax(): string
|
||||
{
|
||||
return $this->fax;
|
||||
}
|
||||
|
||||
public function getCleanedFax(): string
|
||||
{
|
||||
return PropertyModification::getCleanedNumber($this->fax);
|
||||
}
|
||||
|
||||
public function setMobile(string $mobile): void
|
||||
{
|
||||
$this->mobile = $mobile;
|
||||
}
|
||||
|
||||
public function getMobile(): string
|
||||
{
|
||||
return $this->mobile;
|
||||
}
|
||||
|
||||
public function getCleanedMobile(): string
|
||||
{
|
||||
return PropertyModification::getCleanedNumber($this->mobile);
|
||||
}
|
||||
|
||||
public function setWww(string $www): void
|
||||
{
|
||||
$this->www = $www;
|
||||
}
|
||||
|
||||
public function getWww(): string
|
||||
{
|
||||
return $this->www;
|
||||
}
|
||||
|
||||
public function getWwwSimplified(): string
|
||||
{
|
||||
return PropertyModification::getCleanedDomain($this->www);
|
||||
}
|
||||
|
||||
public function setSlug(string $slug): void
|
||||
{
|
||||
$this->slug = $slug;
|
||||
}
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function setSkype(string $skype): void
|
||||
{
|
||||
$this->skype = $skype;
|
||||
}
|
||||
|
||||
public function getSkype(): string
|
||||
{
|
||||
return $this->skype;
|
||||
}
|
||||
|
||||
public function setTwitter(string $twitter): void
|
||||
{
|
||||
if ($twitter[0] !== '@') {
|
||||
throw new \InvalidArgumentException('twitter name must start with @', 1357530444);
|
||||
}
|
||||
|
||||
$this->twitter = $twitter;
|
||||
}
|
||||
|
||||
public function getTwitter(): string
|
||||
{
|
||||
return $this->twitter;
|
||||
}
|
||||
|
||||
public function setFacebook(string $facebook): void
|
||||
{
|
||||
if ($facebook[0] !== '/') {
|
||||
throw new \InvalidArgumentException('Facebook name must start with /', 1357530471);
|
||||
}
|
||||
|
||||
$this->facebook = $facebook;
|
||||
}
|
||||
|
||||
public function getFacebook(): string
|
||||
{
|
||||
return $this->facebook;
|
||||
}
|
||||
|
||||
public function setInstagram(string $instagram): void
|
||||
{
|
||||
$this->instagram = $instagram;
|
||||
}
|
||||
|
||||
public function getInstagram(): string
|
||||
{
|
||||
return $this->instagram;
|
||||
}
|
||||
|
||||
public function setTiktok(string $tiktok): void
|
||||
{
|
||||
$this->tiktok = $tiktok;
|
||||
}
|
||||
|
||||
public function getTiktok(): string
|
||||
{
|
||||
return $this->tiktok;
|
||||
}
|
||||
|
||||
public function setLinkedin(string $linkedin): void
|
||||
{
|
||||
$this->linkedin = $linkedin;
|
||||
}
|
||||
|
||||
public function getLinkedin(): string
|
||||
{
|
||||
return $this->linkedin;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setCompany(string $company): void
|
||||
{
|
||||
$this->company = $company;
|
||||
}
|
||||
|
||||
public function getCompany(): string
|
||||
{
|
||||
return $this->company;
|
||||
}
|
||||
|
||||
public function setPosition(string $position): void
|
||||
{
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function setCity(string $city): void
|
||||
{
|
||||
$this->city = $city;
|
||||
}
|
||||
|
||||
public function getCity(): string
|
||||
{
|
||||
return $this->city;
|
||||
}
|
||||
|
||||
public function setZip(string $zip): void
|
||||
{
|
||||
$this->zip = $zip;
|
||||
}
|
||||
|
||||
public function getZip(): string
|
||||
{
|
||||
return $this->zip;
|
||||
}
|
||||
|
||||
public function setRegion(string $region): void
|
||||
{
|
||||
$this->region = $region;
|
||||
}
|
||||
|
||||
public function getRegion(): string
|
||||
{
|
||||
return $this->region;
|
||||
}
|
||||
|
||||
public function setCountry(string $country): void
|
||||
{
|
||||
$this->country = $country;
|
||||
}
|
||||
|
||||
public function getCountry(): string
|
||||
{
|
||||
return $this->country;
|
||||
}
|
||||
|
||||
public function addImage(FileReference $image): void
|
||||
{
|
||||
$this->image->attach($image);
|
||||
}
|
||||
|
||||
public function removeImage(FileReference $imageToRemove): void
|
||||
{
|
||||
$this->image->detach($imageToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
|
||||
*/
|
||||
public function getImage(): ?ObjectStorage
|
||||
{
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
public function getFirstImage(): ?FileReference
|
||||
{
|
||||
$images = $this->getImage();
|
||||
if ($images) {
|
||||
foreach ($images as $image) {
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ObjectStorage<FileReference> $image
|
||||
*/
|
||||
public function setImage(ObjectStorage $image): void
|
||||
{
|
||||
$this->image = $image;
|
||||
}
|
||||
|
||||
public function setDescription(string $description): void
|
||||
{
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ObjectStorage<Category>
|
||||
*/
|
||||
public function getCategories(): ObjectStorage
|
||||
{
|
||||
return $this->categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ObjectStorage<Category> $categories
|
||||
*/
|
||||
public function setCategories(ObjectStorage $categories): void
|
||||
{
|
||||
$this->categories = $categories;
|
||||
}
|
||||
|
||||
public function getSysLanguageUid(): int
|
||||
{
|
||||
return $this->_languageUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full name including title, first, middle and last name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFullName(): string
|
||||
{
|
||||
$list = [
|
||||
$this->getTitle(),
|
||||
$this->getFirstName(),
|
||||
$this->getMiddleName(),
|
||||
$this->getLastName(),
|
||||
];
|
||||
|
||||
$name = implode(' ', array_filter($list));
|
||||
if ($this->titleSuffix) {
|
||||
$name .= ', ' . $this->titleSuffix;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first category
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Domain\Model\Category|null the first category
|
||||
*/
|
||||
public function getFirstCategory(): ?Category
|
||||
{
|
||||
$categories = $this->getCategories();
|
||||
if (!is_null($categories)) {
|
||||
$categories->rewind();
|
||||
return $categories->current();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getAddressInOneLine(): string
|
||||
{
|
||||
return implode(', ', array_filter([
|
||||
str_replace(chr(10), ',', $this->address),
|
||||
$this->city,
|
||||
$this->region,
|
||||
$this->country,
|
||||
]));
|
||||
}
|
||||
}
|
||||
165
typo3conf/ext/tt_address/Classes/Domain/Model/Dto/Demand.php
Normal file
165
typo3conf/ext/tt_address/Classes/Domain/Model/Dto/Demand.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Domain\Model\Dto;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
class Demand
|
||||
{
|
||||
/** @var array */
|
||||
protected $pages = [];
|
||||
|
||||
/** @var string */
|
||||
protected $sortBy = '';
|
||||
|
||||
/** @var string */
|
||||
protected $sortOrder = '';
|
||||
|
||||
/** @var string */
|
||||
protected $categories = '';
|
||||
|
||||
/** @var bool */
|
||||
protected $includeSubCategories = false;
|
||||
|
||||
/** @var string */
|
||||
protected $categoryCombination = '';
|
||||
|
||||
/** @var string */
|
||||
protected $singleRecords = '';
|
||||
|
||||
/** @var bool */
|
||||
protected $ignoreWithoutCoordinates = false;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getPages(): array
|
||||
{
|
||||
return $this->pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $pages
|
||||
*/
|
||||
public function setPages(array $pages)
|
||||
{
|
||||
$this->pages = $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSortBy(): string
|
||||
{
|
||||
return $this->sortBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sortBy
|
||||
*/
|
||||
public function setSortBy(string $sortBy)
|
||||
{
|
||||
$this->sortBy = $sortBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSortOrder(): string
|
||||
{
|
||||
return $this->sortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sortOrder
|
||||
*/
|
||||
public function setSortOrder(string $sortOrder)
|
||||
{
|
||||
$this->sortOrder = $sortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCategories(): string
|
||||
{
|
||||
return $this->categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $categories
|
||||
*/
|
||||
public function setCategories(string $categories)
|
||||
{
|
||||
$this->categories = $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIncludeSubCategories(): bool
|
||||
{
|
||||
return $this->includeSubCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeSubCategories
|
||||
*/
|
||||
public function setIncludeSubCategories(bool $includeSubCategories)
|
||||
{
|
||||
$this->includeSubCategories = $includeSubCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCategoryCombination(): string
|
||||
{
|
||||
return $this->categoryCombination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $categoryCombination
|
||||
*/
|
||||
public function setCategoryCombination(string $categoryCombination)
|
||||
{
|
||||
$this->categoryCombination = $categoryCombination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSingleRecords(): string
|
||||
{
|
||||
return $this->singleRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $singleRecords
|
||||
*/
|
||||
public function setSingleRecords(string $singleRecords)
|
||||
{
|
||||
$this->singleRecords = $singleRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIgnoreWithoutCoordinates(): bool
|
||||
{
|
||||
return $this->ignoreWithoutCoordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $ignoreWithoutCoordinates
|
||||
*/
|
||||
public function setIgnoreWithoutCoordinates(bool $ignoreWithoutCoordinates)
|
||||
{
|
||||
$this->ignoreWithoutCoordinates = $ignoreWithoutCoordinates;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Domain\Model\Dto;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Class Settings
|
||||
*/
|
||||
class Settings
|
||||
{
|
||||
/** @var string */
|
||||
protected $telephoneValidationPatternForPhp = '/[^\d\+\s\-]/';
|
||||
|
||||
/** @var string */
|
||||
protected $telephoneValidationPatternForJs = '/[^\d\+\s\-]/g';
|
||||
|
||||
/** @var bool */
|
||||
protected $newPagination = false;
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$settings = $this->getSettings();
|
||||
|
||||
if (!empty($settings)) {
|
||||
$this->newPagination = (bool)($settings['newPagination'] ?? false);
|
||||
|
||||
if ($settings['telephoneValidationPatternForPhp'] ?? '') {
|
||||
$this->telephoneValidationPatternForPhp = (string)$settings['telephoneValidationPatternForPhp'];
|
||||
}
|
||||
if ($settings['telephoneValidationPatternForJs'] ?? '') {
|
||||
$this->telephoneValidationPatternForJs = (string)$settings['telephoneValidationPatternForJs'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTelephoneValidationPatternForPhp(): string
|
||||
{
|
||||
return $this->telephoneValidationPatternForPhp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTelephoneValidationPatternForJs(): string
|
||||
{
|
||||
return $this->telephoneValidationPatternForJs;
|
||||
}
|
||||
|
||||
protected function getSettings(): array
|
||||
{
|
||||
try {
|
||||
return GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('tt_address');
|
||||
} catch (\Exception $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Domain\Repository;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Dto\Demand;
|
||||
use FriendsOfTYPO3\TtAddress\Service\CategoryService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Repository;
|
||||
|
||||
/**
|
||||
* The repository for the domain model Address
|
||||
*/
|
||||
class AddressRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* override the storagePid settings (do not use storagePid) of extbase
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
$this->defaultQuerySettings = GeneralUtility::makeInstance(Typo3QuerySettings::class);
|
||||
$this->defaultQuerySettings->setRespectStoragePage(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Demand $demand
|
||||
* @return QueryResultInterface
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
public function findByDemand(Demand $demand)
|
||||
{
|
||||
$query = $this->createDemandQuery($demand);
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Demand $demand
|
||||
* @return QueryInterface
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
protected function createDemandQuery(Demand $demand): QueryInterface
|
||||
{
|
||||
$query = $this->createQuery();
|
||||
|
||||
// sorting
|
||||
$sortBy = $demand->getSortBy();
|
||||
if ($sortBy && $sortBy !== 'singleSelection' && $sortBy !== 'default') {
|
||||
$order = strtolower($demand->getSortOrder()) === 'desc' ? QueryInterface::ORDER_DESCENDING : QueryInterface::ORDER_ASCENDING;
|
||||
$query->setOrderings([$sortBy => $order]);
|
||||
}
|
||||
|
||||
$constraints = [];
|
||||
$pages = $demand->getPages();
|
||||
if (!empty($pages)) {
|
||||
$constraints['pages'] = $query->in('pid', $pages);
|
||||
}
|
||||
$categories = $demand->getCategories();
|
||||
if ($categories) {
|
||||
$categoryConstraints = $this->createCategoryConstraint($query, $categories, $demand->getIncludeSubCategories());
|
||||
if ($demand->getCategoryCombination() === 'or') {
|
||||
$constraints['categories'] = $query->logicalOr(...$categoryConstraints);
|
||||
} else {
|
||||
$constraints['categories'] = $query->logicalAnd(...$categoryConstraints);
|
||||
}
|
||||
}
|
||||
|
||||
if ($demand->getIgnoreWithoutCoordinates()) {
|
||||
$constraints['coordinatesLat'] = $query->logicalNot(
|
||||
$query->logicalOr(
|
||||
$query->equals('latitude', null),
|
||||
$query->equals('latitude', 0.0)
|
||||
)
|
||||
);
|
||||
$constraints['coordinatesLng'] = $query->logicalNot(
|
||||
$query->logicalOr(
|
||||
$query->equals('longitude', null),
|
||||
$query->equals('longitude', 0.0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($constraints)) {
|
||||
$query->matching($query->logicalAnd(...array_values($constraints)));
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database query to get the matching, see findByDemand()
|
||||
*
|
||||
* @param Demand $demand
|
||||
* @return string
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
public function getSqlQuery(Demand $demand): string
|
||||
{
|
||||
$query = $this->createDemandQuery($demand);
|
||||
$queryParser = GeneralUtility::makeInstance(Typo3DbQueryParser::class);
|
||||
|
||||
$queryBuilder = $queryParser->convertQueryToDoctrineQueryBuilder($query);
|
||||
$queryParameters = $queryBuilder->getParameters();
|
||||
$params = [];
|
||||
foreach ($queryParameters as $key => $value) {
|
||||
// prefix array keys with ':'
|
||||
$params[':' . $key] = (\is_numeric($value)) ? $value : "'" . $value . "'"; //all non numeric values have to be quoted
|
||||
unset($params[$key]);
|
||||
}
|
||||
// replace placeholders with real values
|
||||
$query = strtr($queryBuilder->getSQL(), $params);
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Demand $demand
|
||||
* @return array|QueryResultInterface
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
public function getAddressesByCustomSorting(Demand $demand)
|
||||
{
|
||||
$idList = GeneralUtility::intExplode(',', $demand->getSingleRecords(), true);
|
||||
$sortBy = $demand->getSortBy();
|
||||
|
||||
if ($sortBy && $sortBy !== 'default' && $sortBy !== 'singleSelection') {
|
||||
$query = $this->createQuery();
|
||||
|
||||
$order = strtolower($demand->getSortOrder()) === 'desc' ? QueryInterface::ORDER_DESCENDING : QueryInterface::ORDER_ASCENDING;
|
||||
$query->setOrderings([$sortBy => $order]);
|
||||
|
||||
$constraints = [
|
||||
$query->in('uid', $idList)
|
||||
];
|
||||
|
||||
$query->matching($query->logicalAnd(...$constraints));
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
if ($demand->getSortOrder() === 'DESC') {
|
||||
$idList = array_reverse($idList);
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($idList as $id) {
|
||||
$item = $this->findByIdentifier($id);
|
||||
if ($item) {
|
||||
$list[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a category constraint created by
|
||||
* a given list of categories and a junction string
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @param string $categories
|
||||
* @param bool $includeSubCategories
|
||||
* @return array
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
protected function createCategoryConstraint(QueryInterface $query, string $categories, bool $includeSubCategories = false): array
|
||||
{
|
||||
$constraints = [];
|
||||
|
||||
if ($includeSubCategories) {
|
||||
$categoryService = GeneralUtility::makeInstance(CategoryService::class);
|
||||
$allCategories = $categoryService->getChildrenCategories($categories);
|
||||
if (!\is_array($allCategories)) {
|
||||
$allCategories = GeneralUtility::intExplode(',', $allCategories, true);
|
||||
}
|
||||
} else {
|
||||
$allCategories = GeneralUtility::intExplode(',', $categories, true);
|
||||
}
|
||||
|
||||
foreach ($allCategories as $category) {
|
||||
$constraints[] = $query->contains('categories', $category);
|
||||
}
|
||||
return $constraints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Evaluation;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use FriendsOfTYPO3\TtAddress\Utility\EvalcoordinatesUtility;
|
||||
|
||||
/**
|
||||
* Class for validation/evaluation of longitude to be used in 'eval' of TCA
|
||||
* removes everything except numbers and digit-sign (dot). Fills coordinates up with zeros if too short
|
||||
*/
|
||||
class LatitudeEvaluation
|
||||
{
|
||||
/**
|
||||
* Server-side validation/evaluation on saving the record
|
||||
* Tests if latutide is between -90 and +90, fills up with zeros to mach decimal (14,12) in database
|
||||
*
|
||||
* @param string $value The field value to be evaluated
|
||||
* @return string Evaluated field value
|
||||
*/
|
||||
public function evaluateFieldValue($value)
|
||||
{
|
||||
// test if we have any latitude
|
||||
if ($value && $value !== '') {
|
||||
return EvalcoordinatesUtility::formatLatitude($value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side validation/evaluation on opening the record
|
||||
*
|
||||
* @param array $parameters Array with key 'value' containing the field value from the database
|
||||
* @return string Evaluated field value
|
||||
*/
|
||||
public function deevaluateFieldValue(array $parameters)
|
||||
{
|
||||
// test if we have any latitude
|
||||
if ($parameters['value'] && $parameters['value'] !== '') {
|
||||
$parameters['value'] = EvalcoordinatesUtility::formatLatitude($parameters['value']);
|
||||
}
|
||||
return $parameters['value'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Evaluation;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use FriendsOfTYPO3\TtAddress\Utility\EvalcoordinatesUtility;
|
||||
|
||||
/**
|
||||
* Class for validation/evaluation of Longitude to be used in 'eval' of TCA
|
||||
* removes everything except numbers and digit-sign (dot). Fills coordinates up with zeros if too short
|
||||
*/
|
||||
class LongitudeEvaluation
|
||||
{
|
||||
/**
|
||||
* Server-side validation/evaluation on saving the record
|
||||
* Tests if latitude is between -90 and +90, fills up with zeros to mach decimal (14,12) in database
|
||||
*
|
||||
* @param string $value The field value to be evaluated
|
||||
* @return string Evaluated field value
|
||||
*/
|
||||
public function evaluateFieldValue($value)
|
||||
{
|
||||
// test if we have any longitude
|
||||
if ($value && $value !== '') {
|
||||
return EvalcoordinatesUtility::formatLongitude($value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side validation/evaluation on opening the record
|
||||
*
|
||||
* @param array $parameters Array with key 'value' containing the field value from the database
|
||||
* @return string Evaluated field value
|
||||
*/
|
||||
public function deevaluateFieldValue(array $parameters)
|
||||
{
|
||||
// test if we have any longitude
|
||||
if ($parameters['value'] && $parameters['value'] != '') {
|
||||
$parameters['value'] = EvalcoordinatesUtility::formatLongitude($parameters['value']);
|
||||
}
|
||||
return $parameters['value'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Evaluation;
|
||||
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Dto\Settings;
|
||||
use TYPO3\CMS\Core\Information\Typo3Version;
|
||||
use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for telephone number validation/evaluation to be used in 'eval' of TCA
|
||||
*/
|
||||
class TelephoneEvaluation
|
||||
{
|
||||
/** @var Settings */
|
||||
protected $extensionSettings;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->extensionSettings = GeneralUtility::makeInstance(Settings::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript code for client side validation/evaluation
|
||||
*/
|
||||
public function returnFieldJS()
|
||||
{
|
||||
if ((new Typo3Version())->getMajorVersion() >= 12) {
|
||||
GeneralUtility::makeInstance(PageRenderer::class)->addInlineSetting(
|
||||
'TtAddress.Evaluation',
|
||||
'telephoneValidationPattern',
|
||||
$this->extensionSettings->getTelephoneValidationPatternForJs()
|
||||
);
|
||||
return JavaScriptModuleInstruction::create(
|
||||
'@friendsoftypo3/tt-address/telephone-evaluation.js',
|
||||
'TelephoneEvaluation'
|
||||
);
|
||||
}
|
||||
return '
|
||||
return value.replace(' . $this->extensionSettings->getTelephoneValidationPatternForJs() . ', "");
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side validation/evaluation on saving the record
|
||||
*
|
||||
* @param string $value The field value to be evaluated
|
||||
* @return string Evaluated field value
|
||||
*/
|
||||
public function evaluateFieldValue($value)
|
||||
{
|
||||
return $this->evaluate($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side validation/evaluation on opening the record
|
||||
*
|
||||
* @param array $parameters Array with key 'value' containing the field value from the database
|
||||
* @return string Evaluated field value
|
||||
*/
|
||||
public function deevaluateFieldValue(array $parameters)
|
||||
{
|
||||
return $this->evaluate($parameters['value']);
|
||||
}
|
||||
|
||||
private function evaluate(string $in)
|
||||
{
|
||||
$data = preg_replace($this->extensionSettings->getTelephoneValidationPatternForPhp(), '', $in);
|
||||
return trim($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace FriendsOfTYPO3\TtAddress\FormEngine\FieldControl;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Backend\Form\AbstractNode;
|
||||
use TYPO3\CMS\Core\Information\Typo3Version;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\StringUtility;
|
||||
|
||||
/**
|
||||
* Adds a wizard for location selection via map
|
||||
*/
|
||||
class LocationMapWizard extends AbstractNode
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function render(): array
|
||||
{
|
||||
$row = $this->data['databaseRow'];
|
||||
$paramArray = $this->data['parameterArray'];
|
||||
$resultArray = $this->initializeResultArray();
|
||||
|
||||
$nameLongitude = $paramArray['itemFormElName'];
|
||||
$nameLatitude = str_replace('longitude', 'latitude', $nameLongitude);
|
||||
$nameLatitudeActive = str_replace('data', 'control[active]', $nameLatitude);
|
||||
$geoCodeUrl = $geoCodeUrlShort = '';
|
||||
$gLat = '55.6760968';
|
||||
$gLon = '12.5683371';
|
||||
|
||||
$lat = $row['latitude'] != '' ? htmlspecialchars($row['latitude']) : '';
|
||||
$lon = $row['longitude'] != '' ? htmlspecialchars($row['longitude']) : '';
|
||||
|
||||
if ($row['latitude'] || $row['longitude'] == '') {
|
||||
// remove all after first slash in address (top, floor ...)
|
||||
$address = preg_replace('/^([^\/]*).*$/', '$1', $row['address'] ?? '') . ' ';
|
||||
$address .= $row['city'] ?? '';
|
||||
// if we have at least some address part (saves geocoding calls)
|
||||
if ($address) {
|
||||
// base url
|
||||
$geoCodeUrlBase = 'https://nominatim.openstreetmap.org/search?q=';
|
||||
$geoCodeUrlAddress = $address;
|
||||
$geoCodeUrlCityOnly = ($row['city'] ?? '');
|
||||
// urlparams for nominatim which are fixed.
|
||||
$geoCodeUrlQuery = '&format=json&addressdetails=1&limit=1&polygon_svg=1';
|
||||
// replace newlines with spaces; remove multiple spaces
|
||||
$geoCodeUrl = trim(preg_replace('/\s\s+/', ' ', $geoCodeUrlBase . $geoCodeUrlAddress . $geoCodeUrlQuery));
|
||||
$geoCodeUrlShort = trim(preg_replace('/\s\s+/', ' ', $geoCodeUrlBase . $geoCodeUrlCityOnly . $geoCodeUrlQuery));
|
||||
}
|
||||
}
|
||||
|
||||
$resultArray['iconIdentifier'] = 'location-map-wizard';
|
||||
$resultArray['title'] = $this->getLanguageService()->sL('LLL:EXT:tt_address/Resources/Private/Language/locallang_db.xlf:tt_address.locationMapWizard');
|
||||
$resultArray['linkAttributes']['class'] = 'locationMapWizard ';
|
||||
$resultArray['linkAttributes']['data-label-title'] = $this->getLanguageService()->sL('LLL:EXT:tt_address/Resources/Private/Language/locallang_db.xlf:tt_address.locationMapWizard');
|
||||
$resultArray['linkAttributes']['data-label-close'] = $this->getLanguageService()->sL('LLL:EXT:tt_address/Resources/Private/Language/locallang_db.xlf:tt_address.locationMapWizard.close');
|
||||
$resultArray['linkAttributes']['data-label-import'] = $this->getLanguageService()->sL('LLL:EXT:tt_address/Resources/Private/Language/locallang_db.xlf:tt_address.locationMapWizard.import');
|
||||
$resultArray['linkAttributes']['data-lat'] = $lat;
|
||||
$resultArray['linkAttributes']['data-lon'] = $lon;
|
||||
$resultArray['linkAttributes']['data-glat'] = $gLat;
|
||||
$resultArray['linkAttributes']['data-glon'] = $gLon;
|
||||
$resultArray['linkAttributes']['data-geocodeurl'] = $geoCodeUrl;
|
||||
$resultArray['linkAttributes']['data-geocodeurlshort'] = $geoCodeUrlShort;
|
||||
$resultArray['linkAttributes']['data-namelat'] = htmlspecialchars($nameLatitude);
|
||||
$resultArray['linkAttributes']['data-namelon'] = htmlspecialchars($nameLongitude);
|
||||
$resultArray['linkAttributes']['data-namelat-active'] = htmlspecialchars($nameLatitudeActive);
|
||||
$resultArray['linkAttributes']['data-tiles'] = htmlspecialchars('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
|
||||
$resultArray['linkAttributes']['data-copy'] = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
|
||||
$resultArray['stylesheetFiles'][] = 'EXT:tt_address/Resources/Public/Contrib/leaflet-core-1.4.0.css';
|
||||
$resultArray['stylesheetFiles'][] = 'EXT:tt_address/Resources/Public/Backend/LocationMapWizard/leafletBackend.css';
|
||||
|
||||
$versionInformation = GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion();
|
||||
if ($versionInformation > 11) {
|
||||
$id = StringUtility::getUniqueId('t3js-formengine-fieldcontrol-');
|
||||
$resultArray['requireJsModules'][] = JavaScriptModuleInstruction::forRequireJS(
|
||||
'TYPO3/CMS/TtAddress/leaflet-core-1.4.0'
|
||||
)->instance($id);
|
||||
$resultArray['requireJsModules'][] = JavaScriptModuleInstruction::forRequireJS(
|
||||
'TYPO3/CMS/TtAddress/LeafletBackend'
|
||||
)->instance($id);
|
||||
} else {
|
||||
$resultArray['requireJsModules'][] = 'TYPO3/CMS/TtAddress/leaflet-core-1.4.0';
|
||||
$resultArray['requireJsModules'][] = 'TYPO3/CMS/TtAddress/LeafletBackend';
|
||||
}
|
||||
|
||||
return $resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\FormEngine;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
|
||||
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Improve the rendering of the plugin in page module
|
||||
*/
|
||||
class TtAddressPreviewRenderer extends StandardContentPreviewRenderer
|
||||
{
|
||||
protected array $recordMapping = [
|
||||
'singleRecords' => [
|
||||
'table' => 'tt_address',
|
||||
'multiValue' => true,
|
||||
],
|
||||
'pages' => [
|
||||
'table' => 'pages',
|
||||
'multiValue' => true,
|
||||
],
|
||||
'singlePid' => [
|
||||
'table' => 'pages',
|
||||
'multiValue' => false,
|
||||
],
|
||||
'groups' => [
|
||||
'table' => 'sys_category',
|
||||
'multiValue' => true,
|
||||
],
|
||||
];
|
||||
|
||||
protected function renderContentElementPreviewFromFluidTemplate(array $row, ?GridColumnItem $item = null): ?string
|
||||
{
|
||||
$row = $this->enrichRow($row);
|
||||
return parent::renderContentElementPreviewFromFluidTemplate($row, $item);
|
||||
}
|
||||
|
||||
protected function enrichRow(array $row): array
|
||||
{
|
||||
$settings = $this->getFlexFormData($row['pi_flexform'] ?? '');
|
||||
|
||||
foreach ($this->recordMapping as $fieldName => $fieldConfiguration) {
|
||||
if ($settings['settings'][$fieldName] ?? false) {
|
||||
$records = $this->getRecords($fieldConfiguration['table'], $settings['settings'][$fieldName]);
|
||||
|
||||
if ($fieldConfiguration['multiValue']) {
|
||||
$row['_computed'][$fieldName] = $records;
|
||||
} else {
|
||||
$row['_computed'][$fieldName] = $records[0] ?: [];
|
||||
}
|
||||
}
|
||||
}
|
||||
$row['_computed']['lll'] = 'LLL:EXT:tt_address/Resources/Private/Language/ff/locallang_ff.xlf:pi1_flexform.';
|
||||
return $row;
|
||||
}
|
||||
|
||||
protected function getRecords(string $table, string $idList): array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
|
||||
$queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
|
||||
|
||||
$rows = $queryBuilder
|
||||
->select('*')
|
||||
->from($table)
|
||||
->where(
|
||||
$queryBuilder->expr()->in(
|
||||
'uid',
|
||||
$queryBuilder->createNamedParameter(GeneralUtility::intExplode(',', $idList, true), Connection::PARAM_INT_ARRAY)
|
||||
)
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
$row['_computed']['title'] = BackendUtility::getRecordTitle($table, $row);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
protected function getFlexFormData(string $flexforms): array
|
||||
{
|
||||
$settings = [];
|
||||
if (!empty($flexforms)) {
|
||||
$settings = GeneralUtility::makeInstance(FlexFormService::class)->convertFlexFormContentToArray($flexforms);
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Hooks\Tca;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
|
||||
/**
|
||||
* Class AddFieldsToSelector
|
||||
*/
|
||||
class AddFieldsToSelector
|
||||
{
|
||||
/** @var LanguageService */
|
||||
protected $languageService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->languageService = $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
// TODO consolidate with list in pi1
|
||||
const sortFields = ['gender', 'name', 'first_name', 'middle_name', 'last_name', 'title', 'company', 'address', 'building', 'room', 'birthday', 'zip', 'city', 'region', 'country', 'email', 'www', 'phone', 'mobile', 'fax'];
|
||||
|
||||
/**
|
||||
* Manipulating the input array, $params, adding new selectorbox items.
|
||||
*
|
||||
* @param array $params array of select field options (reference)
|
||||
*/
|
||||
public function main(array &$params)
|
||||
{
|
||||
$selectOptions = [];
|
||||
foreach (self::sortFields as $field) {
|
||||
$label = $this->languageService->sL($GLOBALS['TCA']['tt_address']['columns'][$field]['label']);
|
||||
$label = rtrim($label, ':');
|
||||
|
||||
$selectOptions[] = [
|
||||
'field' => $field,
|
||||
'label' => $label
|
||||
];
|
||||
}
|
||||
|
||||
// add sorting by order of single selection
|
||||
$selectOptions[] = [
|
||||
'field' => 'singleSelection',
|
||||
'label' => $this->languageService->sL('LLL:EXT:tt_address/Resources/Private/Language/ff/locallang_ff.xlf:pi1_flexform.sortBy.singleSelection')
|
||||
];
|
||||
|
||||
// sort by labels
|
||||
$labels = [];
|
||||
foreach ($selectOptions as $key => $v) {
|
||||
$labels[$key] = $v['label'];
|
||||
}
|
||||
$labels = array_map('strtolower', $labels);
|
||||
array_multisort($labels, SORT_ASC, $selectOptions);
|
||||
|
||||
// add fields to <select>
|
||||
foreach ($selectOptions as $option) {
|
||||
$params['items'][] = [
|
||||
$option['label'],
|
||||
$option['field']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
76
typo3conf/ext/tt_address/Classes/Hooks/Tca/Label.php
Normal file
76
typo3conf/ext/tt_address/Classes/Hooks/Tca/Label.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Hooks\Tca;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Dynamic label of the address record based on tsconfig
|
||||
*/
|
||||
class Label
|
||||
{
|
||||
private const FALLBACK = [
|
||||
['last_name', 'first_name'],
|
||||
['email'],
|
||||
];
|
||||
|
||||
public function getAddressLabel(array &$params): void
|
||||
{
|
||||
if (!($params['row']['pid'] ?? 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_numeric($params['row']['uid'])) {
|
||||
$row = BackendUtility::getRecordWSOL('tt_address', (int) $params['row']['uid']);
|
||||
} else {
|
||||
$row = $params['row'];
|
||||
}
|
||||
|
||||
// record might be in deleting process
|
||||
if (!$row) {
|
||||
return;
|
||||
}
|
||||
|
||||
$configuration = $this->getConfiguration((int) $row['pid']);
|
||||
if (!$configuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($configuration as $fieldList) {
|
||||
$label = [];
|
||||
foreach ($fieldList as $field) {
|
||||
if (isset($row['uid'], $row[$field]) && !empty($row[$field])) {
|
||||
$label[] = BackendUtility::getProcessedValue('tt_address', $field, $row[$field], 0, false, 0, $row['uid']);
|
||||
}
|
||||
}
|
||||
if (!empty($label)) {
|
||||
$params['title'] = implode(', ', $label);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getConfiguration(int $pid): array
|
||||
{
|
||||
$labelConfiguration = BackendUtility::getPagesTSconfig($pid)['tt_address.']['label'] ?? '';
|
||||
if (!$labelConfiguration) {
|
||||
return self::FALLBACK;
|
||||
}
|
||||
|
||||
$configuration = [];
|
||||
$options = GeneralUtility::trimExplode(';', $labelConfiguration, true);
|
||||
foreach ($options as $option) {
|
||||
$configuration[] = GeneralUtility::trimExplode(',', $option, true);
|
||||
}
|
||||
return $configuration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Seo;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Address;
|
||||
use TYPO3\CMS\Core\PageTitle\AbstractPageTitleProvider;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Generate page title based on properties of the address model
|
||||
*/
|
||||
class AddressTitleProvider extends AbstractPageTitleProvider
|
||||
{
|
||||
private const DEFAULT_PROPERTIES = 'firstName,middleName,lastName';
|
||||
private const DEFAULT_GLUE = '" "';
|
||||
|
||||
/**
|
||||
* @param Address $address
|
||||
* @param array $configuration
|
||||
*/
|
||||
public function setTitle(Address $address, array $configuration = []): void
|
||||
{
|
||||
$titleFields = [];
|
||||
$fields = GeneralUtility::trimExplode(',', $configuration['properties'] ?? self::DEFAULT_PROPERTIES, true);
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$getter = 'get' . ucfirst($field);
|
||||
$value = $address->$getter();
|
||||
if ($value) {
|
||||
$titleFields[] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($titleFields)) {
|
||||
$glue = isset($configuration['glue']) && !empty($configuration['glue']) ? $configuration['glue'] : self::DEFAULT_GLUE;
|
||||
$glue = str_getcsv($glue, '');
|
||||
$this->title = implode($glue[0], $titleFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
128
typo3conf/ext/tt_address/Classes/Service/CategoryService.php
Normal file
128
typo3conf/ext/tt_address/Classes/Service/CategoryService.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Service;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Information\Typo3Version;
|
||||
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Service for category related stuff
|
||||
*/
|
||||
class CategoryService
|
||||
{
|
||||
/** @var TimeTracker */
|
||||
protected $timeTracker;
|
||||
|
||||
/** @var FrontendInterface */
|
||||
protected $cache;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
|
||||
$versionInformation = GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion();
|
||||
$cacheIdentifier = $versionInformation >= 11 ? 'ttaddress_category' : 'cache_ttaddress_category';
|
||||
$this->cache = GeneralUtility::makeInstance(CacheManager::class)->getCache($cacheIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get child categories by calling recursive function
|
||||
* and using the caching framework to save some queries
|
||||
*
|
||||
* @param string $idList list of category ids to start
|
||||
* @param int $counter
|
||||
* @return string comma separated list of category ids
|
||||
*/
|
||||
public function getChildrenCategories(string $idList, int $counter = 0)
|
||||
{
|
||||
$cacheIdentifier = sha1('children' . $idList);
|
||||
|
||||
$entry = $this->cache->get($cacheIdentifier);
|
||||
if (!$entry) {
|
||||
$entry = $this->getChildrenCategoriesRecursive($idList, $counter);
|
||||
$this->cache->set($cacheIdentifier, $entry);
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get child categories
|
||||
*
|
||||
* @param string $idList list of category ids to start
|
||||
* @param int $counter
|
||||
* @return string comma separated list of category ids
|
||||
*/
|
||||
protected function getChildrenCategoriesRecursive(string $idList, $counter = 0): string
|
||||
{
|
||||
$result = [];
|
||||
|
||||
// add id list to the output
|
||||
if ($counter === 0) {
|
||||
$newList = $this->getUidListFromRecords($idList);
|
||||
if ($newList) {
|
||||
$result[] = $newList;
|
||||
}
|
||||
}
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('sys_category');
|
||||
$res = $queryBuilder
|
||||
->select('uid')
|
||||
->from('sys_category')
|
||||
->where(
|
||||
$queryBuilder->expr()->in('parent', $queryBuilder->createNamedParameter(explode(',', $idList), Connection::PARAM_INT_ARRAY))
|
||||
)
|
||||
->executeQuery();
|
||||
|
||||
while ($row = $res->fetchAssociative()) {
|
||||
$counter++;
|
||||
if ($counter > 10000) {
|
||||
$this->timeTracker->setTSlogMessage('EXT:tt_address: one or more recursive categories where found');
|
||||
return implode(',', $result);
|
||||
}
|
||||
$subcategories = $this->getChildrenCategoriesRecursive((string)$row['uid'], $counter);
|
||||
$result[] = $row['uid'] . ($subcategories ? ',' . $subcategories : '');
|
||||
}
|
||||
|
||||
$result = implode(',', $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch ids again from DB to avoid false positives
|
||||
*
|
||||
* @param string $idList
|
||||
* @return string
|
||||
*/
|
||||
protected function getUidListFromRecords(string $idList): string
|
||||
{
|
||||
$list = [];
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('sys_category');
|
||||
$rows = $queryBuilder
|
||||
->select('uid')
|
||||
->from('sys_category')
|
||||
->where(
|
||||
$queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter(explode(',', $idList), Connection::PARAM_INT_ARRAY))
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
foreach ($rows as $row) {
|
||||
$list[] = $row['uid'];
|
||||
}
|
||||
|
||||
return implode(',', $list);
|
||||
}
|
||||
}
|
||||
184
typo3conf/ext/tt_address/Classes/Service/GeocodeService.php
Normal file
184
typo3conf/ext/tt_address/Classes/Service/GeocodeService.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Service;
|
||||
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
|
||||
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryHelper;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Service for category related stuff
|
||||
*
|
||||
* thanks to https://github.com/b13/t3ext-geocoding for inspiration
|
||||
*/
|
||||
class GeocodeService implements SingletonInterface
|
||||
{
|
||||
/** @var int */
|
||||
protected $cacheTime = 7776000;
|
||||
|
||||
/** @var string */
|
||||
protected $geocodingUrl = 'https://maps.googleapis.com/maps/api/geocode/json?language=de&sensor=false';
|
||||
|
||||
public function __construct(string $googleMapsKey = '')
|
||||
{
|
||||
$this->geocodingUrl .= '&key=' . $googleMapsKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* geocodes all missing records in a DB table and then stores the values
|
||||
* in the DB record.
|
||||
*
|
||||
* only works if your DB table has the necessary fields
|
||||
* helpful when calculating a batch of addresses and save the latitude/longitude automatically
|
||||
*
|
||||
* @param string $addWhereClause
|
||||
* @return int
|
||||
*/
|
||||
public function calculateCoordinatesForAllRecordsInTable($addWhereClause = ''): int
|
||||
{
|
||||
$tableName = 'tt_address';
|
||||
$latitudeField = 'latitude';
|
||||
$longitudeField = 'longitude';
|
||||
$streetField = 'address';
|
||||
$zipField = 'zip';
|
||||
$cityField = 'city';
|
||||
$countryField = 'country';
|
||||
|
||||
// Fetch all records without latitude/longitude
|
||||
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);
|
||||
$queryBuilder = $connection->createQueryBuilder();
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
$queryBuilder
|
||||
->select('*')
|
||||
->from($tableName)
|
||||
->where(
|
||||
$queryBuilder->expr()->or(
|
||||
$queryBuilder->expr()->isNull($latitudeField),
|
||||
$queryBuilder->expr()->eq($latitudeField, $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq($latitudeField, 0.00000000000),
|
||||
$queryBuilder->expr()->isNull($longitudeField),
|
||||
$queryBuilder->expr()->eq($longitudeField, $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq($longitudeField, 0.00000000000)
|
||||
)
|
||||
)
|
||||
->setMaxResults(500);
|
||||
if (!empty($addWhereClause)) {
|
||||
$queryBuilder->andWhere(QueryHelper::stripLogicalOperatorPrefix($addWhereClause));
|
||||
}
|
||||
$records = $queryBuilder->executeQuery()->fetchAllAssociative();
|
||||
if (\count($records) > 0) {
|
||||
foreach ($records as $record) {
|
||||
$country = $record[$countryField];
|
||||
|
||||
// do the geocoding
|
||||
if (!empty($record[$zipField]) || !empty($record[$cityField])) {
|
||||
$coords = $this->getCoordinatesForAddress($record[$streetField], $record[$zipField], $record[$cityField], $country);
|
||||
if ($coords) {
|
||||
// Update the record to fill in the latitude and longitude values in the DB
|
||||
$connection->update(
|
||||
$tableName,
|
||||
[
|
||||
$latitudeField => $coords['latitude'],
|
||||
$longitudeField => $coords['longitude'],
|
||||
],
|
||||
[
|
||||
'uid' => $record['uid']
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \count($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* core functionality: asks google for the coordinates of an address
|
||||
* stores known addresses in a local cache.
|
||||
*
|
||||
* @param string $street
|
||||
* @param string $zip
|
||||
* @param string $city
|
||||
* @param string $country
|
||||
* @return array an array with latitude and longitude
|
||||
*/
|
||||
public function getCoordinatesForAddress($street = null, $zip = null, $city = null, $country = ''): array
|
||||
{
|
||||
$addressParts = [];
|
||||
foreach ([$street, $zip . ' ' . $city, $country] as $addressPart) {
|
||||
if (empty($addressPart)) {
|
||||
continue;
|
||||
}
|
||||
$addressParts[] = trim($addressPart);
|
||||
}
|
||||
$address = ltrim(implode(',', $addressParts), ',');
|
||||
if (empty($address)) {
|
||||
return [];
|
||||
}
|
||||
$cacheObject = $this->initializeCache();
|
||||
$cacheKey = 'geocode-' . strtolower(str_replace(' ', '-', preg_replace('/[^0-9a-zA-Z ]/m', '', $address)));
|
||||
// Found in cache? Return it.
|
||||
if ($cacheObject->has($cacheKey)) {
|
||||
return $cacheObject->get($cacheKey);
|
||||
}
|
||||
$result = $this->getApiCallResult(
|
||||
$this->geocodingUrl . '&address=' . urlencode($address)
|
||||
);
|
||||
if (empty($result) || empty($result['results']) || empty($result['results'][0]['geometry'])) {
|
||||
return [];
|
||||
}
|
||||
$geometry = $result['results'][0]['geometry'];
|
||||
$result = [
|
||||
'latitude' => $geometry['location']['lat'],
|
||||
'longitude' => $geometry['location']['lng'],
|
||||
];
|
||||
// Now store the $result in cache and return
|
||||
$cacheObject->set($cacheKey, $result, [], $this->cacheTime);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return array
|
||||
*/
|
||||
protected function getApiCallResult(string $url): array
|
||||
{
|
||||
$response = GeneralUtility::getUrl($url);
|
||||
$result = json_decode($response, true);
|
||||
if ($result['status'] !== 'OVER_QUERY_LIMIT') {
|
||||
return $result;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the cache for the DB requests.
|
||||
*
|
||||
* @param string $name
|
||||
* @return FrontendInterface Cache Object
|
||||
*/
|
||||
protected function initializeCache(string $name = 'ttaddress_geocoding'): FrontendInterface
|
||||
{
|
||||
try {
|
||||
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
|
||||
return $cacheManager->getCache($name);
|
||||
} catch (NoSuchCacheException $e) {
|
||||
throw new \RuntimeException('Unable to load Cache!', 1548785854);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
typo3conf/ext/tt_address/Classes/Utility/CacheUtility.php
Normal file
46
typo3conf/ext/tt_address/Classes/Utility/CacheUtility.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Utility;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Address;
|
||||
|
||||
/**
|
||||
* Class CacheUtility handles cache tags
|
||||
*/
|
||||
class CacheUtility
|
||||
{
|
||||
/**
|
||||
* Adds cache tags to page cache by tt_address-records.
|
||||
*
|
||||
* TYPO3 has a built-in mechanism which flushes the page cache
|
||||
* when editing a record. This is done by a tag that looks
|
||||
* like [table]_[record:uid]
|
||||
*
|
||||
* @param array $addressRecords array with address records
|
||||
*/
|
||||
public static function addCacheTagsByAddressRecords(array $addressRecords)
|
||||
{
|
||||
$prefix = 'tt_address_';
|
||||
$cacheTags = [];
|
||||
foreach ($addressRecords as $addressRecord) {
|
||||
if (!$addressRecord instanceof Address) {
|
||||
continue;
|
||||
}
|
||||
// cache tag for each addressRecord record
|
||||
$cacheTags[] = $prefix . $addressRecord->getUid();
|
||||
|
||||
if ($addressRecord->_getProperty('_localizedUid') != $addressRecord->getUid()) {
|
||||
$cacheTags[] = $prefix . $addressRecord->_getProperty('_localizedUid');
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['TSFE']->addCacheTags($cacheTags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Utility;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class EvalcoordinatesUtility
|
||||
*/
|
||||
class EvalcoordinatesUtility
|
||||
{
|
||||
const LATITUDE_UPPER = '90.00000000';
|
||||
const LONGITUDE_UPPER = '180.00000000';
|
||||
|
||||
/**
|
||||
* @param string $coordinate
|
||||
* @return float evaluated and well-formed coordinate
|
||||
*/
|
||||
public static function formatLongitude(string $coordinate)
|
||||
{
|
||||
return self::validate($coordinate, self::LONGITUDE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $coordinate
|
||||
* @return float evaluated and well-formed coordinate
|
||||
*/
|
||||
public static function formatLatitude(string $coordinate)
|
||||
{
|
||||
return self::validate($coordinate, self::LATITUDE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $coordinate
|
||||
* @param string $upperRange
|
||||
* @return string
|
||||
*/
|
||||
protected static function validate($coordinate, string $upperRange): string
|
||||
{
|
||||
if ($coordinate === '') {
|
||||
return '.00000000';
|
||||
}
|
||||
|
||||
// test if value is negative
|
||||
$negative = '';
|
||||
if ($coordinate[0] === '-') {
|
||||
$negative = '-';
|
||||
}
|
||||
// remove all chars not being digits and point
|
||||
// therefore we will get a number
|
||||
$coordinate = preg_replace("/[^\d\.]/", '', $coordinate);
|
||||
|
||||
// split up string at first occurrence decimal point without losing data
|
||||
$integerPart = strstr($coordinate, '.', true);
|
||||
$decimalPart = strstr($coordinate, '.');
|
||||
|
||||
// if coordinate is given as integer (no decimal point)
|
||||
if ($integerPart === false) {
|
||||
$integerPart = $coordinate;
|
||||
}
|
||||
if ($decimalPart === false) {
|
||||
$decimalPart = '00';
|
||||
}
|
||||
|
||||
// remove all points from decimal-part
|
||||
$decimalPart = preg_replace("/[^\d]/", '', $decimalPart);
|
||||
|
||||
// fill up with zeros or shorten to match our goal of decimal(latitude: 10,8 and longitude: 11,8) in DB
|
||||
if (\strlen($decimalPart) >= 8) {
|
||||
$decimalPart = substr($decimalPart, 0, 8);
|
||||
} else {
|
||||
$decimalPart = str_pad($decimalPart, 8, '0', STR_PAD_RIGHT);
|
||||
}
|
||||
|
||||
// concatenate the whole string to a well-formed longitude and return
|
||||
$coordinate = $integerPart . '.' . $decimalPart;
|
||||
|
||||
// test if value is in the possible range. longitude can be -180 to +180.
|
||||
// latitude can be -90 to +90
|
||||
// At this point, our minus, if there, is stored to 'negative'
|
||||
// therefore we just test if integerpart is bigger than 90
|
||||
if ($coordinate > $upperRange) {
|
||||
$coordinate = $upperRange;
|
||||
}
|
||||
|
||||
// reapply signed/unsigned and return
|
||||
return $negative . $coordinate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Utility;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modify properties of the address model
|
||||
*/
|
||||
class PropertyModification
|
||||
{
|
||||
/**
|
||||
* Get cleaned number of a given telephone, fax or mobile number.
|
||||
* It removes all chars which are not possible to enter on your cell phone.
|
||||
*
|
||||
* @param string $number
|
||||
* @return string
|
||||
*/
|
||||
public static function getCleanedNumber(string $number): string
|
||||
{
|
||||
$number = trim($number);
|
||||
|
||||
// Remove 0 on +49(0)221, but keep 0 on (0)221
|
||||
if (strpos($number, '(0)') > 0) {
|
||||
$number = str_replace('(0)', '', $number);
|
||||
}
|
||||
|
||||
return preg_replace('/[^0-9#+*]/', '', $number);
|
||||
}
|
||||
|
||||
public static function getCleanedDomain(string $domain): string
|
||||
{
|
||||
$domain = trim($domain);
|
||||
if (!$domain) {
|
||||
return '';
|
||||
}
|
||||
$parts = str_replace(['\\\\', '\\"'], ['\\', '"'], str_getcsv($domain, ' '));
|
||||
return $parts[0];
|
||||
}
|
||||
}
|
||||
114
typo3conf/ext/tt_address/Classes/Utility/TypoScript.php
Normal file
114
typo3conf/ext/tt_address/Classes/Utility/TypoScript.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\Utility;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* TypoScript Utility class
|
||||
*/
|
||||
class TypoScript
|
||||
{
|
||||
/**
|
||||
* @param array $previousData
|
||||
* @param array $tsData
|
||||
* @return array
|
||||
*/
|
||||
public function override(array $previousData, array $tsData)
|
||||
{
|
||||
$validFields = GeneralUtility::trimExplode(',', $tsData['settings']['overrideFlexformSettingsIfEmpty'], true);
|
||||
foreach ($validFields as $fieldName) {
|
||||
// Multilevel field
|
||||
if (strpos($fieldName, '.') !== false) {
|
||||
$keyAsArray = explode('.', $fieldName);
|
||||
|
||||
$foundInCurrentTs = $this->getValue($previousData, $keyAsArray);
|
||||
|
||||
if (is_string($foundInCurrentTs) && strlen($foundInCurrentTs) === 0) {
|
||||
$foundInOriginal = $this->getValue($tsData['settings'], $keyAsArray);
|
||||
if ($foundInOriginal) {
|
||||
$previousData = $this->setValue($previousData, $keyAsArray, $foundInOriginal);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($fieldName === 'sortBy' && (($previousData['sortBy'] ?? '') === 'default') && (($tsData['settings']['sortBy'] ?? '') !== '')) {
|
||||
unset($previousData['sortBy']);
|
||||
}
|
||||
// if flexform setting is empty and value is available in TS
|
||||
if (((!isset($previousData[$fieldName]) || (string)$previousData[$fieldName] === '') || (strlen($previousData[$fieldName]) === 0))
|
||||
&& isset($tsData['settings'][$fieldName])
|
||||
) {
|
||||
$previousData[$fieldName] = $tsData['settings'][$fieldName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $previousData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from array by path
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $path
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getValue(array $data, array $path)
|
||||
{
|
||||
$found = true;
|
||||
|
||||
for ($x = 0; $x < count($path) && $found; $x++) {
|
||||
$key = $path[$x];
|
||||
|
||||
if (isset($data[$key])) {
|
||||
$data = $data[$key];
|
||||
} else {
|
||||
$found = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
return $data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value in array by path
|
||||
*
|
||||
* @param array $array
|
||||
* @param $path
|
||||
* @param $value
|
||||
* @return array
|
||||
*/
|
||||
protected function setValue(array $array, $path, $value)
|
||||
{
|
||||
$this->setValueByReference($array, $path, $value);
|
||||
|
||||
return array_merge_recursive([], $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value by reference
|
||||
*
|
||||
* @param array $array
|
||||
* @param array $path
|
||||
* @param $value
|
||||
*/
|
||||
private function setValueByReference(array &$array, array $path, $value)
|
||||
{
|
||||
while (count($path) > 1) {
|
||||
$key = array_shift($path);
|
||||
$array = &$array[$key];
|
||||
}
|
||||
|
||||
$key = reset($path);
|
||||
$array[$key] = $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\ViewHelpers\Clean;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use FriendsOfTYPO3\TtAddress\Utility\PropertyModification;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class DomainViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('value', 'string', 'value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
||||
{
|
||||
$value = $arguments['value'] ?: $renderChildrenClosure();
|
||||
return PropertyModification::getCleanedDomain($value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\ViewHelpers\Clean;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use FriendsOfTYPO3\TtAddress\Utility\PropertyModification;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class PhoneNumberViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('value', 'string', 'value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
||||
{
|
||||
$value = $arguments['value'] ?: $renderChildrenClosure();
|
||||
return PropertyModification::getCleanedNumber($value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\MetaTag\MetaTagManagerRegistry;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class MetaTagViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('property', 'string', 'Property to be set', true);
|
||||
$this->registerArgument('value', 'string', 'value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
||||
{
|
||||
$value = trim($arguments['value'] ?: $renderChildrenClosure());
|
||||
if ($value) {
|
||||
$property = $arguments['property'];
|
||||
$metaTagManager = GeneralUtility::makeInstance(MetaTagManagerRegistry::class)->getManagerForProperty($property);
|
||||
$metaTagManager->addProperty($property, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class RemoveSpacesViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('value', 'string', 'value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
||||
{
|
||||
$value = $arguments['value'] ?: $renderChildrenClosure();
|
||||
return str_replace(' ', '', $value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FriendsOfTYPO3\TtAddress\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "tt_address" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use FriendsOfTYPO3\TtAddress\Domain\Model\Address;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class StaticGoogleMapsViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments(): void
|
||||
{
|
||||
$this->registerArgument('addresses', 'mixed', 'Addresses', true);
|
||||
$this->registerArgument('parameters', 'array', 'Parameters', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
||||
{
|
||||
$mapArguments = $arguments['parameters'];
|
||||
|
||||
$markers = [];
|
||||
foreach ($arguments['addresses'] as $address) {
|
||||
/** @var Address $address */
|
||||
$markers[] = '&markers=' . $address->getLatitude() . ',' . $address->getLongitude();
|
||||
}
|
||||
if (count($markers) === 1) {
|
||||
$mapArguments['zoom'] = 13;
|
||||
}
|
||||
|
||||
return 'https://maps.googleapis.com/maps/api/staticmap?' . GeneralUtility::implodeArrayForUrl('', $mapArguments, '', true) . implode('', $markers);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user