Inital commit

This commit is contained in:
2020-11-19 15:36:28 +01:00
parent 71f32f83d3
commit 66ce4ee218
18077 changed files with 2166122 additions and 35184 deletions

View File

@@ -0,0 +1,231 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools;
use CommerceGuys\Addressing\Formatter\DefaultFormatter;
use CommerceGuys\Addressing\Formatter\PostalLabelFormatter;
use CommerceGuys\Addressing\Model\Address;
use CommerceGuys\Addressing\Model\AddressInterface;
use CommerceGuys\Addressing\Repository\AddressFormatRepository;
use CommerceGuys\Addressing\Repository\CountryRepository;
use CommerceGuys\Addressing\Repository\SubdivisionRepository;
use Thelia\Model\Country;
use Thelia\Model\CountryQuery;
use Thelia\Model\Lang;
use Thelia\Model\OrderAddress;
/**
* Class AddressFormat
* @package Thelia\Tools
* @author Julien Chanséaume <julien@thelia.net>
*/
class AddressFormat
{
private static $instance;
private function __construct()
{
}
/**
* @return $this
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new AddressFormat();
}
return self::$instance;
}
/**
* Format an address
*
* @param AddressInterface $address
* @param null $locale
* @param bool $html
* @param string $htmlTag
* @param array $htmlAttributes
* @return string
*/
public function format(
AddressInterface $address,
$locale = null,
$html = true,
$htmlTag = "p",
$htmlAttributes = []
) {
$locale = $this->normalizeLocale($locale);
$addressFormatRepository = new AddressFormatRepository();
$countryRepository = new CountryRepository();
$subdivisionRepository = new SubdivisionRepository();
$formatter = new DefaultFormatter(
$addressFormatRepository,
$countryRepository,
$subdivisionRepository,
$locale
);
$formatter->setOption('html', $html);
$formatter->setOption('html_tag', $htmlTag);
$formatter->setOption('html_attributes', $htmlAttributes);
$addressFormatted = $formatter->format($address);
return $addressFormatted;
}
/**
* Format a Thelia address (Address or OrderAddress)
*
* @param \Thelia\Model\OrderAddress|OrderAddress $address
* @param null $locale
* @param bool $html
* @param string $htmlTag
* @param array $htmlAttributes
* @return string
*/
public function formatTheliaAddress($address, $locale = null, $html = true, $htmlTag = "p", $htmlAttributes = [])
{
$address = $this->mapTheliaAddress($address, $locale);
return $this->format($address, $locale, $html, $htmlTag, $htmlAttributes);
}
/**
* Format an address to a postal label
*
* @param AddressInterface $address
* @param null $locale
* @param null $originCountry
* @param array $options
* @return string
*/
public function postalLabelFormat(AddressInterface $address, $locale = null, $originCountry = null, $options = [])
{
$locale = $this->normalizeLocale($locale);
$addressFormatRepository = new AddressFormatRepository();
$countryRepository = new CountryRepository();
$subdivisionRepository = new SubdivisionRepository();
if (null === $originCountry) {
$countryId = Country::getShopLocation();
if (null === $country = CountryQuery::create()->findPk($countryId)) {
$country = Country::getDefaultCountry();
}
$originCountry = $country->getIsoalpha2();
}
$formatter = new PostalLabelFormatter(
$addressFormatRepository,
$countryRepository,
$subdivisionRepository,
$originCountry,
$locale,
$options
);
$addressFormatted = $formatter->format($address);
return $addressFormatted;
}
/**
* Format a Thelia address (Address or OrderAddress) to a postal label
*
* @param \Thelia\Model\OrderAddress|OrderAddress $address
* @param null $locale
* @param null $originCountry
* @param array $options
* @return string
*/
public function postalLabelFormatTheliaAddress($address, $locale = null, $originCountry = null, $options = [])
{
$address = $this->mapTheliaAddress($address, $locale);
return $this->postalLabelFormat($address, $locale, $originCountry, $options);
}
/**
* Convert a Thelia address (Address or OrderAddress) to ImmutableAddressInterface
*
* @param \Thelia\Model\OrderAddress|OrderAddress $address
* @return Address|\CommerceGuys\Addressing\Model\ImmutableAddressInterface
*/
protected function mapTheliaAddress($address, $locale = null)
{
$country = $address->getCountry();
if (null === $locale) {
$locale = Lang::getDefaultLanguage()->getLocale();
}
$customerTitle = $address->getCustomerTitle()
->setLocale($this->denormalizeLocale($locale))
->getShort()
;
$addressModel = new Address();
$addressModel = $addressModel
->withCountryCode($country->getIsoalpha2())
->withAddressLine1($address->getAddress1())
->withAddressLine2($address->getAddress2())
->withPostalCode($address->getZipcode())
->withLocality($address->getCity())
->withOrganization($address->getCompany())
->withRecipient(
sprintf(
'%s %s %s',
$customerTitle,
$address->getLastname(),
$address->getFirstname()
)
)
;
if ($country->getHasStates() && intval($address->getStateId()) !== 0) {
$addressModel = $addressModel->withAdministrativeArea(
sprintf(
'%s-%s',
$country->getIsoalpha2(),
$address->getState()->getIsocode()
)
);
}
return $addressModel;
}
private function normalizeLocale($locale)
{
if (null !== $locale) {
$locale = str_replace('_', '-', $locale);
}
return $locale;
}
private function denormalizeLocale($locale)
{
if (null !== $locale) {
$locale = str_replace('-', '_', $locale);
}
return $locale;
}
}

View File

@@ -36,14 +36,14 @@ class DateTimeFormat
if ($lang) {
switch ($output) {
case "date" :
case "date":
$format = $lang->getDateFormat();
break;
case "time" :
case "time":
$format = $lang->getTimeFormat();
break;
default:
case "datetime" :
case "datetime":
$format = $lang->getDateTimeFormat();
break;
}

View File

@@ -11,6 +11,7 @@
/*************************************************************************************/
namespace Thelia\Tools\FileDownload;
use Psr\Log\LoggerInterface;
use Symfony\Component\Translation\Translator;
use Thelia\Core\Translation\Translator as TheliaTranslator;
@@ -74,6 +75,7 @@ class FileDownloader implements FileDownloaderInterface
*/
$con = curl_init($url);
curl_setopt($con, CURLOPT_RETURNTRANSFER, true);
curl_setopt($con, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($con);
$errno = curl_errno($con);

View File

@@ -66,8 +66,10 @@ class I18n
Lang::getDefaultLanguage()->getLocale()
)->findOne();
}
if (null === $i18n) { // @todo something else ?
$i18n = new $i18nClass();;
if (null === $i18n) {
// @todo something else ?
$i18n = new $i18nClass();
;
$i18n->setId($id);
foreach ($needed as $need) {
$method = sprintf('set%s', $need);
@@ -94,8 +96,8 @@ class I18n
static::$defaultLocale = Lang::getDefaultLanguage()->getLocale();
}
$locale = static::real_escape($locale);
$defaultLocale = static::real_escape(static::$defaultLocale);
$locale = static::realEscape($locale);
$defaultLocale = static::realEscape(static::$defaultLocale);
$query
->_and()
@@ -104,7 +106,6 @@ class I18n
"(SELECT DISTINCT ".$i18nIdColumn." ".
"FROM `".$i18nTableName."` ".
"WHERE locale=$locale) ".
"THEN ".$localeColumn." = $locale ".
"ELSE ".$localeColumn." = $defaultLocale ".
"END"
@@ -118,7 +119,7 @@ class I18n
*
* Really escapes a string for SQL query.
*/
public static function real_escape($str)
public static function realEscape($str)
{
$str = trim($str, "\"'");

View File

@@ -23,7 +23,7 @@ class Image
return true;
}
if (in_array($imageType , $allowedImageTypes)) {
if (in_array($imageType, $allowedImageTypes)) {
return true;
}

View File

@@ -13,6 +13,7 @@
namespace Thelia\Tools;
use Symfony\Component\HttpFoundation\Request;
use Thelia\Model\CurrencyQuery;
class MoneyFormat extends NumberFormat
{
@@ -27,18 +28,55 @@ class MoneyFormat extends NumberFormat
*
* @param float $number the number
* @param string $decimals number of decimal figures
* @return string
*/
public function formatStandardMoney($number, $decimals = null)
{
return parent::formatStandardNumber($number, $decimals);
}
public function format($number, $decimals = null, $decPoint = null, $thousandsSep = null, $symbol = null)
{
public function format(
$number,
$decimals = null,
$decPoint = null,
$thousandsSep = null,
$symbol = null
) {
$number = parent::format($number, $decimals, $decPoint, $thousandsSep);
if ($symbol !== null) {
$number = $number . ' ' . $symbol;
return $number . ' ' . $symbol;
}
return $number;
}
/**
* @since 2.3
* @param float $number
* @param int $decimals
* @param string $decPoint
* @param string $thousandsSep
* @param int|null $currencyId
* @return string
*/
public function formatByCurrency(
$number,
$decimals = null,
$decPoint = null,
$thousandsSep = null,
$currencyId = null
) {
$number = parent::format($number, $decimals, $decPoint, $thousandsSep);
$currency = $currencyId !== null ? CurrencyQuery::create()->findPk($currencyId) : $this->request->getSession()->getCurrency();
if ($currency !== null && strpos($currency->getFormat(), '%n') !== false) {
return str_replace(
['%n', '%s', '%c'],
[$number, $currency->getSymbol(), $currency->getCode()],
$currency->getFormat()
);
}
return $number;

View File

@@ -32,14 +32,18 @@ class NumberFormat
* Get a standard number, with '.' as decimal point and no thousands separator
* so that this number can be used to perform calculations.
*
* @param float $number the number
* @param float $number the number
* @param string $decimals number of decimal figures
* @return string
*/
public function formatStandardNumber($number, $decimals = null)
{
$lang = $this->request->getSession()->getLang();
if ($decimals == null) $decimals = $lang->getDecimals();
if ($decimals === null) {
$decimals = $lang->getDecimals();
}
return number_format($number, $decimals, '.', '');
}
@@ -47,9 +51,15 @@ class NumberFormat
{
$lang = $this->request->getSession()->getLang();
if ($decimals == null) $decimals = $lang->getDecimals();
if ($decPoint == null) $decPoint = $lang->getDecimalSeparator();
if ($thousandsSep == null) $thousandsSep = $lang->getThousandsSeparator();
if ($decimals === null) {
$decimals = $lang->getDecimals();
}
if ($decPoint === null) {
$decPoint = $lang->getDecimalSeparator();
}
if ($thousandsSep === null) {
$thousandsSep = $lang->getThousandsSeparator();
}
return number_format($number, $decimals, $decPoint, $thousandsSep);
}
}

View File

@@ -15,14 +15,18 @@ namespace Thelia\Tools;
/**
* Class Password
* @package Thelia\Tools
* @author Manuel Raynaud <mraynaud@openstudio.fr>
* @author Manuel Raynaud <manu@raynaud.io>
*/
class Password
{
private static function randgen($letter, $length)
{
return substr(str_shuffle($letter), 0, $length);
$string = "";
do {
$string .= substr(str_shuffle($letter), 0, 1);
} while (strlen($string) < $length);
return $string;
}
/**
@@ -39,4 +43,12 @@ class Password
return self::randgen($letter, $length);
}
public static function generateHexaRandom($length = 8)
{
$letter = "ABCDEF";
$letter .= "0123456789";
return self::randgen($letter, $length);
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Security\Token\CookieTokenProvider;
use Thelia\Core\Security\User\UserInterface;
/**
* Trait RememberMeTrait
* @package Thelia\Tools
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
trait RememberMeTrait
{
/**
* Get the remember me key from the cookie.
*
* @return string hte key found, or null if no key was found.
*/
protected function getRememberMeKeyFromCookie(Request $request, $cookieName)
{
$ctp = new CookieTokenProvider();
return $ctp->getKeyFromCookie($request, $cookieName);
}
/**
* Create the remember me cookie for the given user.
*/
protected function createRememberMeCookie(UserInterface $user, $cookieName, $cookieExpiration)
{
$ctp = new CookieTokenProvider();
$ctp->createCookie(
$user,
$cookieName,
$cookieExpiration
);
}
/**
* Clear the remember me cookie.
*/
protected function clearRememberMeCookie($cookieName)
{
$ctp = new CookieTokenProvider();
$ctp->clearCookie($cookieName);
}
}

View File

@@ -12,7 +12,6 @@
namespace Thelia\Tools\Rest;
use Thelia\Core\HttpFoundation\Response;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
@@ -95,5 +94,4 @@ class ResponseRest extends Response
return new Serializer($normalizers, $encoders);
}
}

View File

@@ -0,0 +1,156 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Thelia\Core\Security\Exception\TokenAuthenticationException;
/**
* Class TokenProvider
* @package Thelia\Tools
* @author Benjamin Perche <bperche@openstudio.fr>
*/
class TokenProvider
{
/**
* @var string The stored token for this page
*/
protected $token;
/**
* @var SessionInterface The session where the token is stored
*/
protected $session;
/**
* @var RequestStack
*/
protected $requestStack;
/**
* @var TranslatorInterface The translator
*/
protected $translator;
/**
* @var string the current name of the token
*/
protected $tokenName;
/**
* @param RequestStack $requestStack
* @param TranslatorInterface $translator
* @param $tokenName
*/
public function __construct(RequestStack $requestStack, TranslatorInterface $translator, $tokenName)
{
/**
* Store the services
*/
$this->requestStack = $requestStack;
$this->session = $this->requestStack->getCurrentRequest()->getSession();
$this->translator = $translator;
$this->tokenName = $tokenName;
$this->token = $this->session->get($this->tokenName);
}
/**
* @return string
*/
public function assignToken()
{
if (null === $this->token) {
$this->token = $this->getToken();
$this->session->set($this->tokenName, $this->token);
}
return $this->token;
}
/**
* @param string $entryValue
* @return bool
* @throws \Thelia\Core\Security\Exception\TokenAuthenticationException
*/
public function checkToken($entryValue)
{
if (null === $this->token) {
throw new TokenAuthenticationException(
"Tried to check a token without assigning it before"
);
} elseif ($this->token !== $entryValue) {
throw new TokenAuthenticationException(
"Tried to validate an invalid token"
);
}
return true;
}
protected function refreshToken()
{
$this->token = null;
$this->assignToken();
}
/**
* @return string
*/
public function getToken()
{
return self::generateToken();
}
/**
* Same method as getToken but can be called statically
*
* @alias getToken
* @return string
*/
public static function generateToken()
{
$raw = self::getOpenSSLRandom();
if (false === $raw) {
$raw = self::getComplexRandom();
}
return md5($raw);
}
/**
* @param int $length
* @return string
*/
protected static function getOpenSSLRandom($length = 40)
{
if (!function_exists("openssl_random_pseudo_bytes")) {
return false;
}
return openssl_random_pseudo_bytes($length);
}
/**
* @return string
*/
protected static function getComplexRandom()
{
$firstValue = (float) (mt_rand(1, 0xFFFF) * rand(1, 0x10001));
$secondValues = (float) (rand(1, 0xFFFF) * mt_rand(1, 0x10001));
return microtime() . ceil($firstValue / $secondValues) . uniqid();
}
}

View File

@@ -15,9 +15,9 @@ namespace Thelia\Tools;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Validator\Constraints\UrlValidator;
use Thelia\Model\ConfigQuery;
use Thelia\Model\LangQuery;
use Thelia\Rewriting\RewritingResolver;
use Thelia\Rewriting\RewritingRetriever;
use Thelia\Core\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -47,13 +47,23 @@ class URL
// in TheliaHttpKernel, by calling $this->container->get('thelia.url.manager');
self::$instance = $this;
if ($container !== null)
if ($container !== null) {
$this->requestContext = $container->get('router.admin')->getContext();
}
$this->retriever = new RewritingRetriever();
$this->resolver = new RewritingResolver();
}
/**
* @param RequestContext $requestContext
* @since Version 2.2
*/
public function setRequestContext(RequestContext $requestContext)
{
$this->requestContext = $requestContext;
}
/**
* Return this class instance, only once instanciated.
*
@@ -62,7 +72,9 @@ class URL
*/
public static function getInstance()
{
if (self::$instance == null) throw new \RuntimeException("URL instance is not initialized.");
if (self::$instance == null) {
throw new \RuntimeException("URL instance is not initialized.");
}
return self::$instance;
}
@@ -77,12 +89,10 @@ class URL
public function getBaseUrl($scheme_only = false)
{
if (null === $this->baseUrlScheme) {
$scheme = "http";
$port = 80;
if ($host = $this->requestContext->getHost()) {
$scheme = $this->requestContext->getScheme();
$port = '';
@@ -122,9 +132,8 @@ class URL
*/
public function absoluteUrl($path, array $parameters = null, $path_only = self::WITH_INDEX_PAGE)
{
// Already absolute ?
// Already absolute ?
if (substr($path, 0, 4) != 'http') {
// Prevent duplication of the subdirectory name when Thelia is installed in a subdirectory.
// This happens when $path was calculated with Router::generate(), which returns an absolute URL,
// starting at web server root. For example, if Thelia is installed in /thelia2, we got something like /thelia2/my/path
@@ -146,29 +155,32 @@ class URL
// If only a path is requested, be sure to remove the script name (index.php or index_dev.php), if any.
if ($path_only == self::PATH_TO_FILE) {
if (substr($base_url, -3) == 'php') $base_url = dirname($base_url);
if (substr($base_url, -3) == 'php') {
$base_url = dirname($base_url);
}
}
// Normalize the given path
$base = rtrim($base_url, '/') . '/' . ltrim($path, '/');
} else
} else {
$base = $path;
}
$base = str_replace('&amp;', '&', $base);
$queryString = '';
$anchor = '';
if (! is_null($parameters)) {
foreach ($parameters as $name => $value) {
// Remove this parameter from base URL to prevent duplicate parameters
$base = preg_replace('/([?&])'.$name.'=([^&])*(&|$)/', '$1', $base);
$base = preg_replace('`([?&])'.preg_quote($name, '`').'=(?:[^&]*)(?:&|$)`', '$1', $base);
$queryString .= sprintf("%s=%s&", urlencode($name), urlencode($value));
}
}
if ('' !== $queryString = rtrim($queryString, "&")) {
// url could contain anchor
$pos = strrpos($base, '#');
if ($pos !== false) {
@@ -204,115 +216,118 @@ class URL
/**
* Returns the Absolute URL to a view
*
* @param string $viewName the view name (e.g. login for login.html)
* @param mixed $parameters An array of parameters
* @param string $viewName the view name (e.g. login for login.html)
* @param mixed $parameters An array of parameters
*
* @return string The generated URL
*/
public function viewUrl($viewName, array $parameters = array())
{
$path = sprintf("?view=%s", $viewName);
public function viewUrl($viewName, array $parameters = array())
{
$path = sprintf("?view=%s", $viewName);
return $this->absoluteUrl($path, $parameters);
}
return $this->absoluteUrl($path, $parameters);
}
/**
* Retrieve a rewritten URL from a view, a view id and a locale
*
* @param $view
* @param $viewId
* @param $viewLocale
*
* @return RewritingRetriever You can access $url and $rewrittenUrl properties
*/
public function retrieve($view, $viewId, $viewLocale)
{
if (ConfigQuery::isRewritingEnable()) {
$this->retriever->loadViewUrl($view, $viewLocale, $viewId);
} else {
$allParametersWithoutView = array();
$allParametersWithoutView['locale'] = $viewLocale;
if (null !== $viewId) {
$allParametersWithoutView[$view . '_id'] = $viewId;
}
$this->retriever->rewrittenUrl = null;
$this->retriever->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
}
/**
* Retrieve a rewritten URL from a view, a view id and a locale
*
* @param $view
* @param $viewId
* @param $viewLocale
*
* @return RewritingRetriever You can access $url and $rewrittenUrl properties
*/
public function retrieve($view, $viewId, $viewLocale)
{
if (ConfigQuery::isRewritingEnable()) {
$this->retriever->loadViewUrl($view, $viewLocale, $viewId);
} else {
$allParametersWithoutView = array();
$allParametersWithoutView['lang'] = $viewLocale;
if (null !== $viewId) {
$allParametersWithoutView[$view . '_id'] = $viewId;
}
$this->retriever->rewrittenUrl = null;
$this->retriever->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
}
return $this->retriever;
}
return $this->retriever;
}
/**
* Retrieve a rewritten URL from the current GET parameters
*
* @param Request $request
*
* @return RewritingRetriever You can access $url and $rewrittenUrl properties or use toString method
*/
public function retrieveCurrent(Request $request)
{
if (ConfigQuery::isRewritingEnable()) {
$view = $request->attributes->get('_view', null);
$viewLocale = $request->query->get('locale', null);
$viewId = $view === null ? null : $request->query->get($view . '_id', null);
/**
* Retrieve a rewritten URL from the current GET parameters
*
* @param Request $request
*
* @return RewritingRetriever You can access $url and $rewrittenUrl properties or use toString method
*/
public function retrieveCurrent(Request $request)
{
if (ConfigQuery::isRewritingEnable()) {
$view = $request->attributes->get('_view', null);
$allOtherParameters = $request->query->all();
if ($view !== null) {
unset($allOtherParameters['view']);
if ($viewId !== null) {
unset($allOtherParameters[$view . '_id']);
}
}
if ($viewLocale !== null) {
unset($allOtherParameters['locale']);
}
$viewLocale = $this->getViewLocale($request);
$this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters);
} else {
$allParametersWithoutView = $request->query->all();
$view = $request->attributes->get('_view');
if (isset($allOtherParameters['view'])) {
unset($allOtherParameters['view']);
}
$this->retriever->rewrittenUrl = null;
$this->retriever->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
}
$viewId = $view === null ? null : $request->query->get($view . '_id', null);
return $this->retriever;
}
$allOtherParameters = $request->query->all();
if ($view !== null) {
unset($allOtherParameters['view']);
if ($viewId !== null) {
unset($allOtherParameters[$view . '_id']);
}
}
if ($viewLocale !== null) {
unset($allOtherParameters['lang']);
unset($allOtherParameters['locale']);
}
/**
* Retrieve a rewritten URL from the current GET parameters or use toString method
*
* @param $url
*
* @return RewritingResolver
*/
public function resolve($url)
{
$this->resolver->load($url);
$this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters);
} else {
$allParametersWithoutView = $request->query->all();
$view = $request->attributes->get('_view');
if (isset($allOtherParameters['view'])) {
unset($allOtherParameters['view']);
}
$this->retriever->rewrittenUrl = null;
$this->retriever->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
}
return $this->resolver;
}
return $this->retriever;
}
protected function sanitize($string, $force_lowercase = true, $alphabetic_only = false)
{
static $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
/**
* Retrieve a rewritten URL from the current GET parameters or use toString method
*
* @param $url
*
* @return RewritingResolver
*/
public function resolve($url)
{
$this->resolver->load($url);
return $this->resolver;
}
protected function sanitize($string, $force_lowercase = true, $alphabetic_only = false)
{
static $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
"}", "\\", "|", ";", ":", "\"", "'", "&#8216;", "&#8217;", "&#8220;", "&#8221;", "&#8211;", "&#8212;",
"—", "–", ",", "<", ".", ">", "/", "?");
$clean = trim(str_replace($strip, "", strip_tags($string)));
$clean = trim(str_replace($strip, "", strip_tags($string)));
$clean = preg_replace('/\s+/', "-", $clean);
$clean = preg_replace('/\s+/', "-", $clean);
$clean = ($alphabetic_only) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
$clean = ($alphabetic_only) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
return ($force_lowercase) ?
return ($force_lowercase) ?
(function_exists('mb_strtolower')) ?
mb_strtolower($clean, 'UTF-8') :
strtolower($clean) :
$clean;
}
}
public static function checkUrl($url, array $protocols = ["http", "https"])
{
@@ -320,4 +335,21 @@ class URL
return (bool) preg_match($pattern, $url);
}
/**
* Get the locale code from the lang attribute in URL.
*
* @param Request $request
* @return null|string
*/
private function getViewLocale(Request $request)
{
$viewLocale = $request->query->get('lang', null);
if (null === $viewLocale) {
// fallback for old parameter
$viewLocale = $request->query->get('locale', null);
}
return $viewLocale;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version\Constraints;
/**
* Class BaseConstraint
* @package Thelia\Tools\Version\Constraints
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
abstract class BaseConstraint implements ConstraintInterface
{
protected $operator = "=";
protected $expression = null;
public function __construct($expression)
{
$this->expression = $expression;
}
public function test($version, $strict = false)
{
$version = $this->normalize($version, $strict);
return version_compare($version, $this->expression, $this->operator);
}
public function normalize($version, $strict = false)
{
return $strict ? $version : $this->normalizePrecision($version);
}
protected function normalizePrecision($version, $changeExpression = true)
{
$expressionElements = preg_split('/[\.\-]/', $this->expression);
// cleaning alpha RC beta
$version = preg_replace('/\-.*$/', '', $version);
$versionElements = preg_split('/\./', $version);
if (count($expressionElements) < count($versionElements)) {
if (true === $changeExpression) {
$this->expression = implode(
'.',
array_merge(
$expressionElements,
array_fill(
count($expressionElements) - 1,
count($versionElements) - count($expressionElements),
'0'
)
)
);
} else {
$version = implode(
'.',
array_slice($versionElements, 0, count($expressionElements))
);
}
}
return $version;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version\Constraints;
/**
* Class ConstraintEqual
* @package Thelia\Tools\Version\Constraints
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
class ConstraintEqual extends BaseConstraint
{
public function __construct($expression)
{
$this->expression = str_replace('=', '', $expression);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version\Constraints;
/**
* Class ConstraintGreater
* @package Thelia\Tools\Version\Constraints
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
class ConstraintGreater extends BaseConstraint
{
public function __construct($expression, $strict = false)
{
$this->operator = $strict ? ">" : ">=";
$this->expression = substr(
$expression,
strlen($this->operator)
);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version\Constraints;
/**
* Class ContraintInterface
* @package Thelia\Tools\Version\Constraints
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
interface ConstraintInterface
{
/**
* Normalize a version number in a version that will be used in `version_compare`
*
* @param string $version the version expression
* @return string the normalized expression
*/
public function normalize($version, $strict = false);
/**
* Test if the version number is valid
*
* @param string $version the version number
* @param bool $strict if false precision will be normalized. eg: 2.1.0 > 2.1 will become 2.1.0 > 2.1.0 (default false)
* @return bool true if the version is equal, otherwise false
*/
public function test($version, $strict = false);
}

View File

@@ -0,0 +1,30 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version\Constraints;
/**
* Class ConstraintLower
* @package Thelia\Tools\Version\Constraints
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
class ConstraintLower extends BaseConstraint
{
public function __construct($expression, $strict = false)
{
$this->operator = $strict ? "<" : "<=";
$this->expression = substr(
$expression,
strlen($this->operator)
);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version\Constraints;
/**
* Class ConstraintNearlyEqual
* @package Thelia\Tools\Version\Constraints
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
class ConstraintNearlyEqual extends BaseConstraint
{
public function __construct($expression)
{
$this->expression = str_replace('~', '', $expression);
}
public function normalize($version, $strict = false)
{
if (!$strict) {
$version = $this->normalizePrecision($version, false);
}
return $version;
}
}

View File

@@ -0,0 +1,134 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Tools\Version;
use Thelia\Tools\Version\Constraints\ConstraintEqual;
use Thelia\Tools\Version\Constraints\ConstraintGreater;
use Thelia\Tools\Version\Constraints\ConstraintInterface;
use Thelia\Tools\Version\Constraints\ConstraintLower;
use Thelia\Tools\Version\Constraints\ConstraintNearlyEqual;
/**
* Class Version
* @package Thelia\Tools
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
class Version
{
/**
* Test if a version matched the version contraints.
*
* constraints can be simple or complex (multiple constraints separated by space) :
*
* - "~2.1" : version 2.1.*
* - "~2.1 <=2.1.4" : version 2.1.* but lower or equal to 2.1.4
* - ">=2.1" : version 2.1.*, 2.2, ...
* - ">2.1.1 <=2.1.5" : version greater than 2.1.1 but lower or equal than 2.1.5
* - ...
*
* @param string $version the version to test
* @param string $constraints the versions constraints
* @param bool $strict if true 2.1 is different of 2.1.0, if false version are normalized so 2.1
* will be expended to 2.1.0
* @param string $defaultComparison the default comparison if nothing provided
* @return bool true if version matches the constraints
*/
public static function test($version, $constraints, $strict = false, $defaultComparison = "=")
{
$constraints = self::parseConstraints($constraints, $defaultComparison);
/** @var ConstraintInterface $constraint */
foreach ($constraints as $constraint) {
if (!$constraint->test($version, $strict)) {
return false;
}
}
return true;
}
private static function parseConstraints($constraints, $defaultComparison = "=")
{
$constraintsList = [];
foreach (explode(" ", $constraints) as $expression) {
if (1 === preg_match('/^[0-9]/', $expression)) {
$expression = $defaultComparison . $expression;
}
if (strpos($expression, '>=') !== false) {
$constraint = new ConstraintGreater($expression);
} elseif (strpos($expression, '>') !== false) {
$constraint = new ConstraintGreater($expression, true);
} elseif (strpos($expression, '<=') !== false) {
$constraint = new ConstraintLower($expression);
} elseif (strpos($expression, '<') !== false) {
$constraint = new ConstraintLower($expression, true);
} elseif (strpos($expression, '~') !== false) {
$constraint = new ConstraintNearlyEqual($expression);
} else {
$constraint = new ConstraintEqual($expression);
}
$constraintsList[] = $constraint;
}
return $constraintsList;
}
/**
* Split a version into an associative array
* [version, major, minus, release, extra]
*
* @param string $version the version to split
* @return array associative array
* [
* 'version' => 'digit',
* 'major' => 'digit',
* 'minus' => 'digit',
* 'release' => 'digit',
* 'extra' => 'alphanumeric'
* ]
*/
public static function parse($version = null)
{
if (is_null($version)) {
$version = \Thelia\Core\Thelia::THELIA_VERSION;
}
$pattern = "`^(?<version>
(?<major>[0-9]+)\.
(?<minus>[0-9]+)\.
(?<release>[0-9]+)
-?(?<extra>[a-zA-Z0-9]*) # extra_version will also match empty string
)$`x";
if (!preg_match($pattern, $version, $match)) {
throw new \InvalidArgumentException(
sprintf(
"Invalid version number provided : %s".PHP_EOL,
$version
)
);
}
return [
'version' => $match['version'],
'major' => $match['major'],
'minus' => $match['minus'],
'release' => $match['release'],
'extra' => $match['extra'],
];
}
}