Inital commit
This commit is contained in:
231
core/lib/Thelia/Tools/AddressFormat.php
Normal file
231
core/lib/Thelia/Tools/AddressFormat.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, "\"'");
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class Image
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($imageType , $allowedImageTypes)) {
|
||||
if (in_array($imageType, $allowedImageTypes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
62
core/lib/Thelia/Tools/RememberMeTrait.php
Normal file
62
core/lib/Thelia/Tools/RememberMeTrait.php
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
156
core/lib/Thelia/Tools/TokenProvider.php
Normal file
156
core/lib/Thelia/Tools/TokenProvider.php
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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('&', '&', $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("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
|
||||
"}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
|
||||
"—", "–", ",", "<", ".", ">", "/", "?");
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
73
core/lib/Thelia/Tools/Version/Constraints/BaseConstraint.php
Normal file
73
core/lib/Thelia/Tools/Version/Constraints/BaseConstraint.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
134
core/lib/Thelia/Tools/Version/Version.php
Normal file
134
core/lib/Thelia/Tools/Version/Version.php
Normal 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'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user