First, initial commit

This commit is contained in:
Meritoo
2017-08-29 22:37:19 +02:00
commit d9ab2a082e
67 changed files with 18377 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Base;
use Exception;
use Meritoo\Common\Type\Base\BaseType;
use Meritoo\Common\Utilities\Arrays;
/**
* An exception used while type of something is unknown
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
abstract class UnknownTypeException extends Exception
{
/**
* Class constructor
*
* @param string|int $unknownType The unknown type of something (value of constant)
* @param BaseType $typeInstance An instance of class that contains type of the something
* @param string $typeName Name of the something
*/
public function __construct($unknownType, BaseType $typeInstance, $typeName)
{
$allTypes = $typeInstance->getAll();
$types = Arrays::values2string($allTypes, '', ', ');
$template = 'The \'%s\' type of %s is unknown. Probably doesn\'t exist or there is a typo. You should use one'
. ' of these types: %s.';
$message = sprintf(sprintf($template, $unknownType, $typeName, $types));
parent::__construct($message);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Date;
use Exception;
/**
* An exception used while given part of date is incorrect, e.g. value of year is incorrect
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class IncorrectDatePartException extends Exception
{
/**
* Class constructor
*
* @param string $value Incorrect value
* @param string $datePart Type of date part, e.g. "year". One of \Meritoo\Common\Type\DatePartType class constants.
*/
public function __construct($value, $datePart)
{
$message = sprintf('Value of %s \'%s\' is incorrect. Is there everything ok?', $datePart, $value);
parent::__construct($message);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception;
/**
* An exception used while length of given hexadecimal value of color is incorrect
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class IncorrectColorHexLengthException extends \Exception
{
/**
* Class constructor
*
* @param string $color Incorrect hexadecimal value of color
*/
public function __construct($color)
{
$template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6.'
. ' Is there everything ok?';
$message = sprintf($template, $color, strlen($color));
parent::__construct($message);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception;
/**
* An exception used while given hexadecimal value of color is incorrect
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class InvalidColorHexValueException extends \Exception
{
/**
* Class constructor
*
* @param string $color Incorrect hexadecimal value of color
*/
public function __construct($color)
{
$message = sprintf('Hexadecimal value of color \'%s\' is incorrect. Is there everything ok?', $color);
parent::__construct($message);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Reflection;
use Exception;
/**
* An exception used while name of class or trait cannot be resolved
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class CannotResolveClassNameException extends Exception
{
/**
* Class constructor
*
* @param array|object|string $source Source of the class's / trait's name. It cane be an array of objects,
* namespaces, object or namespace.
* @param bool $forClass (optional) If is set to true, message of this exception for class is
* prepared. Otherwise - for trait.
*/
public function __construct($source, $forClass = true)
{
$forWho = 'trait';
$value = '';
if ($forClass) {
$forWho = 'class';
}
if (is_scalar($source)) {
$value = sprintf(' %s', (string)$source);
}
$template = 'Name of %s from given \'%s\'%s cannot be resolved. Is there everything ok?';
$message = sprintf($template, $forWho, gettype($source), $value);
parent::__construct($message);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Reflection;
use Exception;
use Meritoo\Common\Utilities\Reflection;
/**
* An exception used while given class has no child classes
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class MissingChildClassesException extends Exception
{
/**
* Class constructor
*
* @param array|object|string $parentClass Class that hasn't child classes, but it should. An array of objects,
* strings, object or string.
*/
public function __construct($parentClass)
{
$template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract'
. ' class), but the child classes are missing. Did you forget to extend this class?';
$parentClassName = Reflection::getClassName($parentClass);
$message = sprintf($template, $parentClassName);
parent::__construct($message);
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Reflection;
use Exception;
use Meritoo\Common\Utilities\Reflection;
/**
* An exception used while given class has more than one child class
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class TooManyChildClassesException extends Exception
{
/**
* Class constructor
*
* @param array|object|string $parentClass Class that has more than one child class, but it shouldn't. An array
* of objects, strings, object or string.
* @param array $childClasses Child classes
*/
public function __construct($parentClass, array $childClasses)
{
$template = "The '%s' class requires one child class at most who will extend her, but more than one child"
. " class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?";
$parentClassName = Reflection::getClassName($parentClass);
$message = sprintf($template, $parentClassName, implode("\n- ", $childClasses), $parentClassName);
parent::__construct($message);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Type\Base;
use Meritoo\Common\Utilities\Reflection;
/**
* Base / abstract type of something, e.g. type of button, order, date etc.
* Child class should contain constants - each of them represent one type.
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
abstract class BaseType
{
/**
* All types
*
* @var array
*/
private $all;
/**
* Returns all types
*
* @return array
*/
public function getAll()
{
if ($this->all === null) {
$this->all = Reflection::getConstants($this);
}
return $this->all;
}
/**
* Returns information if given type is correct
*
* @param string $type The type to check
* @return bool
*/
public function isCorrectType($type)
{
return in_array($type, $this->getAll(), true);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Meritoo\Common\Type;
use Meritoo\Common\Type\Base\BaseType;
/**
* Type of date part, e.g. "year"
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class DatePartType extends BaseType
{
/**
* The "day" date part
*
* @var string
*/
const DAY = 'day';
/**
* The "hour" date part
*
* @var string
*/
const HOUR = 'hour';
/**
* The "minute" date part
*
* @var string
*/
const MINUTE = 'minute';
/**
* The "month" date part
*
* @var string
*/
const MONTH = 'month';
/**
* The "second" date part
*
* @var string
*/
const SECOND = 'second';
/**
* The "year" date part
*
* @var string
*/
const YEAR = 'year';
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Useful methods for bundle
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Bundle
{
/**
* Returns path to view / template of given bundle
*
* @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template"
* @param string $bundleName Name of the bundle, e.g. "MyExtraBundle"
* @param string $extension (optional) Extension of the view / template
* @return string|null
*/
public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig')
{
/*
* Unknown path, extension of the view / template or name of the bundle?
* Nothing to do
*/
if (empty($viewPath) || empty($bundleName) || empty($extension)) {
return null;
}
/*
* Path of the view / template doesn't end with given extension?
*/
if (!Regex::endsWith($viewPath, $extension)) {
$viewPath = sprintf('%s.%s', $viewPath, $extension);
}
return sprintf('%s:%s', $bundleName, $viewPath);
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use stdClass;
/**
* Useful Composer-related methods (only static functions)
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Composer
{
/**
* Name of the Composer's main file with configuration in Json format
*
* @var string
*/
const FILE_NAME_MAIN = 'composer.json';
/**
* Returns value from composer.json file
*
* @param string $composerJsonPath Path of composer.json file
* @param string $nodeName Name of node who value should be returned
* @return string|null
*/
public static function getValue($composerJsonPath, $nodeName)
{
$composerJsonString = is_string($composerJsonPath);
$composerJsonReadable = false;
if ($composerJsonString) {
$composerJsonReadable = is_readable($composerJsonPath);
}
/*
* Provided path or name of node are invalid?
* The composer.json file doesn't exist or isn't readable?
* Name of node is unknown?
*
* Nothing to do
*/
if (!$composerJsonString || !is_string($nodeName) || !$composerJsonReadable || empty($nodeName)) {
return null;
}
$content = file_get_contents($composerJsonPath);
$data = json_decode($content);
/*
* Unknown data from the composer.json file or there is no node with given name?
* Nothing to do
*/
if ($data === null || !isset($data->{$nodeName})) {
return null;
}
/* @var stdClass $data */
return $data->{$nodeName};
}
}

View File

@@ -0,0 +1,714 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use DateInterval;
use DateTime;
use Meritoo\Common\Exception\Date\IncorrectDatePartException;
use Meritoo\Common\Type\DatePartType;
/**
* Useful date methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Date
{
/**
* The 'days' unit of date difference.
* Difference between dates in days.
*
* @var string
*/
const DATE_DIFFERENCE_UNIT_DAYS = 'days';
/**
* The 'hours' unit of date difference.
* Difference between dates in hours.
*
* @var string
*/
const DATE_DIFFERENCE_UNIT_HOURS = 'hours';
/**
* The 'minutes' unit of date difference.
* Difference between dates in minutes.
*
* @var string
*/
const DATE_DIFFERENCE_UNIT_MINUTES = 'minutes';
/**
* The 'months' unit of date difference.
* Difference between dates in months.
*
* @var string
*/
const DATE_DIFFERENCE_UNIT_MONTHS = 'months';
/**
* The 'years' unit of date difference.
* Difference between dates in years.
*
* @var string
*/
const DATE_DIFFERENCE_UNIT_YEARS = 'years';
/**
* Returns start and end date for given period.
* The dates are returned in an array with indexes 'start' and 'end'.
*
* @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK.
* @return DatePeriod
*/
public static function getDatesForPeriod($period)
{
$datePeriod = null;
if (DatePeriod::isCorrectPeriod($period)) {
$dateStart = null;
$dateEnd = null;
switch ($period) {
case DatePeriod::LAST_WEEK:
$thisWeekStart = new DateTime('this week');
$dateStart = clone $thisWeekStart;
$dateEnd = clone $thisWeekStart;
$dateStart->sub(new DateInterval('P7D'));
$dateEnd->sub(new DateInterval('P1D'));
break;
case DatePeriod::THIS_WEEK:
$dateStart = new DateTime('this week');
$dateEnd = clone $dateStart;
$dateEnd->add(new DateInterval('P6D'));
break;
case DatePeriod::NEXT_WEEK:
$dateStart = new DateTime('this week');
$dateStart->add(new DateInterval('P7D'));
$dateEnd = clone $dateStart;
$dateEnd->add(new DateInterval('P6D'));
break;
case DatePeriod::LAST_MONTH:
$dateStart = new DateTime('first day of last month');
$dateEnd = new DateTime('last day of last month');
break;
case DatePeriod::THIS_MONTH:
$lastMonth = self::getDatesForPeriod(DatePeriod::LAST_MONTH);
$nextMonth = self::getDatesForPeriod(DatePeriod::NEXT_MONTH);
$dateStart = $lastMonth->getEndDate();
$dateStart->add(new DateInterval('P1D'));
$dateEnd = $nextMonth->getStartDate();
$dateEnd->sub(new DateInterval('P1D'));
break;
case DatePeriod::NEXT_MONTH:
$dateStart = new DateTime('first day of next month');
$dateEnd = new DateTime('last day of next month');
break;
case DatePeriod::LAST_YEAR:
case DatePeriod::THIS_YEAR:
case DatePeriod::NEXT_YEAR:
$dateStart = new DateTime();
$dateEnd = new DateTime();
if ($period == DatePeriod::LAST_YEAR || $period == DatePeriod::NEXT_YEAR) {
$yearDifference = 1;
if ($period == DatePeriod::LAST_YEAR) {
$yearDifference *= -1;
}
$modifyString = sprintf('%s year', $yearDifference);
$dateStart->modify($modifyString);
$dateEnd->modify($modifyString);
}
$year = $dateStart->format('Y');
$dateStart->setDate($year, 1, 1);
$dateEnd->setDate($year, 12, 31);
break;
}
if ($dateStart !== null && $dateEnd !== null) {
$dateStart->setTime(0, 0, 0);
$dateEnd->setTime(23, 59, 59);
$datePeriod = new DatePeriod($dateStart, $dateEnd);
}
}
return $datePeriod;
}
/**
* Generates and returns random time (the hour, minute and second values)
*
* @param string $format (optional) Format of returned value. A string acceptable by the DateTime::format()
* method.
* @return string|null
*/
public static function generateRandomTime($format = 'H:i:s')
{
$dateTime = new DateTime();
/*
* Format si empty or is incorrect?
* Nothing to do
*/
if (empty($format) || $dateTime->format($format) === $format) {
return null;
}
$hours = [];
$minutes = [];
$seconds = [];
for ($i = 1; $i <= 23; ++$i) {
$hours[] = $i;
}
for ($i = 1; $i <= 59; ++$i) {
$minutes[] = $i;
}
for ($i = 1; $i <= 59; ++$i) {
$seconds[] = $i;
}
/*
* Prepare random time (hour, minute and second)
*/
$hour = $hours[array_rand($hours)];
$minute = $minutes[array_rand($minutes)];
$second = $seconds[array_rand($seconds)];
return $dateTime
->setTime($hour, $minute, $second)
->format($format);
}
/**
* Returns current day of week
*
* @return int
*/
public static function getCurrentDayOfWeek()
{
$now = new DateTime();
$year = $now->format('Y');
$month = $now->format('m');
$day = $now->format('d');
return self::getDayOfWeek($year, $month, $day);
}
/**
* Returns day of week (number 0 to 6, 0 - sunday, 6 - saturday).
* Based on the Zeller's algorithm (http://pl.wikipedia.org/wiki/Kalendarz_wieczny).
*
* @param int $year The year value
* @param int $month The month value
* @param int $day The day value
*
* @return int
* @throws IncorrectDatePartException
*/
public static function getDayOfWeek($year, $month, $day)
{
$year = (int)$year;
$month = (int)$month;
$day = (int)$day;
/*
* Oops, incorrect year
*/
if ($year <= 0) {
throw new IncorrectDatePartException($year, DatePartType::YEAR);
}
/*
* Oops, incorrect month
*/
if ($month < 1 || $month > 12) {
throw new IncorrectDatePartException($month, DatePartType::MONTH);
}
/*
* Oops, incorrect day
*/
if ($day < 1 || $day > 31) {
throw new IncorrectDatePartException($day, DatePartType::DAY);
}
if ($month < 3) {
$count = 0;
$yearValue = $year - 1;
} else {
$count = 2;
$yearValue = $year;
}
$firstPart = floor(23 * $month / 9);
$secondPart = floor($yearValue / 4);
$thirdPart = floor($yearValue / 100);
$fourthPart = floor($yearValue / 400);
return ($firstPart + $day + 4 + $year + $secondPart - $thirdPart + $fourthPart - $count) % 7;
}
/**
* Returns based on locale name of current weekday
*
* @return string
*/
public static function getCurrentDayOfWeekName()
{
$now = new DateTime();
$year = $now->format('Y');
$month = $now->format('m');
$day = $now->format('d');
return self::getDayOfWeekName($year, $month, $day);
}
/**
* Returns name of weekday based on locale
*
* @param int $year The year value
* @param int $month The month value
* @param int $day The day value
* @return string
*/
public static function getDayOfWeekName($year, $month, $day)
{
$hour = 0;
$minute = 0;
$second = 0;
$time = mktime($hour, $minute, $second, $month, $day, $year);
$name = strftime('%A', $time);
$encoding = mb_detect_encoding($name);
if ($encoding === false) {
$name = mb_convert_encoding($name, 'UTF-8', 'ISO-8859-2');
}
return $name;
}
/**
* Returns difference between given dates.
*
* The difference is calculated in units based on the 3rd argument or all available unit of date difference
* (defined as DATE_DIFFERENCE_UNIT_* constants of this class).
*
* The difference is also whole / complete value for given unit instead of relative value as may be received by
* DateTime::diff() method, e.g.:
* - 2 days, 50 hours
* instead of
* - 2 days, 2 hours
*
* If the unit of date difference is null, all units are returned in array (units are keys of the array).
* Otherwise - one, integer value is returned.
*
* @param string|DateTime $dateStart The start date
* @param string|DateTime $dateEnd The end date
* @param int $differenceUnit (optional) Unit of date difference. One of this class
* DATE_DIFFERENCE_UNIT_* constants. If is set to null all units are
* returned in the array.
* @return array|int
*/
public static function getDateDifference($dateStart, $dateEnd, $differenceUnit = null)
{
$validDateStart = self::isValidDate($dateStart, true);
$validDateEnd = self::isValidDate($dateEnd, true);
/*
* The start or end date is unknown?
* or
* The start or end date is not valid date?
*
* Nothing to do
*/
if (empty($dateStart) || empty($dateEnd) || !$validDateStart || !$validDateEnd) {
return null;
}
$dateStart = self::getDateTime($dateStart, true);
$dateEnd = self::getDateTime($dateEnd, true);
$difference = [];
$dateDiff = $dateEnd->getTimestamp() - $dateStart->getTimestamp();
$daysInSeconds = 0;
$hoursInSeconds = 0;
$hourSeconds = 60 * 60;
$daySeconds = $hourSeconds * 24;
/*
* These units are related, because while calculating difference in the lowest unit, difference in the
* highest unit is required, e.g. while calculating hours I have to know difference in days
*/
$relatedUnits = [
self::DATE_DIFFERENCE_UNIT_DAYS,
self::DATE_DIFFERENCE_UNIT_HOURS,
self::DATE_DIFFERENCE_UNIT_MINUTES,
];
if ($differenceUnit === null || $differenceUnit == self::DATE_DIFFERENCE_UNIT_YEARS) {
$diff = $dateEnd->diff($dateStart);
/*
* Difference between dates in years should be returned only?
*/
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_YEARS) {
return $diff->y;
}
$difference[self::DATE_DIFFERENCE_UNIT_YEARS] = $diff->y;
}
if ($differenceUnit === null || $differenceUnit == self::DATE_DIFFERENCE_UNIT_MONTHS) {
$diff = $dateEnd->diff($dateStart);
/*
* Difference between dates in months should be returned only?
*/
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_MONTHS) {
return $diff->m;
}
$difference[self::DATE_DIFFERENCE_UNIT_MONTHS] = $diff->m;
}
if ($differenceUnit === null || in_array($differenceUnit, $relatedUnits)) {
$days = (int)floor($dateDiff / $daySeconds);
/*
* Difference between dates in days should be returned only?
*/
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_DAYS) {
return $days;
}
/*
* All units should be returned?
*/
if ($differenceUnit === null) {
$difference[self::DATE_DIFFERENCE_UNIT_DAYS] = $days;
}
/*
* Calculation for later usage
*/
$daysInSeconds = $days * $daySeconds;
}
if ($differenceUnit === null || in_array($differenceUnit, $relatedUnits)) {
$hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds);
/*
* Difference between dates in hours should be returned only?
*/
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_HOURS) {
return $hours;
}
/*
* All units should be returned?
*/
if ($differenceUnit === null) {
$difference[self::DATE_DIFFERENCE_UNIT_HOURS] = $hours;
}
/*
* Calculation for later usage
*/
$hoursInSeconds = $hours * $hourSeconds;
}
if ($differenceUnit === null || $differenceUnit == self::DATE_DIFFERENCE_UNIT_MINUTES) {
$minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60);
/*
* Difference between dates in minutes should be returned only?
*/
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_MINUTES) {
return $minutes;
}
$difference[self::DATE_DIFFERENCE_UNIT_MINUTES] = $minutes;
}
return $difference;
}
/**
* Returns collection / set of dates for given start date and count of dates.
* Start from given date, add next, iterated value to given date interval and returns requested count of dates.
*
* @param DateTime $startDate The start date. Start of the collection / set.
* @param int $datesCount Count of dates in resulting collection / set
* @param string $intervalTemplate (optional) Template used to build date interval. It should contain "%d" as the
* placeholder which is replaced with a number that represents each iteration.
* Default: interval for days.
* @return array
*/
public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD')
{
$dates = [];
/*
* The template used to build date interval have to be string.
* Otherwise cannot run preg_match() function and an error occurs.
*/
if (is_string($intervalTemplate)) {
/*
* Let's verify the interval template. It should contains the "%d" placeholder and something before and
* after it.
*
* Examples:
* - P%dD
* - P%dM
* - P1Y%dMT1H
*/
$intervalPattern = '/^(\w*)\%d(\w*)$/';
$matches = [];
$matchCount = preg_match($intervalPattern, $intervalTemplate, $matches);
if ($matchCount > 0 && (!empty($matches[1]) || !empty($matches[2]))) {
$datesCount = (int)$datesCount;
for ($index = 1; $index <= $datesCount; ++$index) {
$date = clone $startDate;
$dates[$index] = $date->add(new DateInterval(sprintf($intervalTemplate, $index)));
}
}
}
return $dates;
}
/**
* Returns random date based on given start date
*
* @param DateTime $startDate The start date. Start of the random date.
* @param int $start (optional) Start of random partition
* @param int $end (optional) End of random partition
* @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced
* with next, iterated value.
* @return DateTime
*/
public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD')
{
if ($startDate === null) {
$startDate = new DateTime();
}
$start = (int)$start;
$end = (int)$end;
/*
* Incorrect end of random partition?
* Use start as the end of random partition
*/
if ($end < $start) {
$end = $start;
}
$randomDate = clone $startDate;
$randomInterval = new DateInterval(sprintf($intervalTemplate, rand($start, $end)));
return $randomDate->add($randomInterval);
}
/**
* Returns the DateTime object for given value.
* If the DateTime object cannot be created, false is returned.
*
* @param mixed $value The value which maybe is a date
* @param bool $allowCompoundFormats (optional) If is set to true, the compound formats used to create an
* instance of DateTime class are allowed (e.g. "now", "last day of next
* month", "yyyy"). Otherwise - not and every incorrect value is refused.
* @param string $dateFormat (optional) Format of date used to verify if given value is actually a date.
* It should be format matched to the given value, e.g. "Y-m-d H:i" for
* "2015-01-01 10:00" value.
* @return DateTime|bool
*/
public static function getDateTime($value, $allowCompoundFormats = false, $dateFormat = 'Y-m-d')
{
/*
* Empty value?
* Nothing to do :)
*/
if (empty($value)) {
return false;
}
/*
* Instance of DateTime class?
* Nothing to do :)
*/
if ($value instanceof DateTime) {
return $value;
}
try {
try {
/*
* Pass the value to the constructor. Maybe it's one of the allowed relative formats.
* Examples: "now", "last day of next month"
*/
$date = new DateTime($value);
/*
* Instance of the DateTime class was created.
* Let's verify if given value is really proper date.
*/
$dateFromFormat = DateTime::createFromFormat($dateFormat, $value);
if ($dateFromFormat === false) {
/*
* Nothing to do more, because:
* a) instance of the DateTime was created
* and
* b) if createFromFormat() method failed, given value is one of the allowed relative formats
* ("now", "last day of next month")
* and...
*/
if ($allowCompoundFormats) {
/*
* ...and
* c) it's not an integer, e.g. not 10 or 100 or 1000
*/
if (!is_numeric($value)) {
return $date;
}
} else {
$specialFormats = [
'now',
];
/*
* ...and
* c) it's special compound format that contains characters that each may be used by
* DateTime::format() method and it raises problem while trying to verify the value at the end
* of this method:
*
* (new DateTime())->format($value);
*
* So, I have to refuse those special compound formats if they are not explicitly declared as
* compound (2nd argument of this method, set to false by default)
*/
if (in_array($value, $specialFormats)) {
return false;
}
}
} /*
* Verify instance of the DateTime created by constructor and by createFromFormat() method.
* After formatting, these dates should be the same.
*/
else {
if ($dateFromFormat->format($dateFormat) === $value) {
return $date;
}
}
} catch (\Exception $exception) {
if (!$allowCompoundFormats) {
return false;
}
}
/*
* Does the value is a string that may be used to format date?
* Example: "Y-m-d"
*/
$dateString = (new DateTime())->format($value);
if ($dateString != $value) {
return new DateTime($dateString);
}
} catch (\Exception $exception) {
}
return false;
}
/**
* Returns information if given value is valid date
*
* @param mixed $value The value which maybe is a date
* @param bool $allowCompoundFormats (optional) If is set to true, the compound formats used to create an
* instance of DateTime class are allowed (e.g. "now", "last day of next
* month", "yyyy"). Otherwise - not and every incorrect value is refused.
* @return bool
*/
public static function isValidDate($value, $allowCompoundFormats = false)
{
return self::getDateTime($value, $allowCompoundFormats) instanceof DateTime;
}
/**
* Returns information if given format of date is valid
*
* @param string $format The validated format of date
* @return bool
*/
public static function isValidDateFormat($format)
{
if (empty($format) || !is_string($format)) {
return false;
}
/*
* Datetime to string
*/
$formatted = (new DateTime())->format($format);
/*
* Formatted date it's the format who is validated?
* The format is invalid
*/
if ($formatted == $format) {
return false;
}
/*
* Validate the format used to create the datetime
*/
$fromFormat = DateTime::createFromFormat($format, $formatted);
/*
* It's instance of DateTime?
* The format is valid
*/
if ($fromFormat instanceof DateTime) {
return true;
}
return $fromFormat instanceof DateTime;
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use DateTime;
/**
* A date's period.
* Contains start and end date of the period.
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class DatePeriod
{
/**
* The period constant: last month
*
* @var int
*/
const LAST_MONTH = 4;
/**
* The period constant: last week
*
* @var int
*/
const LAST_WEEK = 1;
/**
* The period constant: last year
*
* @var int
*/
const LAST_YEAR = 7;
/**
* The period constant: next month
*
* @var int
*/
const NEXT_MONTH = 6;
/**
* The period constant: next week
*
* @var int
*/
const NEXT_WEEK = 3;
/**
* The period constant: next year
*
* @var int
*/
const NEXT_YEAR = 9;
/**
* The period constant: this month
*
* @var int
*/
const THIS_MONTH = 5;
/**
* The period constant: this week
*
* @var int
*/
const THIS_WEEK = 2;
/**
* The period constant: this year
*
* @var int
*/
const THIS_YEAR = 8;
/**
* The start date of period
*
* @var DateTime
*/
private $startDate;
/**
* The end date of period
*
* @var DateTime
*/
private $endDate;
/**
* Class constructor
*
* @param DateTime $startDate (optional) The start date of period
* @param DateTime $endDate (optional) The end date of period
*/
public function __construct(DateTime $startDate = null, DateTime $endDate = null)
{
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/**
* Returns information if given period is correct
*
* @param int $period The period to verify
* @return bool
*/
public static function isCorrectPeriod($period)
{
return in_array($period, Reflection::getConstants(__CLASS__));
}
/**
* Returns formatted one of the period's date: start date or end date
*
* @param string $format Format used to format the date
* @param bool $startDate (optional) If is set to true, start date is formatted. Otherwise - end date.
* @return string
*/
public function getFormattedDate($format, $startDate = true)
{
$date = $this->getEndDate();
/*
* Start date should be formatted?
*/
if ($startDate) {
$date = $this->getStartDate();
}
/*
* Unknown date or format is invalid?
*/
if ($date === null || !Date::isValidDateFormat($format)) {
return '';
}
return $date->format($format);
}
/**
* Returns the end date of period
*
* @return DateTime
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* Sets the end date of period
*
* @param DateTime $endDate (optional) The end date of period
* @return $this
*/
public function setEndDate(DateTime $endDate = null)
{
$this->endDate = $endDate;
return $this;
}
/**
* Returns the start date of period
*
* @return DateTime
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* Sets the start date of period
*
* @param DateTime $startDate (optional) The start date of period
* @return $this
*/
public function setStartDate(DateTime $startDate = null)
{
$this->startDate = $startDate;
return $this;
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Generator;
/**
* Useful methods for the Generator class (only static functions)
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class GeneratorUtility
{
/**
* Returns elements of generator
*
* @param Generator $generator The generator who elements should be returned
* @return array
*/
public static function getGeneratorElements(Generator $generator)
{
$elements = [];
for (; $generator->valid(); $generator->next()) {
$elements[] = $generator->current();
}
return $elements;
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Useful locale methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Locale
{
/**
* Sets locale for given category using given language and country code
*
* @param int $category Named constant specifying the category of the functions affected by the locale
* setting. It's the same constant as required by setlocale() function.
* @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr".
* @param string $countryCode (optional) Country code, in ISO 3166-1 alpha-2 format, e.g. "FR"
* @return bool
*
* Available categories (values of $category argument):
* - LC_ALL for all of the below
* - LC_COLLATE for string comparison, see strcoll()
* - LC_CTYPE for character classification and conversion, for example strtoupper()
* - LC_MONETARY for localeconv()
* - LC_NUMERIC for decimal separator (See also localeconv())
* - LC_TIME for date and time formatting with strftime()
* - LC_MESSAGES for system responses (available if PHP was compiled with libintl)
*/
public static function setLocale($category, $languageCode, $countryCode = '')
{
$category = (int)$category;
if (is_string($languageCode)) {
$languageCode = trim($languageCode);
}
$availableCategories = [
LC_ALL,
LC_COLLATE,
LC_CTYPE,
LC_MONETARY,
LC_NUMERIC,
LC_TIME,
LC_MESSAGES,
];
if (empty($languageCode) || !in_array($category, $availableCategories)) {
return false;
}
$localeLongForm = self::getLongForm($languageCode, $countryCode);
setlocale($category, $localeLongForm);
return true;
}
/**
* Returns long form of the locale
*
* @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr".
* @param string $countryCode (optional) Country code, in ISO 3166-1 alpha-2 format, e.g. "FR"
* @param string $encoding (optional) Encoding of the final locale
* @return string
*
* Example:
* - language code: fr
* - country code: ''
* - result: fr_FR
*/
public static function getLongForm($languageCode, $countryCode = '', $encoding = 'UTF-8')
{
if (is_string($languageCode)) {
$languageCode = trim($languageCode);
}
/*
* Language code not provided?
* Nothing to do
*/
if (empty($languageCode)) {
return '';
}
/*
* Country code not provided?
* Let's use language code
*/
if (empty($countryCode)) {
$countryCode = $languageCode;
}
if (!empty($encoding)) {
$encoding = sprintf('.%s', $encoding);
}
return sprintf('%s_%s%s', $languageCode, strtoupper($countryCode), $encoding);
}
}

View File

@@ -0,0 +1,816 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Useful methods for mime types of files
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class MimeTypes
{
/**
* Mime types data
*
* @var array
*/
private static $mimeTypes = [
'7z' => 'application/x-7z-compressed',
'ez' => 'application/andrew-inset',
'atom' => 'application/atom+xml',
'atomcat' => 'application/atomcat+xml',
'atomsvc' => 'application/atomsvc+xml',
'ccxml' => 'application/ccxml+xml',
'davmount' => 'application/davmount+xml',
'ecma' => 'application/ecmascript',
'pfr' => 'application/font-tdpfr',
'stk' => 'application/hyperstudio',
'js' => 'application/javascript',
'json' => 'application/json',
'hqx' => 'application/mac-binhex40',
'cpt' => 'application/mac-compactpro',
'mrc' => 'application/marc',
'ma' => 'application/mathematica',
'nb' => 'application/mathematica',
'mb' => 'application/mathematica',
'mathml' => 'application/mathml+xml',
'mbox' => 'application/mbox',
'mscml' => 'application/mediaservercontrol+xml',
'mp4s' => 'application/mp4',
'dot' => 'application/msword',
'doc' => 'application/msword',
/*
* MS Office system file format MIME types
* http://technet.microsoft.com/en-us/library/ee309278%28office.12%29.aspx
*/
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'mxf' => 'application/mxf',
'bin' => 'application/octet-stream',
'dms' => 'application/octet-stream',
'lha' => 'application/octet-stream',
'lzh' => 'application/octet-stream',
'class' => 'application/octet-stream',
'so' => 'application/octet-stream',
'iso' => 'application/octet-stream',
'dmg' => 'application/octet-stream',
'dist' => 'application/octet-stream',
'distz' => 'application/octet-stream',
'pkg' => 'application/octet-stream',
'bpk' => 'application/octet-stream',
'dump' => 'application/octet-stream',
'elc' => 'application/octet-stream',
'scpt' => 'application/octet-stream',
'oda' => 'application/oda',
'ogg' => 'application/ogg',
'pdf' => 'application/pdf',
'pgp' => 'application/pgp-encrypted',
'asc' => 'application/pgp-signature',
'sig' => 'application/pgp-signature',
'prf' => 'application/pics-rules',
'p10' => 'application/pkcs10',
'p7m' => 'application/pkcs7-mime',
'p7c' => 'application/pkcs7-mime',
'p7s' => 'application/pkcs7-signature',
'cer' => 'application/pkix-cert',
'crl' => 'application/pkix-crl',
'pkipath' => 'application/pkix-pkipath',
'pki' => 'application/pkixcmp',
'pls' => 'application/pls+xml',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
'cww' => 'application/prs.cww',
'rdf' => 'application/rdf+xml',
'rif' => 'application/reginfo+xml',
'rnc' => 'application/relax-ng-compact-syntax',
'rl' => 'application/resource-lists+xml',
'rs' => 'application/rls-services+xml',
'rsd' => 'application/rsd+xml',
'rss' => 'application/rss+xml',
'rtf' => 'application/rtf',
'sbml' => 'application/sbml+xml',
'sdp' => 'application/sdp',
'setpay' => 'application/set-payment-initiation',
'setreg' => 'application/set-registration-initiation',
'shf' => 'application/shf+xml',
'smi' => 'application/smil+xml',
'smil' => 'application/smil+xml',
'gram' => 'application/srgs',
'grxml' => 'application/srgs+xml',
'ssml' => 'application/ssml+xml',
'plb' => 'application/vnd.3gpp.pic-bw-large',
'psb' => 'application/vnd.3gpp.pic-bw-small',
'pvb' => 'application/vnd.3gpp.pic-bw-var',
'pwn' => 'application/vnd.3m.post-it-notes',
'aso' => 'application/vnd.accpac.simply.aso',
'imp' => 'application/vnd.accpac.simply.imp',
'acu' => 'application/vnd.acucobol',
'atc' => 'application/vnd.acucorp',
'acutc' => 'application/vnd.acucorp',
'xdp' => 'application/vnd.adobe.xdp+xml',
'xfdf' => 'application/vnd.adobe.xfdf',
'ami' => 'application/vnd.amiga.ami',
'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
'atx' => 'application/vnd.antix.game-component',
'mpkg' => 'application/vnd.apple.installer+xml',
'aep' => 'application/vnd.audiograph',
'mpm' => 'application/vnd.blueice.multipass',
'bmi' => 'application/vnd.bmi',
'rep' => 'application/vnd.businessobjects',
'cdxml' => 'application/vnd.chemdraw+xml',
'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
'cdy' => 'application/vnd.cinderella',
'cla' => 'application/vnd.claymore',
'c4g' => 'application/vnd.clonk.c4group',
'c4d' => 'application/vnd.clonk.c4group',
'c4f' => 'application/vnd.clonk.c4group',
'c4p' => 'application/vnd.clonk.c4group',
'c4u' => 'application/vnd.clonk.c4group',
'csp' => 'application/vnd.commonspace',
'cst' => 'application/vnd.commonspace',
'cdbcmsg' => 'application/vnd.contact.cmsg',
'cmc' => 'application/vnd.cosmocaller',
'clkx' => 'application/vnd.crick.clicker',
'clkk' => 'application/vnd.crick.clicker.keyboard',
'clkp' => 'application/vnd.crick.clicker.palette',
'clkt' => 'application/vnd.crick.clicker.template',
'clkw' => 'application/vnd.crick.clicker.wordbank',
'wbs' => 'application/vnd.criticaltools.wbs+xml',
'pml' => 'application/vnd.ctc-posml',
'ppd' => 'application/vnd.cups-ppd',
'curl' => 'application/vnd.curl',
'rdz' => 'application/vnd.data-vision.rdz',
'dna' => 'application/vnd.dna',
'mlp' => 'application/vnd.dolby.mlp',
'dpg' => 'application/vnd.dpgraph',
'dfac' => 'application/vnd.dreamfactory',
'mag' => 'application/vnd.ecowin.chart',
'nml' => 'application/vnd.enliven',
'esf' => 'application/vnd.epson.esf',
'msf' => 'application/vnd.epson.msf',
'qam' => 'application/vnd.epson.quickanime',
'slt' => 'application/vnd.epson.salt',
'ssf' => 'application/vnd.epson.ssf',
'es3' => 'application/vnd.eszigno3+xml',
'et3' => 'application/vnd.eszigno3+xml',
'ez2' => 'application/vnd.ezpix-album',
'ez3' => 'application/vnd.ezpix-package',
'fdf' => 'application/vnd.fdf',
'gph' => 'application/vnd.flographit',
'ftc' => 'application/vnd.fluxtime.clip',
'fm' => 'application/vnd.framemaker',
'frame' => 'application/vnd.framemaker',
'maker' => 'application/vnd.framemaker',
'fnc' => 'application/vnd.frogans.fnc',
'ltf' => 'application/vnd.frogans.ltf',
'fsc' => 'application/vnd.fsc.weblaunch',
'oas' => 'application/vnd.fujitsu.oasys',
'oa2' => 'application/vnd.fujitsu.oasys2',
'oa3' => 'application/vnd.fujitsu.oasys3',
'fg5' => 'application/vnd.fujitsu.oasysgp',
'bh2' => 'application/vnd.fujitsu.oasysprs',
'ddd' => 'application/vnd.fujixerox.ddd',
'xdw' => 'application/vnd.fujixerox.docuworks',
'xbd' => 'application/vnd.fujixerox.docuworks.binder',
'fzs' => 'application/vnd.fuzzysheet',
'txd' => 'application/vnd.genomatix.tuxedo',
'kml' => 'application/vnd.google-earth.kml+xml',
'kmz' => 'application/vnd.google-earth.kmz',
'gqf' => 'application/vnd.grafeq',
'gqs' => 'application/vnd.grafeq',
'gac' => 'application/vnd.groove-account',
'ghf' => 'application/vnd.groove-help',
'gim' => 'application/vnd.groove-identity-message',
'grv' => 'application/vnd.groove-injector',
'gtm' => 'application/vnd.groove-tool-message',
'tpl' => 'application/vnd.groove-tool-template',
'vcg' => 'application/vnd.groove-vcard',
'zmm' => 'application/vnd.handheld-entertainment+xml',
'hbci' => 'application/vnd.hbci',
'les' => 'application/vnd.hhe.lesson-player',
'hpgl' => 'application/vnd.hp-hpgl',
'hpid' => 'application/vnd.hp-hpid',
'hps' => 'application/vnd.hp-hps',
'jlt' => 'application/vnd.hp-jlyt',
'pcl' => 'application/vnd.hp-pcl',
'pclxl' => 'application/vnd.hp-pclxl',
'x3d' => 'application/vnd.hzn-3d-crossword',
'mpy' => 'application/vnd.ibm.minipay',
'afp' => 'application/vnd.ibm.modcap',
'listafp' => 'application/vnd.ibm.modcap',
'list3820' => 'application/vnd.ibm.modcap',
'irm' => 'application/vnd.ibm.rights-management',
'sc' => 'application/vnd.ibm.secure-container',
'igl' => 'application/vnd.igloader',
'ivp' => 'application/vnd.immervision-ivp',
'ivu' => 'application/vnd.immervision-ivu',
'xpw' => 'application/vnd.intercon.formnet',
'xpx' => 'application/vnd.intercon.formnet',
'qbo' => 'application/vnd.intu.qbo',
'qfx' => 'application/vnd.intu.qfx',
'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
'irp' => 'application/vnd.irepository.package+xml',
'xpr' => 'application/vnd.is-xpr',
'jam' => 'application/vnd.jam',
'rms' => 'application/vnd.jcp.javame.midlet-rms',
'jisp' => 'application/vnd.jisp',
'ktz' => 'application/vnd.kahootz',
'ktr' => 'application/vnd.kahootz',
'karbon' => 'application/vnd.kde.karbon',
'chrt' => 'application/vnd.kde.kchart',
'kfo' => 'application/vnd.kde.kformula',
'flw' => 'application/vnd.kde.kivio',
'kon' => 'application/vnd.kde.kontour',
'kpr' => 'application/vnd.kde.kpresenter',
'kpt' => 'application/vnd.kde.kpresenter',
'ksp' => 'application/vnd.kde.kspread',
'kwd' => 'application/vnd.kde.kword',
'kwt' => 'application/vnd.kde.kword',
'htke' => 'application/vnd.kenameaapp',
'kia' => 'application/vnd.kidspiration',
'kne' => 'application/vnd.kinar',
'knp' => 'application/vnd.kinar',
'skp' => 'application/vnd.koan',
'skd' => 'application/vnd.koan',
'skt' => 'application/vnd.koan',
'skm' => 'application/vnd.koan',
'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
'123' => 'application/vnd.lotus-1-2-3',
'apr' => 'application/vnd.lotus-approach',
'pre' => 'application/vnd.lotus-freelance',
'nsf' => 'application/vnd.lotus-notes',
'org' => 'application/vnd.lotus-organizer',
'scm' => 'application/vnd.lotus-screencam',
'lwp' => 'application/vnd.lotus-wordpro',
'portpkg' => 'application/vnd.macports.portpkg',
'mcd' => 'application/vnd.mcd',
'mc1' => 'application/vnd.medcalcdata',
'cdkey' => 'application/vnd.mediastation.cdkey',
'mwf' => 'application/vnd.mfer',
'mfm' => 'application/vnd.mfmp',
'flo' => 'application/vnd.micrografx.flo',
'igx' => 'application/vnd.micrografx.igx',
'mif' => 'application/vnd.mif',
'daf' => 'application/vnd.mobius.daf',
'dis' => 'application/vnd.mobius.dis',
'mbk' => 'application/vnd.mobius.mbk',
'mqy' => 'application/vnd.mobius.mqy',
'msl' => 'application/vnd.mobius.msl',
'plc' => 'application/vnd.mobius.plc',
'txf' => 'application/vnd.mobius.txf',
'mpn' => 'application/vnd.mophun.application',
'mpc' => 'application/vnd.mophun.certificate',
'xul' => 'application/vnd.mozilla.xul+xml',
'cil' => 'application/vnd.ms-artgalry',
'asf' => 'application/vnd.ms-asf',
'cab' => 'application/vnd.ms-cab-compressed',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlm' => 'application/vnd.ms-excel',
'xla' => 'application/vnd.ms-excel',
'xlc' => 'application/vnd.ms-excel',
'xlt' => 'application/vnd.ms-excel',
'xlw' => 'application/vnd.ms-excel',
'eot' => 'application/vnd.ms-fontobject',
'chm' => 'application/vnd.ms-htmlhelp',
'ims' => 'application/vnd.ms-ims',
'lrm' => 'application/vnd.ms-lrm',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pps' => 'application/vnd.ms-powerpoint',
'pot' => 'application/vnd.ms-powerpoint',
'mpp' => 'application/vnd.ms-project',
'mpt' => 'application/vnd.ms-project',
'wps' => 'application/vnd.ms-works',
'wks' => 'application/vnd.ms-works',
'wcm' => 'application/vnd.ms-works',
'wdb' => 'application/vnd.ms-works',
'wpl' => 'application/vnd.ms-wpl',
'xps' => 'application/vnd.ms-xpsdocument',
'mseq' => 'application/vnd.mseq',
'mus' => 'application/vnd.musician',
'nlu' => 'application/vnd.neurolanguage.nlu',
'nnd' => 'application/vnd.noblenet-directory',
'nns' => 'application/vnd.noblenet-sealer',
'nnw' => 'application/vnd.noblenet-web',
'ngdat' => 'application/vnd.nokia.n-gage.data',
'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
'rpst' => 'application/vnd.nokia.radio-preset',
'rpss' => 'application/vnd.nokia.radio-presets',
'edm' => 'application/vnd.novadigm.edm',
'edx' => 'application/vnd.novadigm.edx',
'ext' => 'application/vnd.novadigm.ext',
'odc' => 'application/vnd.oasis.opendocument.chart',
'otc' => 'application/vnd.oasis.opendocument.chart-template',
'odf' => 'application/vnd.oasis.opendocument.formula',
'otf' => 'application/vnd.oasis.opendocument.formula-template',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
'odi' => 'application/vnd.oasis.opendocument.image',
'oti' => 'application/vnd.oasis.opendocument.image-template',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
'odt' => 'application/vnd.oasis.opendocument.text',
'otm' => 'application/vnd.oasis.opendocument.text-master',
'ott' => 'application/vnd.oasis.opendocument.text-template',
'oth' => 'application/vnd.oasis.opendocument.text-web',
'xo' => 'application/vnd.olpc-sugar',
'dd2' => 'application/vnd.oma.dd2+xml',
'oxt' => 'application/vnd.openofficeorg.extension',
'dp' => 'application/vnd.osgi.dp',
'prc' => 'application/vnd.palm',
'pdb' => 'application/vnd.palm',
'pqa' => 'application/vnd.palm',
'oprc' => 'application/vnd.palm',
'str' => 'application/vnd.pg.format',
'ei6' => 'application/vnd.pg.osasli',
'efif' => 'application/vnd.picsel',
'plf' => 'application/vnd.pocketlearn',
'pbd' => 'application/vnd.powerbuilder6',
'box' => 'application/vnd.previewsystems.box',
'mgz' => 'application/vnd.proteus.magazine',
'qps' => 'application/vnd.publishare-delta-tree',
'ptid' => 'application/vnd.pvi.ptid1',
'qxd' => 'application/vnd.quark.quarkxpress',
'qxt' => 'application/vnd.quark.quarkxpress',
'qwd' => 'application/vnd.quark.quarkxpress',
'qwt' => 'application/vnd.quark.quarkxpress',
'qxl' => 'application/vnd.quark.quarkxpress',
'qxb' => 'application/vnd.quark.quarkxpress',
'mxl' => 'application/vnd.recordare.musicxml',
'rm' => 'application/vnd.rn-realmedia',
'see' => 'application/vnd.seemail',
'sema' => 'application/vnd.sema',
'semd' => 'application/vnd.semd',
'semf' => 'application/vnd.semf',
'ifm' => 'application/vnd.shana.informed.formdata',
'itp' => 'application/vnd.shana.informed.formtemplate',
'iif' => 'application/vnd.shana.informed.interchange',
'ipk' => 'application/vnd.shana.informed.package',
'twd' => 'application/vnd.simtech-mindmapper',
'twds' => 'application/vnd.simtech-mindmapper',
'mmf' => 'application/vnd.smaf',
'sdkm' => 'application/vnd.solent.sdkm+xml',
'sdkd' => 'application/vnd.solent.sdkm+xml',
'dxp' => 'application/vnd.spotfire.dxp',
'sfs' => 'application/vnd.spotfire.sfs',
'sus' => 'application/vnd.sus-calendar',
'susp' => 'application/vnd.sus-calendar',
'svd' => 'application/vnd.svd',
'xsm' => 'application/vnd.syncml+xml',
'bdm' => 'application/vnd.syncml.dm+wbxml',
'xdm' => 'application/vnd.syncml.dm+xml',
'tao' => 'application/vnd.tao.intent-module-archive',
'tmo' => 'application/vnd.tmobile-livetv',
'tpt' => 'application/vnd.trid.tpt',
'mxs' => 'application/vnd.triscape.mxs',
'tra' => 'application/vnd.trueapp',
'ufd' => 'application/vnd.ufdl',
'ufdl' => 'application/vnd.ufdl',
'utz' => 'application/vnd.uiq.theme',
'umj' => 'application/vnd.umajin',
'unityweb' => 'application/vnd.unity',
'uoml' => 'application/vnd.uoml+xml',
'vcx' => 'application/vnd.vcx',
'vsd' => 'application/vnd.visio',
'vst' => 'application/vnd.visio',
'vss' => 'application/vnd.visio',
'vsw' => 'application/vnd.visio',
'vis' => 'application/vnd.visionary',
'vsf' => 'application/vnd.vsf',
'wbxml' => 'application/vnd.wap.wbxml',
'wmlc' => 'application/vnd.wap.wmlc',
'wmlsc' => 'application/vnd.wap.wmlscriptc',
'wtb' => 'application/vnd.webturbo',
'wpd' => 'application/vnd.wordperfect',
'wqd' => 'application/vnd.wqd',
'stf' => 'application/vnd.wt.stf',
'xar' => 'application/vnd.xara',
'xfdl' => 'application/vnd.xfdl',
'hvd' => 'application/vnd.yamaha.hv-dic',
'hvs' => 'application/vnd.yamaha.hv-script',
'hvp' => 'application/vnd.yamaha.hv-voice',
'saf' => 'application/vnd.yamaha.smaf-audio',
'spf' => 'application/vnd.yamaha.smaf-phrase',
'cmp' => 'application/vnd.yellowriver-custom-menu',
'zaz' => 'application/vnd.zzazz.deck+xml',
'vxml' => 'application/voicexml+xml',
'hlp' => 'application/winhlp',
'wsdl' => 'application/wsdl+xml',
'wspolicy' => 'application/wspolicy+xml',
'ace' => 'application/x-ace-compressed',
'bcpio' => 'application/x-bcpio',
'torrent' => 'application/x-bittorrent',
'bz' => 'application/x-bzip',
'bz2' => 'application/x-bzip2',
'boz' => 'application/x-bzip2',
'vcd' => 'application/x-cdlink',
'chat' => 'application/x-chat',
'pgn' => 'application/x-chess-pgn',
'cpio' => 'application/x-cpio',
'csh' => 'application/x-csh',
'dcr' => 'application/x-director',
'dir' => 'application/x-director',
'dxr' => 'application/x-director',
'fgd' => 'application/x-director',
'dvi' => 'application/x-dvi',
'spl' => 'application/x-futuresplash',
'gtar' => 'application/x-gtar',
'hdf' => 'application/x-hdf',
'jnlp' => 'application/x-java-jnlp-file',
'latex' => 'application/x-latex',
'wmd' => 'application/x-ms-wmd',
'wmz' => 'application/x-ms-wmz',
'mdb' => 'application/x-msaccess',
'obd' => 'application/x-msbinder',
'crd' => 'application/x-mscardfile',
'clp' => 'application/x-msclip',
'exe' => 'application/x-msdownload',
'dll' => 'application/x-msdownload',
'com' => 'application/x-msdownload',
'bat' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'mvb' => 'application/x-msmediaview',
'm13' => 'application/x-msmediaview',
'm14' => 'application/x-msmediaview',
'wmf' => 'application/x-msmetafile',
'mny' => 'application/x-msmoney',
'pub' => 'application/x-mspublisher',
'scd' => 'application/x-msschedule',
'trm' => 'application/x-msterminal',
'wri' => 'application/x-mswrite',
'nc' => 'application/x-netcdf',
'cdf' => 'application/x-netcdf',
'p12' => 'application/x-pkcs12',
'pfx' => 'application/x-pkcs12',
'p7b' => 'application/x-pkcs7-certificates',
'spc' => 'application/x-pkcs7-certificates',
'p7r' => 'application/x-pkcs7-certreqresp',
'rar' => 'application/x-rar-compressed',
'sh' => 'application/x-sh',
'shar' => 'application/x-shar',
'swf' => 'application/x-shockwave-flash',
'sit' => 'application/x-stuffit',
'sitx' => 'application/x-stuffitx',
'sv4cpio' => 'application/x-sv4cpio',
'sv4crc' => 'application/x-sv4crc',
'tar' => 'application/x-tar',
'tcl' => 'application/x-tcl',
'tex' => 'application/x-tex',
'texinfo' => 'application/x-texinfo',
'texi' => 'application/x-texinfo',
'ustar' => 'application/x-ustar',
'src' => 'application/x-wais-source',
'der' => 'application/x-x509-ca-cert',
'crt' => 'application/x-x509-ca-cert',
'xenc' => 'application/xenc+xml',
'xhtml' => 'application/xhtml+xml',
'xht' => 'application/xhtml+xml',
'xml' => 'application/xml',
'xsl' => 'application/xml',
'dtd' => 'application/xml-dtd',
'xop' => 'application/xop+xml',
'xslt' => 'application/xslt+xml',
'xspf' => 'application/xspf+xml',
'mxml' => 'application/xv+xml',
'xhvml' => 'application/xv+xml',
'xvml' => 'application/xv+xml',
'xvm' => 'application/xv+xml',
'zip' => 'application/zip',
'au' => 'audio/basic',
'snd' => 'audio/basic',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'kar' => 'audio/midi',
'rmi' => 'audio/midi',
'mp4a' => 'audio/mp4',
'm4a' => 'audio/mp4a-latm',
'm4p' => 'audio/mp4a-latm',
'mpga' => 'audio/mpeg',
'mp2' => 'audio/mpeg',
'mp2a' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'm2a' => 'audio/mpeg',
'm3a' => 'audio/mpeg',
'eol' => 'audio/vnd.digital-winds',
'lvp' => 'audio/vnd.lucent.voice',
'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
'wav' => 'audio/wav',
'aif' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'm3u' => 'audio/x-mpegurl',
'wax' => 'audio/x-ms-wax',
'wma' => 'audio/x-ms-wma',
'ram' => 'audio/x-pn-realaudio',
'ra' => 'audio/x-pn-realaudio',
'rmp' => 'audio/x-pn-realaudio-plugin',
'cdx' => 'chemical/x-cdx',
'cif' => 'chemical/x-cif',
'cmdf' => 'chemical/x-cmdf',
'cml' => 'chemical/x-cml',
'csml' => 'chemical/x-csml',
'xyz' => 'chemical/x-xyz',
'bmp' => 'image/bmp',
'cgm' => 'image/cgm',
'g3' => 'image/g3fax',
'gif' => 'image/gif',
'ief' => 'image/ief',
'jp2' => 'image/jp2',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'jpg' => 'image/jpeg',
'pict' => 'image/pict',
'pic' => 'image/pict',
'pct' => 'image/pict',
'png' => 'image/png',
'btif' => 'image/prs.btif',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'psd' => 'image/vnd.adobe.photoshop',
'djvu' => 'image/vnd.djvu',
'djv' => 'image/vnd.djvu',
'dwg' => 'image/vnd.dwg',
'dxf' => 'image/vnd.dxf',
'fbs' => 'image/vnd.fastbidsheet',
'fpx' => 'image/vnd.fpx',
'fst' => 'image/vnd.fst',
'mmr' => 'image/vnd.fujixerox.edmics-mmr',
'rlc' => 'image/vnd.fujixerox.edmics-rlc',
'ico' => 'image/vnd.microsoft.icon',
'mdi' => 'image/vnd.ms-modi',
'npx' => 'image/vnd.net-fpx',
'wbmp' => 'image/vnd.wap.wbmp',
'xif' => 'image/vnd.xiff',
'ras' => 'image/x-cmu-raster',
'cmx' => 'image/x-cmx',
'pntg' => 'image/x-macpaint',
'pnt' => 'image/x-macpaint',
'mac' => 'image/x-macpaint',
'pcx' => 'image/x-pcx',
'pnm' => 'image/x-portable-anymap',
'pbm' => 'image/x-portable-bitmap',
'pgm' => 'image/x-portable-graymap',
'ppm' => 'image/x-portable-pixmap',
'qtif' => 'image/x-quicktime',
'qti' => 'image/x-quicktime',
'rgb' => 'image/x-rgb',
'xbm' => 'image/x-xbitmap',
'xpm' => 'image/x-xpixmap',
'xwd' => 'image/x-xwindowdump',
'eml' => 'message/rfc822',
'mime' => 'message/rfc822',
'igs' => 'model/iges',
'iges' => 'model/iges',
'msh' => 'model/mesh',
'mesh' => 'model/mesh',
'silo' => 'model/mesh',
'dwf' => 'model/vnd.dwf',
'gdl' => 'model/vnd.gdl',
'gtw' => 'model/vnd.gtw',
'mts' => 'model/vnd.mts',
'vtu' => 'model/vnd.vtu',
'wrl' => 'model/vrml',
'vrml' => 'model/vrml',
'ics' => 'text/calendar',
'ifb' => 'text/calendar',
'css' => 'text/css',
'csv' => 'text/csv',
'html' => 'text/html',
'htm' => 'text/html',
'txt' => 'text/plain',
'text' => 'text/plain',
'conf' => 'text/plain',
'def' => 'text/plain',
'list' => 'text/plain',
'log' => 'text/plain',
'in' => 'text/plain',
'dsc' => 'text/prs.lines.tag',
'rtx' => 'text/richtext',
'sgml' => 'text/sgml',
'sgm' => 'text/sgml',
'tsv' => 'text/tab-separated-values',
't' => 'text/troff',
'tr' => 'text/troff',
'roff' => 'text/troff',
'man' => 'text/troff',
'me' => 'text/troff',
'ms' => 'text/troff',
'uri' => 'text/uri-list',
'uris' => 'text/uri-list',
'urls' => 'text/uri-list',
'fly' => 'text/vnd.fly',
'flx' => 'text/vnd.fmi.flexstor',
'3dml' => 'text/vnd.in3d.3dml',
'spot' => 'text/vnd.in3d.spot',
'jad' => 'text/vnd.sun.j2me.app-descriptor',
'wml' => 'text/vnd.wap.wml',
'wmls' => 'text/vnd.wap.wmlscript',
's' => 'text/x-asm',
'asm' => 'text/x-asm',
'c' => 'text/x-c',
'cc' => 'text/x-c',
'cxx' => 'text/x-c',
'cpp' => 'text/x-c',
'h' => 'text/x-c',
'hh' => 'text/x-c',
'dic' => 'text/x-c',
'f' => 'text/x-fortran',
'for' => 'text/x-fortran',
'f77' => 'text/x-fortran',
'f90' => 'text/x-fortran',
'p' => 'text/x-pascal',
'pas' => 'text/x-pascal',
'java' => 'text/x-java-source',
'etx' => 'text/x-setext',
'uu' => 'text/x-uuencode',
'vcs' => 'text/x-vcalendar',
'vcf' => 'text/x-vcard',
'3gp' => 'video/3gpp',
'3g2' => 'video/3gpp2',
'h261' => 'video/h261',
'h263' => 'video/h263',
'h264' => 'video/h264',
'jpgv' => 'video/jpeg',
'jpm' => 'video/jpm',
'jpgm' => 'video/jpm',
'mj2' => 'video/mj2',
'mjp2' => 'video/mj2',
'mp4' => 'video/mp4',
'mp4v' => 'video/mp4',
'mpg4' => 'video/mp4',
'm4v' => 'video/mp4',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpe' => 'video/mpeg',
'm1v' => 'video/mpeg',
'm2v' => 'video/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
'fvt' => 'video/vnd.fvt',
'mxu' => 'video/vnd.mpegurl',
'm4u' => 'video/vnd.mpegurl',
'viv' => 'video/vnd.vivo',
'dv' => 'video/x-dv',
'dif' => 'video/x-dv',
'fli' => 'video/x-fli',
'asx' => 'video/x-ms-asf',
'wm' => 'video/x-ms-wm',
'wmv' => 'video/x-ms-wmv',
'wmx' => 'video/x-ms-wmx',
'wvx' => 'video/x-ms-wvx',
'avi' => 'video/x-msvideo',
'movie' => 'video/x-sgi-movie',
'ice' => 'x-conference/x-cooltalk',
];
/**
* Returns extensions for given mimes types
*
* @param array $mimesTypes The mimes types, e.g. ['video/mpeg', 'image/jpeg']
* @param bool $asUpperCase (optional) If is set to true, extensions are returned as upper case. Otherwise - lower
* case.
* @return array
*/
public static function getExtensions(array $mimesTypes, $asUpperCase = false)
{
if (empty($mimesTypes)) {
return [];
}
$extensions = [];
foreach ($mimesTypes as $mimeType) {
$extension = self::getExtension($mimeType);
/*
* No extension for given mime type?
* Nothing to do
*/
if (empty($extension)) {
continue;
}
/*
* Extensions should be returned as upper case?
*/
if ($asUpperCase) {
if (is_array($extension)) {
array_walk($extension, function (&$value) {
$value = strtoupper($value);
});
} else {
$extension = strtoupper($extension);
}
}
$extensions[$mimeType] = $extension;
}
return $extensions;
}
/**
* Returns extension for given mime type
*
* @param string $mimeType The mime type, e.g. "video/mpeg"
* @return string|array
*/
public static function getExtension($mimeType)
{
if (is_string($mimeType) && in_array($mimeType, self::$mimeTypes)) {
$data = Arrays::setKeysAsValues(self::$mimeTypes, false);
return $data[$mimeType];
}
return '';
}
/**
* Returns information whether file with the given path is an image
*
* @param string $path Path of the file to check
* @return bool
*/
public static function isImagePath($path)
{
$mimeType = self::getMimeType($path);
return self::isImage($mimeType);
}
/**
* Returns mime type of given file
*
* @param string $filePath Path of the file to check
* @return string
*
* @throws \RuntimeException
*/
public static function getMimeType($filePath)
{
/*
* The file does not exist?
* Nothing to do
*/
if (!is_string($filePath) || !is_readable($filePath)) {
return '';
}
/*
* 1st possibility: the finfo class
*/
if (class_exists('finfo')) {
$finfo = new \finfo();
return $finfo->file($filePath, FILEINFO_MIME_TYPE);
}
/*
* 2nd possibility: the mime_content_type function
*/
if (function_exists('mime_content_type')) {
return mime_content_type($filePath);
}
/*
* Oops, there is no possibility to read the mime type
*/
$template = 'Neither \'finfo\' class nor \'mime_content_type\' function exists. There is no way to read the'
. ' mime type of file \'%s\'.';
$message = sprintf($template, $filePath);
throw new \RuntimeException($message);
}
/**
* Returns information whether the given file type is an image
*
* @param string $mimeType The mime type of file
* @return bool
*/
public static function isImage($mimeType)
{
if (in_array($mimeType, self::$mimeTypes)) {
return (bool)preg_match('|^image/.+$|', $mimeType);
}
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\QueryBuilder;
/**
* Useful methods for query builder (the Doctrine's QueryBuilder class)
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class QueryBuilderUtility
{
/**
* Returns root alias of given query builder.
* If null is returned, alias was not found.
*
* @param QueryBuilder $queryBuilder The query builder to retrieve root alias
* @return null|string
*/
public static function getRootAlias(QueryBuilder $queryBuilder)
{
$aliases = $queryBuilder->getRootAliases();
if (empty($aliases)) {
return null;
}
return Arrays::getFirstElement($aliases);
}
/**
* Returns alias of given property joined in given query builder
* If the join does not exist, null is returned.
* It's also information if given property is already joined in given query builder.
*
* @param QueryBuilder $queryBuilder The query builder to verify
* @param string $property Name of property that maybe is joined
* @return null|string
*/
public static function getJoinedPropertyAlias(QueryBuilder $queryBuilder, $property)
{
$joins = $queryBuilder->getDQLPart('join');
if (empty($joins)) {
return null;
}
$patternTemplate = '/^.+\.%s$/'; // e.g. "SomeThing.PropertyName"
$pattern = sprintf($patternTemplate, $property);
foreach ($joins as $joinExpressions) {
/* @var $expression Join */
foreach ($joinExpressions as $expression) {
$joinedProperty = $expression->getJoin();
if (preg_match($pattern, $joinedProperty)) {
return $expression->getAlias();
}
}
}
return null;
}
/**
* Sets the WHERE criteria in given query builder
*
* @param QueryBuilder $queryBuilder The query builder
* @param array $criteria (optional) The criteria used in WHERE clause. It may simple array with pairs
* key-value or an array of arrays where second element of sub-array is the
* comparison operator. Example below.
* @param string $alias (optional) Alias used in the query
* @return QueryBuilder
*
* Example of the $criteria argument:
* [
* 'created_at' => [
* '2012-11-17 20:00',
* '<'
* ],
* 'title' => [
* '%test%',
* 'like'
* ],
* 'position' => 5,
* ]
*/
public static function setCriteria(QueryBuilder $queryBuilder, array $criteria = [], $alias = '')
{
if (!empty($criteria)) {
if (empty($alias)) {
$alias = self::getRootAlias($queryBuilder);
}
foreach ($criteria as $column => $value) {
$compareOperator = '=';
if (is_array($value) && !empty($value)) {
if (count($value) == 2) {
$compareOperator = $value[1];
}
$value = $value[0];
}
$predicate = sprintf('%s.%s %s :%s', $alias, $column, $compareOperator, $column);
if ($value === null) {
$predicate = $queryBuilder->expr()->isNull(sprintf('%s.%s', $alias, $column));
unset($criteria[$column]);
} else {
$queryBuilder->setParameter($column, $value);
}
$queryBuilder = $queryBuilder->andWhere($predicate);
}
}
return $queryBuilder;
}
/**
* Deletes given entities
*
* @param EntityManager $entityManager The entity manager
* @param array|ArrayCollection $entities The entities to delete
* @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects.
* Otherwise - not.
* @return bool
*/
public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true)
{
/*
* No entities found?
* Nothing to do
*/
if (empty($entities)) {
return false;
}
foreach ($entities as $entity) {
$entityManager->remove($entity);
}
/*
* The deleted objects should be flushed?
*/
if ($flushDeleted) {
$entityManager->flush();
}
return true;
}
/**
* Adds given parameters to given query builder.
* Attention. Existing parameters will be overridden.
*
* @param QueryBuilder $queryBuilder The query builder
* @param array|ArrayCollection $parameters Parameters to add. Collection of instances of
* Doctrine\ORM\Query\Parameter class or an array with key-value pairs.
* @return QueryBuilder
*/
public static function addParameters(QueryBuilder $queryBuilder, $parameters)
{
if (!empty($parameters)) {
foreach ($parameters as $key => $parameter) {
$name = $key;
$value = $parameter;
if ($parameter instanceof Parameter) {
$name = $parameter->getName();
$value = $parameter->getValue();
}
$queryBuilder->setParameter($name, $value);
}
}
return $queryBuilder;
}
}

View File

@@ -0,0 +1,633 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Util\Inflector;
use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException;
use Meritoo\Common\Exception\Reflection\MissingChildClassesException;
use Meritoo\Common\Exception\Reflection\TooManyChildClassesException;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ReflectionObject;
use ReflectionProperty;
/**
* Useful reflection methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Reflection
{
/**
* Returns names of methods for given class / object
*
* @param object|string $class The object or name of object's class
* @param bool $withoutInheritance (optional) If is set to true, only methods for given class are returned.
* Otherwise - all methods, with inherited methods too.
* @return array
*/
public static function getMethods($class, $withoutInheritance = false)
{
$effect = [];
$reflection = new ReflectionClass($class);
$methods = $reflection->getMethods();
if (!empty($methods)) {
$className = self::getClassName($class);
foreach ($methods as $method) {
if ($method instanceof ReflectionMethod) {
if ($withoutInheritance && $className !== $method->class) {
continue;
}
$effect[] = $method->name;
}
}
}
return $effect;
}
/**
* Returns constants of given class / object
*
* @param object|string $class The object or name of object's class
* @return array
*/
public static function getConstants($class)
{
$reflection = new ReflectionClass($class);
return $reflection->getConstants();
}
/**
* Returns maximum constant from all constants of given class / object.
* Values of constants should be integers.
*
* @param object|string $class The object or name of object's class
* @return int|null
*/
public static function getMaxNumberConstant($class)
{
$constants = self::getConstants($class);
if (empty($constants)) {
return null;
}
$maxNumber = 0;
foreach ($constants as $constant) {
if (is_numeric($constant) && $constant > $maxNumber) {
$maxNumber = $constant;
}
}
return $maxNumber;
}
/**
* Returns information if given class / object has given method
*
* @param object|string $class The object or name of object's class
* @param string $method Name of the method to find
* @return bool
*/
public static function hasMethod($class, $method)
{
$reflection = new ReflectionClass($class);
return $reflection->hasMethod($method);
}
/**
* Returns information if given class / object has given property
*
* @param object|string $class The object or name of object's class
* @param string $property Name of the property to find
* @return bool
*/
public static function hasProperty($class, $property)
{
$reflection = new ReflectionClass($class);
return $reflection->hasProperty($property);
}
/**
* Returns information if given class / object has given constant
*
* @param object|string $class The object or name of object's class
* @param string $constant Name of the constant to find
* @return bool
*/
public static function hasConstant($class, $constant)
{
$reflection = new ReflectionClass($class);
return $reflection->hasConstant($constant);
}
/**
* Returns value of given constant
*
* @param object|string $class The object or name of object's class
* @param string $constant Name of the constant that contains a value
* @return mixed
*/
public static function getConstantValue($class, $constant)
{
$reflection = new ReflectionClass($class);
if (self::hasConstant($class, $constant)) {
return $reflection->getConstant($constant);
}
return null;
}
/**
* Returns value of given property.
* Looks for proper getter for the property.
*
* @param mixed $object Object that should contains given property
* @param string $property Name of the property that contains a value. It may be also multiple properties
* dot-separated, e.g. "invoice.user.email".
* @param bool $force (optional) If is set to true, try to retrieve value even if the object doesn't have
* property. Otherwise - not.
* @return mixed
*/
public static function getPropertyValue($object, $property, $force = false)
{
$value = null;
/*
* Property is a dot-separated string?
* Let's find all values of the chain, of the dot-separated properties
*/
if (Regex::contains($property, '.')) {
$exploded = explode('.', $property);
$property = $exploded[0];
$object = self::getPropertyValue($object, $property, $force);
/*
* Value of processed property from the chain is not null?
* Let's dig more and get proper value
*
* Required to avoid bug:
* ReflectionObject::__construct() expects parameter 1 to be object, null given
* (...)
* 4. at ReflectionObject->__construct (null)
* 5. at Reflection ::getPropertyValue (null, 'name', true)
* 6. at ListService->getItemValue (object(Deal), 'project.name', '0')
*
* while using "project.name" as property - $project has $name property ($project exists in the Deal class)
* and the $project equals null
*
* Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* 2016-11-07
*/
if ($object !== null) {
unset($exploded[0]);
$property = implode('.', $exploded);
$value = self::getPropertyValue($object, $property, $force);
}
} else {
$className = self::getClassName($object);
$reflectionProperty = null;
/*
* 1st try:
* Use \ReflectionObject class
*/
try {
$reflectionProperty = new ReflectionProperty($className, $property);
$value = $reflectionProperty->getValue($object);
} catch (ReflectionException $exception) {
/*
* 2nd try:
* Look for the get / has / is methods
*/
$class = new ReflectionObject($object);
$valueFound = false;
if ($class->hasProperty($property) || $force) {
$property = Inflector::classify($property);
$methodPrefixes = [
'get',
'has',
'is',
];
foreach ($methodPrefixes as $prefix) {
$method = sprintf('%s%s', $prefix, $property);
if ($class->hasMethod($method)) {
$value = $object->{$method}();
$valueFound = true;
break;
}
}
}
if (!$valueFound && $reflectionProperty !== null) {
/*
* Oops, we have got exception.
*
* 3rd try:
* Let's try modify accessibility of the property and try again to get value.
*/
$reflectionProperty->setAccessible(true);
$value = $reflectionProperty->getValue($object);
}
}
}
return $value;
}
/**
* Returns values of given property for given objects.
* Looks for proper getter for the property.
*
* @param Collection|object|array $objects The objects that should contain given property. It may be also one
* object.
* @param string $property Name of the property that contains a value
* @param bool $force (optional) If is set to true, try to retrieve value even if the
* object does not have property. Otherwise - not.
* @return array
*/
public static function getPropertyValues($objects, $property, $force = false)
{
if ($objects instanceof Collection) {
$objects = $objects->toArray();
}
$values = [];
$objects = Arrays::makeArray($objects);
foreach ($objects as $entity) {
$value = self::getPropertyValue($entity, $property, $force);
if ($value !== null) {
$values[] = $value;
}
}
return $values;
}
/**
* Returns a class name for given source
*
* @param array|object|string $source An array of objects, namespaces, object or namespace
* @param bool $withoutNamespace (optional) If is set to true, namespace is omitted. Otherwise -
* not, full name of class is returned, with namespace.
* @return string|null
*/
public static function getClassName($source, $withoutNamespace = false)
{
/*
* First argument is not proper source of class?
* Nothing to do
*/
if (empty($source) || (!is_array($source) && !is_object($source) && !is_string($source))) {
return null;
}
$name = '';
/*
* An array of objects was provided?
* Let's use first of them
*/
if (is_array($source)) {
$source = Arrays::getFirstElement($source);
}
/*
* Let's prepare name of class
*/
if (is_object($source)) {
$name = get_class($source);
} elseif (is_string($source) && (class_exists($source) || trait_exists($source))) {
$name = $source;
}
/*
* Name of class is still unknown?
* Nothing to do
*/
if (empty($name)) {
return null;
}
/*
* Namespace is not required?
* Let's return name of class only
*/
if ($withoutNamespace) {
$classOnly = Miscellaneous::getLastElementOfString($name, '\\');
if ($classOnly !== null) {
$name = $classOnly;
}
return $name;
}
return ClassUtils::getRealClass($name);
}
/**
* Returns namespace of class for given source
*
* @param array|object|string $source An array of objects, namespaces, object or namespace
* @return string
*/
public static function getClassNamespace($source)
{
$fullClassName = self::getClassName($source);
if (empty($fullClassName)) {
return '';
}
$className = self::getClassName($source, true);
if ($className == $fullClassName) {
return $className;
}
return Miscellaneous::getStringWithoutLastElement($fullClassName, '\\');
}
/**
* Returns information if given interface is implemented by given class / object
*
* @param array|object|string $source An array of objects, namespaces, object or namespace
* @param string $interface The interface that should be implemented
* @return bool
*/
public static function isInterfaceImplemented($source, $interface)
{
$className = self::getClassName($source);
$interfaces = class_implements($className);
return in_array($interface, $interfaces);
}
/**
* Returns information if given child class is a subclass of given parent class
*
* @param array|object|string $childClass The child class. An array of objects, namespaces, object or namespace.
* @param array|object|string $parentClass The parent class. An array of objects, namespaces, object or namespace.
* @return bool
*/
public static function isChildOfClass($childClass, $parentClass)
{
$childClassName = self::getClassName($childClass);
$parentClassName = self::getClassName($parentClass);
$parents = class_parents($childClassName);
if (is_array($parents)) {
return in_array($parentClassName, $parents);
}
return false;
}
/**
* Returns given object properties
*
* @param array|object|string $source An array of objects, namespaces, object or namespace
* @param int $filter (optional) Filter of properties. Uses ReflectionProperty class constants.
* By default all properties are returned.
* @return array|ReflectionProperty
*/
public static function getProperties($source, $filter = null)
{
$className = self::getClassName($source);
$reflection = new ReflectionClass($className);
if ($filter === null) {
$filter = ReflectionProperty::IS_PRIVATE
+ ReflectionProperty::IS_PROTECTED
+ ReflectionProperty::IS_PUBLIC
+ ReflectionProperty::IS_STATIC;
}
return $reflection->getProperties($filter);
}
/**
* Returns a parent class
*
* @param array|object|string $source An array of objects, namespaces, object or namespace
* @return ReflectionClass
*/
public static function getParentClass($source)
{
$className = self::getClassName($source);
$reflection = new ReflectionClass($className);
return $reflection->getParentClass();
}
/**
* Returns child classes of given class.
* It's an array of namespaces of the child classes or null (if given class has not child classes).
*
* @param array|object|string $class Class who child classes should be returned. An array of objects, strings,
* object or string.
* @return array|null
* @throws CannotResolveClassNameException
*/
public static function getChildClasses($class)
{
$allClasses = get_declared_classes();
/*
* No classes?
* Nothing to do
*/
if (empty($allClasses)) {
return null;
}
$className = self::getClassName($class);
/*
* Oops, cannot resolve class
*/
if ($className === null) {
throw new CannotResolveClassNameException($class);
}
$childClasses = [];
foreach ($allClasses as $oneClass) {
if (self::isChildOfClass($oneClass, $className)) {
/*
* Attention. I have to use ClassUtils::getRealClass() method to avoid problem with the proxy / cache
* classes. Example:
* - My\ExtraBundle\Entity\MyEntity
* - Proxies\__CG__\My\ExtraBundle\Entity\MyEntity
*
* It's actually the same class, so I have to skip it.
*/
$realClass = ClassUtils::getRealClass($oneClass);
if (in_array($realClass, $childClasses)) {
continue;
}
$childClasses[] = $realClass;
}
}
return $childClasses;
}
/**
* Returns namespace of one child class which extends given class.
* Extended class should has only one child class.
*
* @param array|object|string $parentClass Class who child class should be returned. An array of objects,
* namespaces, object or namespace.
* @return mixed
*
* @throws MissingChildClassesException
* @throws TooManyChildClassesException
*/
public static function getOneChildClass($parentClass)
{
$childClasses = self::getChildClasses($parentClass);
/*
* No child classes?
* Oops, the base / parent class hasn't child class
*/
if (empty($childClasses)) {
throw new MissingChildClassesException($parentClass);
}
/*
* More than 1 child class?
* Oops, the base / parent class has too many child classes
*/
if (count($childClasses) > 1) {
throw new TooManyChildClassesException($parentClass, $childClasses);
}
return trim($childClasses[0]);
}
/**
* Returns property, the ReflectionProperty instance, of given object
*
* @param array|object|string $class An array of objects, namespaces, object or namespace
* @param string $property Name of the property
* @param int $filter (optional) Filter of properties. Uses ReflectionProperty class constants.
* By default all properties are allowed / processed.
* @return null|ReflectionProperty
*/
public static function getProperty($class, $property, $filter = null)
{
$className = self::getClassName($class);
$properties = self::getProperties($className, $filter);
if (!empty($properties)) {
/* @var $reflectionProperty ReflectionProperty */
foreach ($properties as $reflectionProperty) {
if ($reflectionProperty->getName() == $property) {
return $reflectionProperty;
}
}
}
return null;
}
/**
* Returns information if given class / object uses / implements given trait
*
* @param array|object|string $class An array of objects, namespaces, object or namespace
* @param array|string $trait An array of strings or string
* @param bool $verifyParents If is set to true, parent classes are verified if they use given
* trait. Otherwise - not.
* @return bool|null
* @throws CannotResolveClassNameException
*/
public static function usesTrait($class, $trait, $verifyParents = false)
{
$className = self::getClassName($class);
$traitName = self::getClassName($trait);
/*
* Oops, cannot resolve class
*/
if (empty($className)) {
throw new CannotResolveClassNameException($class);
}
/*
* Oops, cannot resolve trait
*/
if (empty($traitName)) {
throw new CannotResolveClassNameException($class, false);
}
$reflection = new ReflectionClass($className);
$traitsNames = $reflection->getTraitNames();
$uses = in_array($traitName, $traitsNames);
if (!$uses && $verifyParents) {
$parentClassName = self::getParentClassName($className);
if ($parentClassName !== null) {
return self::usesTrait($parentClassName, $trait, true);
}
}
return $uses;
}
/**
* Returns name of the parent class.
* If given class does not extend another, returns null.
*
* @param array|object|string $class An array of objects, namespaces, object or namespace
* @return string|null
*/
public static function getParentClassName($class)
{
$className = self::getClassName($class);
$reflection = new ReflectionClass($className);
$parentClass = $reflection->getParentClass();
if ($parentClass === null || $parentClass === false) {
return null;
}
return $parentClass->getName();
}
}

View File

@@ -0,0 +1,726 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Meritoo\Common\Exception\IncorrectColorHexLengthException;
use Meritoo\Common\Exception\InvalidColorHexValueException;
/**
* Useful regular expressions methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Regex
{
/**
* Patterns used to validate / verify values
*
* @var array
*/
private static $patterns = [
'email' => '/[\w-]{2,}@[\w-]+\.[\w]{2,}+/',
'phone' => '/^\+?[0-9 ]+$/',
'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/',
'urlProtocol' => '/^([a-z]+:\/\/)',
'urlDomain' => '([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i',
'letterOrDigit' => '/[a-zA-Z0-9]+/',
'htmlEntity' => '/&[a-z0-9]+;/',
'fileName' => '/.+\.\w+$/',
'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/',
'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/',
'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/',
'color' => '/^[a-f0-9]{6}$/i',
];
/**
* Returns information if given e-mail address is valid
*
* @param string $email E-mail address to validate / verify
* @return bool
*
* Examples:
* a) valid e-mails:
* - ni@g-m.pl
* - ni@gm.pl
* - ni@g_m.pl
* b) invalid e-mails:
* - ni@g-m.p
* - n@g-m.pl
*/
public static function isValidEmail($email)
{
$pattern = self::getEmailPattern();
return (bool)preg_match($pattern, $email);
}
/**
* Returns information if given tax ID (in polish: NIP) is valid
*
* @param string $taxidString Tax ID (NIP) string
* @return bool
*/
public static function isValidTaxid($taxidString)
{
if (!empty($taxidString)) {
$weights = [
6,
5,
7,
2,
3,
4,
5,
6,
7,
];
$taxid = preg_replace('/[\s-]/', '', $taxidString);
$sum = 0;
if (strlen($taxid) == 10 && is_numeric($taxid)) {
for ($x = 0; $x <= 8; ++$x) {
$sum += $taxid[$x] * $weights[$x];
}
if ((($sum % 11) % 10) == $taxid[9]) {
return true;
}
}
}
return false;
}
/**
* Returns information if given url address is valid
*
* @param string $url The url to validate / verify
* @param bool $requireProtocol (optional) If is set to true, the protocol is required to be passed in the url.
* Otherwise - not.
* @return bool
*/
public static function isValidUrl($url, $requireProtocol = false)
{
$pattern = self::getUrlPattern($requireProtocol);
return (bool)preg_match($pattern, $url);
}
/**
* Returns information if given phone number is valid
*
* @param string $phoneNumber The phone number to validate / verify
* @return bool
*/
public static function isValidPhoneNumber($phoneNumber)
{
$pattern = self::getPhoneNumberPattern();
return (bool)preg_match($pattern, $phoneNumber);
}
/**
* Returns array values that matches given pattern (or values that keys matches)
*
* @param string $pattern Pattern to match
* @param array $dataArray The array
* @param bool $itsKeyPattern (optional) If is set to true, keys are checks if they match pattern. Otherwise -
* values are checks.
* @return array
*/
public static function getArrayValuesByPattern($pattern, $dataArray, $itsKeyPattern = false)
{
if ($itsKeyPattern) {
$effect = [];
if (!empty($dataArray)) {
$matches = [];
foreach ($dataArray as $key => $value) {
if (preg_match($pattern, $key, $matches)) {
$effect[$key] = $value;
}
}
}
return $effect;
}
return preg_grep($pattern, $dataArray);
}
/**
* Filters array by given expression and column
*
* Expression can be simple compare expression, like ' == 2', or regular expression.
* Returns filtered array.
*
* @param array $array The array that should be filtered
* @param string $arrayColumnKey Column name
* @param string $filterExpression Filter expression, e.g. '== 2' or '!= \'home\''
* @param bool $itsRegularExpression (optional) If is set to true, means that filter expression is a
* regular expression
* @return array
*/
public static function arrayFilter($array, $arrayColumnKey, $filterExpression, $itsRegularExpression = false)
{
$effect = [];
if (!empty($array)) {
$effect = $array;
foreach ($effect as $key => &$item) {
if (isset($item[$arrayColumnKey])) {
$value = $item[$arrayColumnKey];
if ($itsRegularExpression) {
$matches = [];
$pattern = '|' . $filterExpression . '|';
$matchesCount = preg_match($pattern, $value, $matches);
$remove = $matchesCount == 0;
} else {
if ($value == '') {
$value = '\'\'';
} elseif (is_string($value)) {
$value = '\'' . $value . '\'';
}
eval('$isTrue = ' . $value . $filterExpression . ';');
/* @var bool $isTrue */
$remove = !$isTrue;
}
if ($remove) {
unset($effect[$key]);
}
}
}
}
return $effect;
}
/**
* Perform regular expression match with many given patterns.
* Returns information if given $subject matches one or all given $patterns.
*
* @param array|string $patterns The patterns to match
* @param string $subject The string to check
* @param bool $mustAllMatch (optional) If is set to true, $subject must match all $patterns. Otherwise -
* not.
* @return bool
*/
public static function pregMultiMatch($patterns, $subject, $mustAllMatch = false)
{
$effect = false;
$patterns = Arrays::makeArray($patterns);
if (!empty($patterns)) {
if ($mustAllMatch) {
$effect = true;
}
foreach ($patterns as $pattern) {
$matches = [];
$matched = (bool)preg_match_all($pattern, $subject, $matches);
if ($mustAllMatch) {
$effect = $effect && $matched;
} else {
if ($matched) {
$effect = $matched;
break;
}
}
}
}
return $effect;
}
/**
* Returns string in human readable style generated from given camel case string / text
*
* @param string $string The string / text to convert
* @param bool $applyUpperCaseFirst (optional) If is set to true, first word / element from the converted
* string is uppercased. Otherwise - not.
* @return string
*/
public static function camelCase2humanReadable($string, $applyUpperCaseFirst = false)
{
$parts = self::getCamelCaseParts($string);
if (!empty($parts)) {
$elements = [];
foreach ($parts as $part) {
$elements[] = strtolower($part);
}
$string = implode(' ', $elements);
if ($applyUpperCaseFirst) {
$string = ucfirst($string);
}
}
return $string;
}
/**
* Returns parts of given camel case string / text
*
* @param string $string The string / text to retrieve parts
* @return array
*/
public static function getCamelCaseParts($string)
{
$pattern = self::getCamelCasePartPattern();
$matches = [];
preg_match_all($pattern, $string, $matches);
return $matches[0];
}
/**
* Returns simple, lowercase string generated from given camel case string / text
*
* @param string $string The string / text to convert
* @param string $separator (optional) Separator used to concatenate parts of the string, e.g. '-' or '_'
* @param bool $applyLowercase (optional) If is set to true, returned string will be lowercased. Otherwise - not.
* @return string
*/
public static function camelCase2simpleLowercase($string, $separator = '', $applyLowercase = true)
{
$parts = self::getCamelCaseParts($string);
if (!empty($parts)) {
$string = implode($separator, $parts);
if ($applyLowercase) {
$string = strtolower($string);
}
}
return $string;
}
/**
* Returns pattern used to validate / verify or get e-mail address
*
* @return string
*/
public static function getEmailPattern()
{
return self::$patterns['email'];
}
/**
* Returns pattern used to validate / verify or get phone number
*
* @return string
*/
public static function getPhoneNumberPattern()
{
return self::$patterns['phone'];
}
/**
* Returns pattern used to validate / verify or get camel case parts of string
*
* @return string
*/
public static function getCamelCasePartPattern()
{
return self::$patterns['camelCasePart'];
}
/**
* Returns pattern used to validate / verify or get url address
*
* @param bool $requireProtocol (optional) If is set to true, the protocol is required to be passed in the url.
* Otherwise - not.
* @return string
*/
public static function getUrlPattern($requireProtocol = false)
{
$urlProtocol = self::$patterns['urlProtocol'];
$urlDomain = self::$patterns['urlDomain'];
$protocolPatternPart = '?';
if ($requireProtocol) {
$protocolPatternPart = '';
}
return sprintf('%s%s%s', $urlProtocol, $protocolPatternPart, $urlDomain);
}
/**
* Returns information if given path is sub-path of another path, e.g. path file is owned by path of directory
*
* @param string $subPath Path to verify, probably sub-path
* @param string $path Main / parent path
* @return bool
*/
public static function isSubPathOf($subPath, $path)
{
/*
* Empty path?
* Nothing to do
*/
if (empty($path) || empty($subPath)) {
return false;
}
/*
* I have to escape all slashes (directory separators): "/" -> "\/"
*/
$prepared = preg_quote($path, '/');
/*
* Slash at the ending is optional
*/
if (self::endsWith($path, '/')) {
$prepared .= '?';
}
$pattern = sprintf('/^%s.*/', $prepared);
return (bool)preg_match($pattern, $subPath);
}
/**
* Returns pattern used to validate / verify letter or digit
*
* @return string
*/
public static function getLetterOrDigitPattern()
{
return self::$patterns['letterOrDigit'];
}
/**
* Returns information if given character is a letter or digit
*
* @param string $char Character to check
* @return bool
*/
public static function isLetterOrDigit($char)
{
$pattern = self::getLetterOrDigitPattern();
return is_scalar($char) && (bool)preg_match($pattern, $char);
}
/**
* Returns information if the string starts with given beginning / characters
*
* @param string $string String to check
* @param string $beginning The beginning of string, one or more characters
* @return bool
*/
public static function startsWith($string, $beginning)
{
if (!empty($string) && !empty($beginning)) {
if (strlen($beginning) == 1 && !self::isLetterOrDigit($beginning)) {
$beginning = '\\' . $beginning;
}
$pattern = sprintf('|^%s|', $beginning);
return (bool)preg_match($pattern, $string);
}
return false;
}
/**
* Returns information if the string ends with given ending / characters
*
* @param string $string String to check
* @param string $ending The ending of string, one or more characters
* @return bool
*/
public static function endsWith($string, $ending)
{
if (strlen($ending) == 1 && !self::isLetterOrDigit($ending)) {
$ending = '\\' . $ending;
}
return (bool)preg_match('|' . $ending . '$|', $string);
}
/**
* Returns information if the string starts with directory's separator
*
* @param string $string String that may contain a directory's separator at the start / beginning
* @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's
* separator is used.
* @return bool
*/
public static function startsWithDirectorySeparator($string, $separator = '')
{
if (empty($separator)) {
$separator = DIRECTORY_SEPARATOR;
}
return self::startsWith($string, $separator);
}
/**
* Returns information if the string ends with directory's separator
*
* @param string $text String that may contain a directory's separator at the end
* @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's
* separator is used.
* @return string
*/
public static function endsWithDirectorySeparator($text, $separator = '')
{
if (empty($separator)) {
$separator = DIRECTORY_SEPARATOR;
}
return self::endsWith($text, $separator);
}
/**
* Returns information if uri contains parameter
*
* @param string $uri Uri string (e.g. $_SERVER['REQUEST_URI'])
* @param string $parameterName Uri parameter name
* @return bool
*/
public static function isSetUriParameter($uri, $parameterName)
{
return (bool)preg_match('|[?&]{1}' . $parameterName . '=|', $uri); // e.g. ?name=phil&type=4 -> '$type='
}
/**
* Returns pattern used to validate / verify html entity
*
* @return string
*/
public static function getHtmlEntityPattern()
{
return self::$patterns['htmlEntity'];
}
/**
* Returns information if the string contains html entities
*
* @param string $string String to check
* @return bool
*/
public static function containsEntities($string)
{
$pattern = self::getHtmlEntityPattern();
return (bool)preg_match_all($pattern, $string);
}
/**
* Returns information if one string contains another string
*
* @param string $haystack The string to search in
* @param string $needle The string to be search for
* @return bool
*/
public static function contains($haystack, $needle)
{
if (strlen($needle) == 1 && !self::isLetterOrDigit($needle)) {
$needle = '\\' . $needle;
}
return (bool)preg_match('|.*' . $needle . '.*|', $haystack);
}
/**
* Returns pattern used to validate / verify name of file
*
* @return string
*/
public static function getFileNamePattern()
{
return self::$patterns['fileName'];
}
/**
* Returns information if given name of file is a really name of file.
* Verifies if given name contains a dot and an extension, e.g. "My File 001.jpg".
*
* @param string $fileName Name of file to check. It may be path of file also.
* @return bool
*/
public static function isFileName($fileName)
{
$pattern = self::getFileNamePattern();
return (bool)preg_match($pattern, $fileName);
}
/**
* Returns pattern used to validate / verify if value is quoted (by apostrophes or quotation marks)
*
* @return string
*/
public static function getIsQuotedPattern()
{
return self::$patterns['isQuoted'];
}
/**
* Returns information if given value is quoted (by apostrophes or quotation marks)
*
* @param mixed $value The value to check
* @return bool
*/
public static function isQuoted($value)
{
$pattern = self::getIsQuotedPattern();
return is_scalar($value) && (bool)preg_match($pattern, $value);
}
/**
* Returns pattern used to validate / verify if given path is a Windows-based path, e.g. "C:\path\to\file.jpg"
*
* @return string
*/
public static function getWindowsBasedPathPattern()
{
return self::$patterns['windowsBasedPath'];
}
/**
* Returns information if given path is a Windows-based path, e.g. "C:\path\to\file.jpg"
*
* @param string $path The path to verify
* @return bool
*/
public static function isWindowsBasedPath($path)
{
$pattern = self::getWindowsBasedPathPattern();
return (bool)preg_match($pattern, $path);
}
/**
* Returns information if given NIP number is valid
*
* @param string $nip A given NIP number
* @return bool
*
* @see https://pl.wikipedia.org/wiki/NIP#Znaczenie_numeru
*/
public static function isValidNip($nip)
{
$nip = preg_replace('/[^0-9]/', '', $nip);
$invalidNips = [
'1234567890',
'0000000000',
];
if (!preg_match('/^[0-9]{10}$/', $nip) || in_array($nip, $invalidNips)) {
return false;
}
$sum = 0;
$weights = [
6,
5,
7,
2,
3,
4,
5,
6,
7,
];
for ($i = 0; $i < 9; ++$i) {
$sum += $weights[$i] * $nip[$i];
}
$modulo = $sum % 11;
$numberControl = ($modulo == 10) ? 0 : $modulo;
return $numberControl == $nip[9];
}
/**
* Returns pattern used to validate / verify if given value is money-related value
*
* @return string
*/
public static function getMoneyPattern()
{
return self::$patterns['money'];
}
/**
* Returns information if given value is valid money-related value
*
* @param mixed $value Value to verify
* @return bool
*/
public static function isValidMoneyValue($value)
{
$pattern = self::getMoneyPattern();
return (bool)preg_match($pattern, $value);
}
/**
* Returns valid given hexadecimal value of color.
* If the value is invalid, throws an exception or returns false.
*
* @param string $color Color to verify
* @param bool $throwException (optional) If is set to true, throws an exception if given color is invalid
* (default behaviour). Otherwise - not.
* @return string|bool
*
* @throws IncorrectColorHexLengthException
* @throws InvalidColorHexValueException
*/
public static function getValidColorHexValue($color, $throwException = true)
{
$color = Miscellaneous::replace($color, '/#/', '');
$length = strlen($color);
if ($length === 3) {
$color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3');
} else {
if ($length !== 6) {
if ($throwException) {
throw new IncorrectColorHexLengthException($color);
}
return false;
}
}
$pattern = self::$patterns['color'];
$match = (bool)preg_match($pattern, $color);
if (!$match) {
if ($throwException) {
throw new InvalidColorHexValueException($color);
}
return false;
}
return strtolower($color);
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
/**
* Useful methods for repository
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Repository
{
/**
* Replenishes positions of given items
*
* @param array $items The items
* @param bool $asLast (optional) If is set to true, items are placed at the end. Otherwise - at the top.
* @param bool $force (optional) If is set to true, positions are set even there is no extreme position.
* Otherwise - if extreme position is not found (is null) replenishment is stopped / skipped.
*/
public static function replenishPositions($items, $asLast = true, $force = false)
{
$position = self::getExtremePosition($items, $asLast);
if ($position === null && $force) {
$position = 0;
}
if ($position !== null && !empty($items)) {
foreach ($items as $item) {
if (method_exists($item, 'getPosition')) {
if ($item->getPosition() === null) {
if ($asLast) {
++$position;
} else {
--$position;
}
if (method_exists($item, 'setPosition')) {
$item->setPosition($position);
}
}
}
}
}
}
/**
* Returns extreme position (max or min) of given items
*
* @param array $items The items
* @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum.
* @return int
*/
public static function getExtremePosition($items, $max = true)
{
$extreme = null;
if (!empty($items)) {
foreach ($items as $item) {
if (Reflection::hasMethod($item, 'getPosition')) {
$position = $item->getPosition();
if ($max) {
if ($position > $extreme) {
$extreme = $position;
}
} else {
if ($position < $extreme) {
$extreme = $position;
}
}
}
}
}
return $extreme;
}
/**
* Returns query builder for given entity's repository.
* The entity should contain given property, e.g. "name".
*
* @param EntityRepository $repository Repository of the entity
* @param string $property (optional) Name of property used by the ORDER BY clause
* @param string $direction (optional) Direction used by the ORDER BY clause ("ASC" or "DESC")
* @return QueryBuilder
*/
public static function getEntityOrderedQueryBuilder(
EntityRepository $repository,
$property = 'name',
$direction = 'ASC'
) {
$alias = 'qb';
return $repository
->createQueryBuilder($alias)
->orderBy(sprintf('%s.%s', $alias, $property), $direction);
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace Meritoo\Common\Utilities;
use DateTime;
use Generator;
/**
* Test case with common methods and data providers
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* Provides an empty value
*
* @return Generator
*/
public function provideEmptyValue()
{
yield[''];
yield[' '];
yield[null];
yield[0];
yield[false];
yield[[]];
}
/**
* Provides boolean value
*
* @return Generator
*/
public function provideBooleanValue()
{
yield[false];
yield[true];
}
/**
* Provides instance of DateTime class
*
* @return Generator
*/
public function provideDateTimeInstance()
{
yield[new DateTime()];
yield[new DateTime('yesterday')];
yield[new DateTime('now')];
yield[new DateTime('tomorrow')];
}
/**
* Provides relative / compound format of DateTime
*
* @return Generator
*/
public function provideDateTimeRelativeFormat()
{
yield['now'];
yield['yesterday'];
yield['tomorrow'];
yield['back of 10'];
yield['front of 10'];
yield['last day of February'];
yield['first day of next month'];
yield['last day of previous month'];
yield['last day of next month'];
yield['Y-m-d'];
yield['Y-m-d 10:00'];
}
/**
* Provides path of not existing file, e.g. "lorem/ipsum.jpg"
*
* @return Generator
*/
public function provideNotExistingFilePath()
{
yield['lets-test.doc'];
yield['lorem/ipsum.jpg'];
yield['suprise/me/one/more/time.txt'];
}
/**
* Returns path of file used by tests.
* It should be placed in /data/tests directory of this project.
*
* @param string $fileName Name of file
* @param string $directoryPath (optional) Path of directory containing the file
* @return string
*/
public function getFilePathToTests($fileName, $directoryPath = '')
{
if (!empty($directoryPath)) {
$directoryPath = '/' . $directoryPath;
}
return sprintf('%s/../../../../data/tests/%s%s', __DIR__, $fileName, $directoryPath);
}
}

View File

@@ -0,0 +1,310 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Useful uri methods (only static functions)
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Uri
{
/**
* Returns full uri string
*
* @param bool $withoutHost (optional) If is set to true, means that host / server name is omitted
* @return string
*/
public static function getFullUri($withoutHost = false)
{
$effect = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'REQUEST_URI');
if ($withoutHost) {
return $effect;
}
return self::getServerNameOrIp(true) . $effect;
}
/**
* Returns server name or IP address
*
* @param bool $withProtocol (optional) If is set to true, protocol name is included. Otherwise isn't.
* @return string
*/
public static function getServerNameOrIp($withProtocol = false)
{
$protocol = '';
if ($withProtocol) {
$protocol .= self::getProtocolName() . '://';
}
return $protocol . Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_HOST');
}
/**
* Returns protocol name
*
* @return string
*/
public static function getProtocolName()
{
$effect = '';
$matches = [];
$protocolData = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'SERVER_PROTOCOL'); // e.g. HTTP/1.1
$matchCount = preg_match('|(.+)\/(.+)|', $protocolData, $matches);
/*
* $matches[1] - protocol name, e.g. HTTP
* $matches[2] - protocol version, e.g. 1.1
*/
if ($matchCount > 0) {
$effect = strtolower($matches[1]);
}
return $effect;
}
/**
* Returns http referer uri
*
* @return string
*/
public static function getRefererUri()
{
$effect = '';
if (filter_has_var(INPUT_SERVER, 'HTTP_REFERER')) {
$effect = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_REFERER');
}
return $effect;
}
/**
* Returns user's IP address
*
* @return string
*/
public static function getUserAddressIp()
{
return Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'REMOTE_ADDR');
}
/**
* Returns name and version of user's web browser
*
* @param bool $withVersion (optional) If is set to true, version of the browser is returned too. Otherwise -
* name only.
* @return string
*/
public static function getUserWebBrowserName($withVersion = false)
{
$info = self::getUserWebBrowserInfo();
$knownBrowsers = [
'Firefox/([\d\.]+)$' => 'Mozilla Firefox',
'OPR/([\d\.]+)$' => 'Opera',
'Chrome/([\d\.]+)$' => 'Google Chrome',
'Safari/([\d\.]+)$' => 'Apple Safari',
];
foreach ($knownBrowsers as $pattern => $browserName) {
$matches = [];
$matchCount = preg_match(sprintf('|%s|', $pattern), $info, $matches);
if ($matchCount > 0) {
if ($withVersion) {
$version = $matches[1];
return sprintf('%s %s', $browserName, $version);
}
return $browserName;
}
}
return '';
}
/**
* Returns user's web browser information
*
* @return string
*
* Examples:
* - Mozilla Firefox:
* 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:34.0) Gecko/20100101 Firefox/34.0'
*
* - Google Chrome:
* 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95
* Safari/537.36'
*
* - Opera:
* 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65
* Safari/537.36 OPR/26.0.1656.24'
*
* - Apple Safari:
* 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2
* Safari/600.2.5'
*/
public static function getUserWebBrowserInfo()
{
return Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_USER_AGENT');
}
/**
* Returns name of user's operating system
*
* @return string
*/
public static function getUserOperatingSystemName()
{
$info = self::getUserWebBrowserInfo();
$knownSystems = [
'Linux' => 'Linux',
'Win' => 'Windows',
'Mac' => 'Mac OS',
];
foreach ($knownSystems as $pattern => $systemName) {
$matches = [];
$matchCount = preg_match(sprintf('|%s|', $pattern), $info, $matches);
if ($matchCount > 0) {
return $systemName;
}
}
return '';
}
/**
* Returns information if running server is localhost
*
* @return bool
*/
public static function isServerLocalhost()
{
$serverNameOrIp = strtolower(self::getServerNameOrIp());
return in_array($serverNameOrIp, [
'localhost',
'127.0.0.1',
'127.0.1.1',
]);
}
/**
* Returns information if given url is external, from another server / domain
*
* @param string $url The url to check
* @return bool
*/
public static function isExternalUrl($url)
{
$currentUrl = self::getServerNameOrIp(true);
$url = self::replenishProtocol($url);
return !Regex::contains($currentUrl, $url);
}
/**
* Replenishes protocol in the given url
*
* @param string $url The url to check and replenish
* @param string $protocol (optional) The protocol which is replenished. If is empty, protocol of current request
* is used.
* @return string
*/
public static function replenishProtocol($url, $protocol = '')
{
/*
* Let's trim the url
*/
if (is_string($url)) {
$url = trim($url);
}
/*
* Url is not provided?
* Nothing to do
*/
if (empty($url)) {
return '';
}
/*
* It's a valid url?
* Let's return it
*/
if (Regex::isValidUrl($url, true)) {
return $url;
}
/*
* Protocol is not provided?
*/
if (empty($protocol)) {
$protocol = self::getProtocolName();
}
return sprintf('%s://%s', $protocol, $url);
}
/**
* Returns url to resource secured by given htpasswd login and password
*
* @param string $url A path / url to some resource, e.g. page, image, css file
* @param string $user (optional) User name used to log in
* @param string $password (optional) User password used to log in
* @return string
*/
public static function getSecuredUrl($url, $user = '', $password = '')
{
$protocol = self::getProtocolName();
$host = self::getServerNameOrIp();
if (!Regex::startsWith($url, '/')) {
$url = sprintf('/%s', $url);
}
$url = $host . $url;
if (!empty($user) && !empty($password)) {
$url = sprintf('%s:%s@%s', $user, $password, $url);
}
return sprintf('%s://%s', $protocol, $url);
}
/**
* Adds protocol to given url, if the url does not contain given protocol.
* Returns the new url.
*
* @param string $url Url string
* @param string $protocol (optional) Protocol string
* @return string
*/
public static function addProtocolToUrl($url, $protocol = 'http')
{
$pattern = sprintf('/^%s.*/', $protocol);
if ((bool)preg_match($pattern, $url)) {
return $url;
}
return sprintf('%s://%s', $protocol, $url);
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use DOMDocument;
use DOMXPath;
use SimpleXMLElement;
/**
* Useful XML-related methods (only static functions)
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Xml
{
/**
* Merges nodes of given elements.
* Returns merged instance of SimpleXMLElement.
*
* @param SimpleXMLElement $element1 First element to merge
* @param SimpleXMLElement $element2 Second element to merge
* @return SimpleXMLElement
*/
public static function mergeNodes(SimpleXMLElement $element1, SimpleXMLElement $element2)
{
$document1 = new DOMDocument();
$document2 = new DOMDocument();
$document1->loadXML($element1->asXML());
$document2->loadXML($element2->asXML());
$path = new DOMXPath($document2);
$query = $path->query('/*/*');
$nodesCount = $query->length;
if ($nodesCount == 0) {
return $element1;
}
for ($i = 0; $i < $nodesCount; ++$i) {
$node = $document1->importNode($query->item($i), true);
$document1->documentElement->appendChild($node);
}
return simplexml_import_dom($document1);
}
}