CHANGELOG.md 0000666 00000012657 13605043255 0006377 0 ustar 00 # Changelog
All notable changes to this project will be documented in this file, in reverse chronological order by release.
## 2.7.3 - 2015-09-24
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [zendframework/zend-stdlib#27](https://github.com/zendframework/zend-stdlib/pull/27) fixes a race
condition in the `FastPriorityQueue::remove()` logic that occurs when removing
items iteratively from the same priority of a queue.
## 2.7.2 - 2015-09-23
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [zendframework/zend-stdlib#26](https://github.com/zendframework/zend-stdlib/pull/26) fixes a subtle
inheritance issue with deprecation in the hydrators, and updates the
`HydratorInterface` to also extend the laminas-hydrator `HydratorInterface` to
ensure LSP is preserved.
## 2.7.1 - 2015-09-22
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [zendframework/zend-stdlib#24](https://github.com/zendframework/zend-stdlib/pull/24) fixes an import in
`FastPriorityQueue` to alias `SplPriorityQueue` in order to disambiguate with
the local override present in the component.
## 2.7.0 - 2015-09-22
### Added
- [zendframework/zend-stdlib#19](https://github.com/zendframework/zend-stdlib/pull/19) adds a new
`FastPriorityQueue` implementation. It follows the same signature as
`SplPriorityQueue`, but uses a performance-optimized algorithm:
- inserts are 2x faster than `SplPriorityQueue` and 3x faster than the
`Laminas\Stdlib\PriorityQueue` implementation.
- extracts are 4x faster than `SplPriorityQueue` and 4-5x faster than the
`Laminas\Stdlib\PriorityQueue` implementation.
The intention is to use this as a drop-in replacement in the
`laminas-eventmanager` component to provide performance benefits.
### Deprecated
- [zendframework/zend-stdlib#20](https://github.com/zendframework/zend-stdlib/pull/20) deprecates *all
hydrator* classes, in favor of the new [laminas-hydrator](https://github.com/laminas/laminas-hydrator)
component. All classes were updated to extend their laminas-hydrator equivalents,
and marked as `@deprecated`, indicating the equivalent class from the other
repository.
Users *should* immediately start changing their code to use the laminas-hydrator
equivalents; in most cases, this can be as easy as removing the `Stdlib`
namespace from import statements or hydrator configuration. Hydrators will be
removed entirely from laminas-stdlib in v3.0, and all future updates to hydrators
will occur in the laminas-hydrator library.
Changes with backwards compatibility implications:
- Users implementing `Laminas\Stdlib\Hydrator\HydratorAwareInterface` will need to
update their `setHydrator()` implementation to typehint on
`Laminas\Hydrator\HydratorInterface`. This can be done by changing the import
statement for that interface as follows:
```php
// Replace this:
use Laminas\Stdlib\Hydrator\HydratorInterface;
// with this:
use Laminas\Hydrator\HydratorInterface;
```
If you are not using imports, change the typehint within the signature itself:
```php
// Replace this:
public function setHydrator(\Laminas\Stdlib\Hydrator\HydratorInterface $hydrator)
// with this:
public function setHydrator(\Laminas\Hydrator\HydratorInterface $hydrator)
```
If you are using `Laminas\Stdlib\Hydrator\HydratorAwareTrait`, no changes are
necessary, unless you override that method.
- If you were catching hydrator-generated exceptions, these were previously in
the `Laminas\Stdlib\Exception` namespace. You will need to update your code to
catch exceptions in the `Laminas\Hydrator\Exception` namespace.
- Users who *do* migrate to laminas-hydrator may end up in a situation where
their code will not work with existing libraries that are still type-hinting
on the laminas-stdlib interfaces. We will be attempting to address that ASAP,
but the deprecation within laminas-stdlib is necessary as a first step.
In the meantime, you can write hydrators targeting laminas-stdlib still in
order to guarantee compatibility.
### Removed
- Nothing.
### Fixed
- Nothing.
## 2.6.0 - 2015-07-21
### Added
- [zendframework/zend-stdlib#13](https://github.com/zendframework/zend-stdlib/pull/13) adds
`Laminas\Stdlib\Hydrator\Iterator`, which provides mechanisms for hydrating
objects when iterating a traversable. This allows creating generic collection
resultsets; the original idea was pulled from
[PhlyMongo](https://github.com/phly/PhlyMongo), where it was used to hydrate
collections retrieved from MongoDB.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- Nothing.
## 2.5.2 - 2015-07-21
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [zendframework/zend-stdlib#9](https://github.com/zendframework/zend-stdlib/pull/9) fixes an issue with
count incrementation during insert in PriorityList, ensuring that incrementation only
occurs when the item inserted was not previously present in the list.
## 2.4.4 - 2015-07-21
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [zendframework/zend-stdlib#9](https://github.com/zendframework/zend-stdlib/pull/9) fixes an issue with
count incrementation during insert in PriorityList, ensuring that incrementation only
occurs when the item inserted was not previously present in the list.
COPYRIGHT.md 0000666 00000000127 13605043255 0006445 0 ustar 00 Copyright (c) 2019, Laminas Foundation.
All rights reserved. (https://getlaminas.org/)
LICENSE.md 0000666 00000002725 13605043255 0006165 0 ustar 00 Copyright (c) 2019, Laminas Foundation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Laminas Foundation nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md 0000666 00000001251 13605043255 0006031 0 ustar 00 # laminas-stdlib
[![Build Status](https://travis-ci.org/laminas/laminas-stdlib.svg?branch=master)](https://travis-ci.org/laminas/laminas-stdlib)
[![Coverage Status](https://coveralls.io/repos/laminas/laminas-stdlib/badge.svg?branch=master)](https://coveralls.io/r/laminas/laminas-stdlib?branch=master)
`Laminas\Stdlib` is a set of components that implements general purpose utility
class for different scopes like:
- array utilities functions;
- hydrators;
- json serializable interfaces;
- general messaging systems;
- string wrappers;
- etc.
---
- File issues at https://github.com/laminas/laminas-stdlib/issues
- Documentation is at https://docs.laminas.dev/laminas-stdlib
composer.json 0000666 00000003705 13605043255 0007302 0 ustar 00 {
"name": "laminas/laminas-stdlib",
"description": " ",
"license": "BSD-3-Clause",
"keywords": [
"laminas",
"stdlib"
],
"homepage": "https://laminas.dev",
"support": {
"docs": "https://docs.laminas.dev/laminas-stdlib/",
"issues": "https://github.com/laminas/laminas-stdlib/issues",
"source": "https://github.com/laminas/laminas-stdlib",
"rss": "https://github.com/laminas/laminas-stdlib/releases.atom",
"chat": "https://laminas.dev/chat",
"forum": "https://discourse.laminas.dev"
},
"config": {
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "2.7-dev",
"dev-develop": "2.8-dev"
}
},
"require": {
"php": ">=5.5",
"laminas/laminas-hydrator": "~1.0",
"laminas/laminas-zendframework-bridge": "^1.0"
},
"require-dev": {
"athletic/athletic": "~0.1",
"fabpot/php-cs-fixer": "1.7.*",
"laminas/laminas-config": "~2.5",
"laminas/laminas-eventmanager": "~2.5",
"laminas/laminas-filter": "~2.5",
"laminas/laminas-inputfilter": "~2.5",
"laminas/laminas-serializer": "~2.5",
"laminas/laminas-servicemanager": "~2.5",
"phpunit/phpunit": "~4.0"
},
"suggest": {
"laminas/laminas-eventmanager": "To support aggregate hydrator usage",
"laminas/laminas-filter": "To support naming strategy hydrator usage",
"laminas/laminas-serializer": "Laminas\\Serializer component",
"laminas/laminas-servicemanager": "To support hydrator plugin manager usage"
},
"autoload": {
"psr-4": {
"Laminas\\Stdlib\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"LaminasTest\\Stdlib\\": "test/",
"LaminasBench\\Stdlib\\": "benchmark/"
}
},
"replace": {
"zendframework/zend-stdlib": "self.version"
}
}
src/AbstractOptions.php 0000666 00000011120 13605043255 0011165 0 ustar 00 setFromArray($options);
}
}
/**
* Set one or more configuration properties
*
* @param array|Traversable|AbstractOptions $options
* @throws Exception\InvalidArgumentException
* @return AbstractOptions Provides fluent interface
*/
public function setFromArray($options)
{
if ($options instanceof self) {
$options = $options->toArray();
}
if (!is_array($options) && !$options instanceof Traversable) {
throw new Exception\InvalidArgumentException(
sprintf(
'Parameter provided to %s must be an %s, %s or %s',
__METHOD__,
'array',
'Traversable',
'Laminas\Stdlib\AbstractOptions'
)
);
}
foreach ($options as $key => $value) {
$this->__set($key, $value);
}
return $this;
}
/**
* Cast to array
*
* @return array
*/
public function toArray()
{
$array = [];
$transform = function ($letters) {
$letter = array_shift($letters);
return '_' . strtolower($letter);
};
foreach ($this as $key => $value) {
if ($key === '__strictMode__') {
continue;
}
$normalizedKey = preg_replace_callback('/([A-Z])/', $transform, $key);
$array[$normalizedKey] = $value;
}
return $array;
}
/**
* Set a configuration property
*
* @see ParameterObject::__set()
* @param string $key
* @param mixed $value
* @throws Exception\BadMethodCallException
* @return void
*/
public function __set($key, $value)
{
$setter = 'set' . str_replace('_', '', $key);
if (is_callable([$this, $setter])) {
$this->{$setter}($value);
return;
}
if ($this->__strictMode__) {
throw new Exception\BadMethodCallException(sprintf(
'The option "%s" does not have a callable "%s" ("%s") setter method which must be defined',
$key,
'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))),
$setter
));
}
}
/**
* Get a configuration property
*
* @see ParameterObject::__get()
* @param string $key
* @throws Exception\BadMethodCallException
* @return mixed
*/
public function __get($key)
{
$getter = 'get' . str_replace('_', '', $key);
if (is_callable([$this, $getter])) {
return $this->{$getter}();
}
throw new Exception\BadMethodCallException(sprintf(
'The option "%s" does not have a callable "%s" getter method which must be defined',
$key,
'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)))
));
}
/**
* Test if a configuration property is null
* @see ParameterObject::__isset()
* @param string $key
* @return bool
*/
public function __isset($key)
{
$getter = 'get' . str_replace('_', '', $key);
return method_exists($this, $getter) && null !== $this->__get($key);
}
/**
* Set a configuration property to NULL
*
* @see ParameterObject::__unset()
* @param string $key
* @throws Exception\InvalidArgumentException
* @return void
*/
public function __unset($key)
{
try {
$this->__set($key, null);
} catch (Exception\BadMethodCallException $e) {
throw new Exception\InvalidArgumentException(
'The class property $' . $key . ' cannot be unset as'
. ' NULL is an invalid value for it',
0,
$e
);
}
}
}
src/ArrayObject.php 0000666 00000022611 13605043255 0010262 0 ustar 00 setFlags($flags);
$this->storage = $input;
$this->setIteratorClass($iteratorClass);
$this->protectedProperties = array_keys(get_object_vars($this));
}
/**
* Returns whether the requested key exists
*
* @param mixed $key
* @return bool
*/
public function __isset($key)
{
if ($this->flag == self::ARRAY_AS_PROPS) {
return $this->offsetExists($key);
}
if (in_array($key, $this->protectedProperties)) {
throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
}
return isset($this->$key);
}
/**
* Sets the value at the specified key to value
*
* @param mixed $key
* @param mixed $value
* @return void
*/
public function __set($key, $value)
{
if ($this->flag == self::ARRAY_AS_PROPS) {
return $this->offsetSet($key, $value);
}
if (in_array($key, $this->protectedProperties)) {
throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
}
$this->$key = $value;
}
/**
* Unsets the value at the specified key
*
* @param mixed $key
* @return void
*/
public function __unset($key)
{
if ($this->flag == self::ARRAY_AS_PROPS) {
return $this->offsetUnset($key);
}
if (in_array($key, $this->protectedProperties)) {
throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
}
unset($this->$key);
}
/**
* Returns the value at the specified key by reference
*
* @param mixed $key
* @return mixed
*/
public function &__get($key)
{
$ret = null;
if ($this->flag == self::ARRAY_AS_PROPS) {
$ret =& $this->offsetGet($key);
return $ret;
}
if (in_array($key, $this->protectedProperties)) {
throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
}
return $this->$key;
}
/**
* Appends the value
*
* @param mixed $value
* @return void
*/
public function append($value)
{
$this->storage[] = $value;
}
/**
* Sort the entries by value
*
* @return void
*/
public function asort()
{
asort($this->storage);
}
/**
* Get the number of public properties in the ArrayObject
*
* @return int
*/
public function count()
{
return count($this->storage);
}
/**
* Exchange the array for another one.
*
* @param array|ArrayObject $data
* @return array
*/
public function exchangeArray($data)
{
if (!is_array($data) && !is_object($data)) {
throw new Exception\InvalidArgumentException('Passed variable is not an array or object, using empty array instead');
}
if (is_object($data) && ($data instanceof self || $data instanceof \ArrayObject)) {
$data = $data->getArrayCopy();
}
if (!is_array($data)) {
$data = (array) $data;
}
$storage = $this->storage;
$this->storage = $data;
return $storage;
}
/**
* Creates a copy of the ArrayObject.
*
* @return array
*/
public function getArrayCopy()
{
return $this->storage;
}
/**
* Gets the behavior flags.
*
* @return int
*/
public function getFlags()
{
return $this->flag;
}
/**
* Create a new iterator from an ArrayObject instance
*
* @return \Iterator
*/
public function getIterator()
{
$class = $this->iteratorClass;
return new $class($this->storage);
}
/**
* Gets the iterator classname for the ArrayObject.
*
* @return string
*/
public function getIteratorClass()
{
return $this->iteratorClass;
}
/**
* Sort the entries by key
*
* @return void
*/
public function ksort()
{
ksort($this->storage);
}
/**
* Sort an array using a case insensitive "natural order" algorithm
*
* @return void
*/
public function natcasesort()
{
natcasesort($this->storage);
}
/**
* Sort entries using a "natural order" algorithm
*
* @return void
*/
public function natsort()
{
natsort($this->storage);
}
/**
* Returns whether the requested key exists
*
* @param mixed $key
* @return bool
*/
public function offsetExists($key)
{
return isset($this->storage[$key]);
}
/**
* Returns the value at the specified key
*
* @param mixed $key
* @return mixed
*/
public function &offsetGet($key)
{
$ret = null;
if (!$this->offsetExists($key)) {
return $ret;
}
$ret =& $this->storage[$key];
return $ret;
}
/**
* Sets the value at the specified key to value
*
* @param mixed $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value)
{
$this->storage[$key] = $value;
}
/**
* Unsets the value at the specified key
*
* @param mixed $key
* @return void
*/
public function offsetUnset($key)
{
if ($this->offsetExists($key)) {
unset($this->storage[$key]);
}
}
/**
* Serialize an ArrayObject
*
* @return string
*/
public function serialize()
{
return serialize(get_object_vars($this));
}
/**
* Sets the behavior flags
*
* @param int $flags
* @return void
*/
public function setFlags($flags)
{
$this->flag = $flags;
}
/**
* Sets the iterator classname for the ArrayObject
*
* @param string $class
* @return void
*/
public function setIteratorClass($class)
{
if (class_exists($class)) {
$this->iteratorClass = $class;
return ;
}
if (strpos($class, '\\') === 0) {
$class = '\\' . $class;
if (class_exists($class)) {
$this->iteratorClass = $class;
return ;
}
}
throw new Exception\InvalidArgumentException('The iterator class does not exist');
}
/**
* Sort the entries with a user-defined comparison function and maintain key association
*
* @param callable $function
* @return void
*/
public function uasort($function)
{
if (is_callable($function)) {
uasort($this->storage, $function);
}
}
/**
* Sort the entries by keys using a user-defined comparison function
*
* @param callable $function
* @return void
*/
public function uksort($function)
{
if (is_callable($function)) {
uksort($this->storage, $function);
}
}
/**
* Unserialize an ArrayObject
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
$ar = unserialize($data);
$this->protectedProperties = array_keys(get_object_vars($this));
$this->setFlags($ar['flag']);
$this->exchangeArray($ar['storage']);
$this->setIteratorClass($ar['iteratorClass']);
foreach ($ar as $k => $v) {
switch ($k) {
case 'flag':
$this->setFlags($v);
break;
case 'storage':
$this->exchangeArray($v);
break;
case 'iteratorClass':
$this->setIteratorClass($v);
break;
case 'protectedProperties':
continue;
default:
$this->__set($k, $v);
}
}
}
}
src/ArraySerializableInterface.php 0000666 00000001221 13605043255 0013275 0 ustar 00 getArrayCopy();
return new ArrayIterator(array_reverse($array));
}
}
src/ArrayUtils.php 0000666 00000022427 13605043255 0010161 0 ustar 00 0;
}
/**
* Test whether an array contains one or more integer keys
*
* @param mixed $value
* @param bool $allowEmpty Should an empty array() return true
* @return bool
*/
public static function hasIntegerKeys($value, $allowEmpty = false)
{
if (!is_array($value)) {
return false;
}
if (!$value) {
return $allowEmpty;
}
return count(array_filter(array_keys($value), 'is_int')) > 0;
}
/**
* Test whether an array contains one or more numeric keys.
*
* A numeric key can be one of the following:
* - an integer 1,
* - a string with a number '20'
* - a string with negative number: '-1000'
* - a float: 2.2120, -78.150999
* - a string with float: '4000.99999', '-10.10'
*
* @param mixed $value
* @param bool $allowEmpty Should an empty array() return true
* @return bool
*/
public static function hasNumericKeys($value, $allowEmpty = false)
{
if (!is_array($value)) {
return false;
}
if (!$value) {
return $allowEmpty;
}
return count(array_filter(array_keys($value), 'is_numeric')) > 0;
}
/**
* Test whether an array is a list
*
* A list is a collection of values assigned to continuous integer keys
* starting at 0 and ending at count() - 1.
*
* For example:
*
* $list = array('a', 'b', 'c', 'd');
* $list = array(
* 0 => 'foo',
* 1 => 'bar',
* 2 => array('foo' => 'baz'),
* );
*
*
* @param mixed $value
* @param bool $allowEmpty Is an empty list a valid list?
* @return bool
*/
public static function isList($value, $allowEmpty = false)
{
if (!is_array($value)) {
return false;
}
if (!$value) {
return $allowEmpty;
}
return (array_values($value) === $value);
}
/**
* Test whether an array is a hash table.
*
* An array is a hash table if:
*
* 1. Contains one or more non-integer keys, or
* 2. Integer keys are non-continuous or misaligned (not starting with 0)
*
* For example:
*
* $hash = array(
* 'foo' => 15,
* 'bar' => false,
* );
* $hash = array(
* 1995 => 'Birth of PHP',
* 2009 => 'PHP 5.3.0',
* 2012 => 'PHP 5.4.0',
* );
* $hash = array(
* 'formElement,
* 'options' => array( 'debug' => true ),
* );
*
*
* @param mixed $value
* @param bool $allowEmpty Is an empty array() a valid hash table?
* @return bool
*/
public static function isHashTable($value, $allowEmpty = false)
{
if (!is_array($value)) {
return false;
}
if (!$value) {
return $allowEmpty;
}
return (array_values($value) !== $value);
}
/**
* Checks if a value exists in an array.
*
* Due to "foo" == 0 === TRUE with in_array when strict = false, an option
* has been added to prevent this. When $strict = 0/false, the most secure
* non-strict check is implemented. if $strict = -1, the default in_array
* non-strict behaviour is used.
*
* @param mixed $needle
* @param array $haystack
* @param int|bool $strict
* @return bool
*/
public static function inArray($needle, array $haystack, $strict = false)
{
if (!$strict) {
if (is_int($needle) || is_float($needle)) {
$needle = (string) $needle;
}
if (is_string($needle)) {
foreach ($haystack as &$h) {
if (is_int($h) || is_float($h)) {
$h = (string) $h;
}
}
}
}
return in_array($needle, $haystack, $strict);
}
/**
* Convert an iterator to an array.
*
* Converts an iterator to an array. The $recursive flag, on by default,
* hints whether or not you want to do so recursively.
*
* @param array|Traversable $iterator The array or Traversable object to convert
* @param bool $recursive Recursively check all nested structures
* @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object
* @return array
*/
public static function iteratorToArray($iterator, $recursive = true)
{
if (!is_array($iterator) && !$iterator instanceof Traversable) {
throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object');
}
if (!$recursive) {
if (is_array($iterator)) {
return $iterator;
}
return iterator_to_array($iterator);
}
if (method_exists($iterator, 'toArray')) {
return $iterator->toArray();
}
$array = [];
foreach ($iterator as $key => $value) {
if (is_scalar($value)) {
$array[$key] = $value;
continue;
}
if ($value instanceof Traversable) {
$array[$key] = static::iteratorToArray($value, $recursive);
continue;
}
if (is_array($value)) {
$array[$key] = static::iteratorToArray($value, $recursive);
continue;
}
$array[$key] = $value;
}
return $array;
}
/**
* Merge two arrays together.
*
* If an integer key exists in both arrays and preserveNumericKeys is false, the value
* from the second array will be appended to the first array. If both values are arrays, they
* are merged together, else the value of the second array overwrites the one of the first array.
*
* @param array $a
* @param array $b
* @param bool $preserveNumericKeys
* @return array
*/
public static function merge(array $a, array $b, $preserveNumericKeys = false)
{
foreach ($b as $key => $value) {
if ($value instanceof MergeReplaceKeyInterface) {
$a[$key] = $value->getData();
} elseif (isset($a[$key]) || array_key_exists($key, $a)) {
if ($value instanceof MergeRemoveKey) {
unset($a[$key]);
} elseif (!$preserveNumericKeys && is_int($key)) {
$a[] = $value;
} elseif (is_array($value) && is_array($a[$key])) {
$a[$key] = static::merge($a[$key], $value, $preserveNumericKeys);
} else {
$a[$key] = $value;
}
} else {
if (!$value instanceof MergeRemoveKey) {
$a[$key] = $value;
}
}
}
return $a;
}
/**
* Compatibility Method for array_filter on <5.6 systems
*
* @param array $data
* @param callable $callback
* @param null|int $flag
* @return array
*/
public static function filter(array $data, $callback, $flag = null)
{
if (! is_callable($callback)) {
throw new Exception\InvalidArgumentException(sprintf(
'Second parameter of %s must be callable',
__METHOD__
));
}
if (version_compare(PHP_VERSION, '5.6.0') >= 0) {
return array_filter($data, $callback, $flag);
}
$output = [];
foreach ($data as $key => $value) {
$params = [$value];
if ($flag === static::ARRAY_FILTER_USE_BOTH) {
$params[] = $key;
}
if ($flag === static::ARRAY_FILTER_USE_KEY) {
$params = [$key];
}
$response = call_user_func_array($callback, $params);
if ($response) {
$output[$key] = $value;
}
}
return $output;
}
}
src/ArrayUtils/MergeRemoveKey.php 0000666 00000000541 13605043255 0013040 0 ustar 00 data = $data;
}
/**
* {@inheritDoc}
*/
public function getData()
{
return $this->data;
}
}
src/ArrayUtils/MergeReplaceKeyInterface.php 0000666 00000001032 13605043255 0014773 0 ustar 00 metadata = $metadata;
$this->registerCallback($callback);
}
/**
* Registers the callback provided in the constructor
*
* @param callable $callback
* @throws Exception\InvalidCallbackException
* @return void
*/
protected function registerCallback($callback)
{
if (!is_callable($callback)) {
throw new Exception\InvalidCallbackException('Invalid callback provided; not callable');
}
$this->callback = $callback;
}
/**
* Retrieve registered callback
*
* @return callable
*/
public function getCallback()
{
return $this->callback;
}
/**
* Invoke handler
*
* @param array $args Arguments to pass to callback
* @return mixed
*/
public function call(array $args = [])
{
$callback = $this->getCallback();
$argCount = count($args);
if (is_string($callback)) {
$result = $this->validateStringCallbackFor54($callback);
if ($result !== true && $argCount <= 3) {
$callback = $result;
// Minor performance tweak, if the callback gets called more
// than once
$this->callback = $result;
}
}
// Minor performance tweak; use call_user_func() until > 3 arguments
// reached
switch ($argCount) {
case 0:
return $callback();
case 1:
return $callback(array_shift($args));
case 2:
$arg1 = array_shift($args);
$arg2 = array_shift($args);
return $callback($arg1, $arg2);
case 3:
$arg1 = array_shift($args);
$arg2 = array_shift($args);
$arg3 = array_shift($args);
return $callback($arg1, $arg2, $arg3);
default:
return call_user_func_array($callback, $args);
}
}
/**
* Invoke as functor
*
* @return mixed
*/
public function __invoke()
{
return $this->call(func_get_args());
}
/**
* Get all callback metadata
*
* @return array
*/
public function getMetadata()
{
return $this->metadata;
}
/**
* Retrieve a single metadatum
*
* @param string $name
* @return mixed
*/
public function getMetadatum($name)
{
if (array_key_exists($name, $this->metadata)) {
return $this->metadata[$name];
}
return;
}
/**
* Validate a static method call
*
*
* @param string $callback
* @return true|array
* @throws Exception\InvalidCallbackException if invalid
*/
protected function validateStringCallbackFor54($callback)
{
if (!strstr($callback, '::')) {
return true;
}
list($class, $method) = explode('::', $callback, 2);
if (!class_exists($class)) {
throw new Exception\InvalidCallbackException(sprintf(
'Static method call "%s" refers to a class that does not exist',
$callback
));
}
$r = new ReflectionClass($class);
if (!$r->hasMethod($method)) {
throw new Exception\InvalidCallbackException(sprintf(
'Static method call "%s" refers to a method that does not exist',
$callback
));
}
$m = $r->getMethod($method);
if (!$m->isStatic()) {
throw new Exception\InvalidCallbackException(sprintf(
'Static method call "%s" refers to a method that is not static',
$callback
));
}
// returning a non boolean value may not be nice for a validate method,
// but that allows the usage of a static string callback without using
// the call_user_func function.
return [$class, $method];
}
}
src/DateTime.php 0000666 00000002447 13605043255 0007556 0 ustar 00 values[$priority][] = $value;
if (! isset($this->priorities[$priority])) {
$this->priorities[$priority] = $priority;
$this->maxPriority = max($priority, $this->maxPriority);
}
++$this->count;
}
/**
* Extract an element in the queue according to the priority and the
* order of insertion
*
* @return mixed
*/
public function extract()
{
if (! $this->valid()) {
return false;
}
$value = $this->current();
$this->nextAndRemove();
return $value;
}
/**
* Remove an item from the queue
*
* This is different than {@link extract()}; its purpose is to dequeue an
* item.
*
* Note: this removes the first item matching the provided item found. If
* the same item has been added multiple times, it will not remove other
* instances.
*
* @param mixed $datum
* @return bool False if the item was not found, true otherwise.
*/
public function remove($datum)
{
$this->rewind();
while ($this->valid()) {
if (current($this->values[$this->maxPriority]) === $datum) {
$index = key($this->values[$this->maxPriority]);
unset($this->values[$this->maxPriority][$index]);
--$this->count;
return true;
}
$this->next();
}
return false;
}
/**
* Get the total number of elements in the queue
*
* @return integer
*/
public function count()
{
return $this->count;
}
/**
* Get the current element in the queue
*
* @return mixed
*/
public function current()
{
switch ($this->extractFlag) {
case self::EXTR_DATA:
return current($this->values[$this->maxPriority]);
case self::EXTR_PRIORITY:
return $this->maxPriority;
case self::EXTR_BOTH:
return [
'data' => current($this->values[$this->maxPriority]),
'priority' => $this->maxPriority
];
}
}
/**
* Get the index of the current element in the queue
*
* @return integer
*/
public function key()
{
return $this->index;
}
/**
* Set the iterator pointer to the next element in the queue
* removing the previous element
*/
protected function nextAndRemove()
{
if (false === next($this->values[$this->maxPriority])) {
unset($this->priorities[$this->maxPriority]);
unset($this->values[$this->maxPriority]);
$this->maxPriority = empty($this->priorities) ? 0 : max($this->priorities);
$this->subIndex = -1;
}
++$this->index;
++$this->subIndex;
--$this->count;
}
/**
* Set the iterator pointer to the next element in the queue
* without removing the previous element
*/
public function next()
{
if (false === next($this->values[$this->maxPriority])) {
unset($this->subPriorities[$this->maxPriority]);
reset($this->values[$this->maxPriority]);
$this->maxPriority = empty($this->subPriorities) ? 0 : max($this->subPriorities);
$this->subIndex = -1;
}
++$this->index;
++$this->subIndex;
}
/**
* Check if the current iterator is valid
*
* @return boolean
*/
public function valid()
{
return isset($this->values[$this->maxPriority]);
}
/**
* Rewind the current iterator
*/
public function rewind()
{
$this->subPriorities = $this->priorities;
$this->maxPriority = empty($this->priorities) ? 0 : max($this->priorities);
$this->index = 0;
$this->subIndex = 0;
}
/**
* Serialize to an array
*
* Array will be priority => data pairs
*
* @return array
*/
public function toArray()
{
$array = [];
foreach (clone $this as $item) {
$array[] = $item;
}
return $array;
}
/**
* Serialize
*
* @return string
*/
public function serialize()
{
$clone = clone $this;
$clone->setExtractFlags(self::EXTR_BOTH);
$data = [];
foreach ($clone as $item) {
$data[] = $item;
}
return serialize($data);
}
/**
* Deserialize
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
foreach (unserialize($data) as $item) {
$this->insert($item['data'], $item['priority']);
}
}
/**
* Set the extract flag
*
* @param integer $flag
*/
public function setExtractFlags($flag)
{
switch ($flag) {
case self::EXTR_DATA:
case self::EXTR_PRIORITY:
case self::EXTR_BOTH:
$this->extractFlag = $flag;
break;
default:
throw new Exception\InvalidArgumentException("The extract flag specified is not valid");
}
}
/**
* Check if the queue is empty
*
* @return boolean
*/
public function isEmpty()
{
return empty($this->values);
}
/**
* Does the queue contain the given datum?
*
* @param mixed $datum
* @return bool
*/
public function contains($datum)
{
foreach ($this->values as $values) {
if (in_array($datum, $values)) {
return true;
}
}
return false;
}
/**
* Does the queue have an item with the given priority?
*
* @param int $priority
* @return bool
*/
public function hasPriority($priority)
{
return isset($this->values[$priority]);
}
}
src/Glob.php 0000666 00000012703 13605043255 0006741 0 ustar 00 GLOB_MARK,
self::GLOB_NOSORT => GLOB_NOSORT,
self::GLOB_NOCHECK => GLOB_NOCHECK,
self::GLOB_NOESCAPE => GLOB_NOESCAPE,
self::GLOB_BRACE => GLOB_BRACE,
self::GLOB_ONLYDIR => GLOB_ONLYDIR,
self::GLOB_ERR => GLOB_ERR,
];
$globFlags = 0;
foreach ($flagMap as $internalFlag => $globFlag) {
if ($flags & $internalFlag) {
$globFlags |= $globFlag;
}
}
} else {
$globFlags = 0;
}
ErrorHandler::start();
$res = glob($pattern, $globFlags);
$err = ErrorHandler::stop();
if ($res === false) {
throw new Exception\RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err);
}
return $res;
}
/**
* Expand braces manually, then use the system glob.
*
* @param string $pattern
* @param int $flags
* @return array
* @throws Exception\RuntimeException
*/
protected static function fallbackGlob($pattern, $flags)
{
if (!$flags & self::GLOB_BRACE) {
return static::systemGlob($pattern, $flags);
}
$flags &= ~self::GLOB_BRACE;
$length = strlen($pattern);
$paths = [];
if ($flags & self::GLOB_NOESCAPE) {
$begin = strpos($pattern, '{');
} else {
$begin = 0;
while (true) {
if ($begin === $length) {
$begin = false;
break;
} elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) {
$begin++;
} elseif ($pattern[$begin] === '{') {
break;
}
$begin++;
}
}
if ($begin === false) {
return static::systemGlob($pattern, $flags);
}
$next = static::nextBraceSub($pattern, $begin + 1, $flags);
if ($next === null) {
return static::systemGlob($pattern, $flags);
}
$rest = $next;
while ($pattern[$rest] !== '}') {
$rest = static::nextBraceSub($pattern, $rest + 1, $flags);
if ($rest === null) {
return static::systemGlob($pattern, $flags);
}
}
$p = $begin + 1;
while (true) {
$subPattern = substr($pattern, 0, $begin)
. substr($pattern, $p, $next - $p)
. substr($pattern, $rest + 1);
$result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE);
if ($result) {
$paths = array_merge($paths, $result);
}
if ($pattern[$next] === '}') {
break;
}
$p = $next + 1;
$next = static::nextBraceSub($pattern, $p, $flags);
}
return array_unique($paths);
}
/**
* Find the end of the sub-pattern in a brace expression.
*
* @param string $pattern
* @param int $begin
* @param int $flags
* @return int|null
*/
protected static function nextBraceSub($pattern, $begin, $flags)
{
$length = strlen($pattern);
$depth = 0;
$current = $begin;
while ($current < $length) {
if (!$flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') {
if (++$current === $length) {
break;
}
$current++;
} else {
if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) {
break;
} elseif ($pattern[$current++] === '{') {
$depth++;
}
}
}
return ($current < $length ? $current : null);
}
}
src/Guard/AllGuardsTrait.php 0000666 00000000732 13605043255 0012001 0 ustar 00 metadata[$spec] = $value;
return $this;
}
if (!is_array($spec) && !$spec instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'Expected a string, array, or Traversable argument in first position; received "%s"',
(is_object($spec) ? get_class($spec) : gettype($spec))
));
}
foreach ($spec as $key => $value) {
$this->metadata[$key] = $value;
}
return $this;
}
/**
* Retrieve all metadata or a single metadatum as specified by key
*
* @param null|string|int $key
* @param null|mixed $default
* @throws Exception\InvalidArgumentException
* @return mixed
*/
public function getMetadata($key = null, $default = null)
{
if (null === $key) {
return $this->metadata;
}
if (!is_scalar($key)) {
throw new Exception\InvalidArgumentException('Non-scalar argument provided for key');
}
if (array_key_exists($key, $this->metadata)) {
return $this->metadata[$key];
}
return $default;
}
/**
* Set message content
*
* @param mixed $value
* @return Message
*/
public function setContent($value)
{
$this->content = $value;
return $this;
}
/**
* Get message content
*
* @return mixed
*/
public function getContent()
{
return $this->content;
}
/**
* @return string
*/
public function toString()
{
$request = '';
foreach ($this->getMetadata() as $key => $value) {
$request .= sprintf(
"%s: %s\r\n",
(string) $key,
(string) $value
);
}
$request .= "\r\n" . $this->getContent();
return $request;
}
}
src/MessageInterface.php 0000666 00000001604 13605043255 0011261 0 ustar 00 exchangeArray($values);
}
/**
* Populate from query string
*
* @param string $string
* @return void
*/
public function fromString($string)
{
$array = [];
parse_str($string, $array);
$this->fromArray($array);
}
/**
* Serialize to native PHP array
*
* @return array
*/
public function toArray()
{
return $this->getArrayCopy();
}
/**
* Serialize to query string
*
* @return string
*/
public function toString()
{
return http_build_query($this);
}
/**
* Retrieve by key
*
* Returns null if the key does not exist.
*
* @param string $name
* @return mixed
*/
public function offsetGet($name)
{
if ($this->offsetExists($name)) {
return parent::offsetGet($name);
}
return;
}
/**
* @param string $name
* @param mixed $default optional default value
* @return mixed
*/
public function get($name, $default = null)
{
if ($this->offsetExists($name)) {
return parent::offsetGet($name);
}
return $default;
}
/**
* @param string $name
* @param mixed $value
* @return Parameters
*/
public function set($name, $value)
{
$this[$name] = $value;
return $this;
}
}
src/ParametersInterface.php 0000666 00000003445 13605043255 0012005 0 ustar 00 items[$name])) {
$this->count++;
}
$this->sorted = false;
$this->items[$name] = [
'data' => $value,
'priority' => (int) $priority,
'serial' => $this->serial++,
];
}
/**
* @param string $name
* @param int $priority
*
* @return $this
*
* @throws \Exception
*/
public function setPriority($name, $priority)
{
if (!isset($this->items[$name])) {
throw new \Exception("item $name not found");
}
$this->items[$name]['priority'] = (int) $priority;
$this->sorted = false;
return $this;
}
/**
* Remove a item.
*
* @param string $name
* @return void
*/
public function remove($name)
{
if (isset($this->items[$name])) {
$this->count--;
}
unset($this->items[$name]);
}
/**
* Remove all items.
*
* @return void
*/
public function clear()
{
$this->items = [];
$this->serial = 0;
$this->count = 0;
$this->sorted = false;
}
/**
* Get a item.
*
* @param string $name
* @return mixed
*/
public function get($name)
{
if (!isset($this->items[$name])) {
return;
}
return $this->items[$name]['data'];
}
/**
* Sort all items.
*
* @return void
*/
protected function sort()
{
if (!$this->sorted) {
uasort($this->items, [$this, 'compare']);
$this->sorted = true;
}
}
/**
* Compare the priority of two items.
*
* @param array $item1,
* @param array $item2
* @return int
*/
protected function compare(array $item1, array $item2)
{
return ($item1['priority'] === $item2['priority'])
? ($item1['serial'] > $item2['serial'] ? -1 : 1) * $this->isLIFO
: ($item1['priority'] > $item2['priority'] ? -1 : 1);
}
/**
* Get/Set serial order mode
*
* @param bool|null $flag
*
* @return bool
*/
public function isLIFO($flag = null)
{
if ($flag !== null) {
$isLifo = $flag === true ? 1 : -1;
if ($isLifo !== $this->isLIFO) {
$this->isLIFO = $isLifo;
$this->sorted = false;
}
}
return 1 === $this->isLIFO;
}
/**
* {@inheritDoc}
*/
public function rewind()
{
$this->sort();
reset($this->items);
}
/**
* {@inheritDoc}
*/
public function current()
{
$this->sorted || $this->sort();
$node = current($this->items);
return $node ? $node['data'] : false;
}
/**
* {@inheritDoc}
*/
public function key()
{
$this->sorted || $this->sort();
return key($this->items);
}
/**
* {@inheritDoc}
*/
public function next()
{
$node = next($this->items);
return $node ? $node['data'] : false;
}
/**
* {@inheritDoc}
*/
public function valid()
{
return current($this->items) !== false;
}
/**
* @return self
*/
public function getIterator()
{
return clone $this;
}
/**
* {@inheritDoc}
*/
public function count()
{
return $this->count;
}
/**
* Return list as array
*
* @param int $flag
*
* @return array
*/
public function toArray($flag = self::EXTR_DATA)
{
$this->sort();
if ($flag == self::EXTR_BOTH) {
return $this->items;
}
return array_map(
function ($item) use ($flag) {
return ($flag == PriorityList::EXTR_PRIORITY) ? $item['priority'] : $item['data'];
},
$this->items
);
}
}
src/PriorityQueue.php 0000666 00000017272 13605043255 0010712 0 ustar 00 items[] = [
'data' => $data,
'priority' => $priority,
];
$this->getQueue()->insert($data, $priority);
return $this;
}
/**
* Remove an item from the queue
*
* This is different than {@link extract()}; its purpose is to dequeue an
* item.
*
* This operation is potentially expensive, as it requires
* re-initialization and re-population of the inner queue.
*
* Note: this removes the first item matching the provided item found. If
* the same item has been added multiple times, it will not remove other
* instances.
*
* @param mixed $datum
* @return bool False if the item was not found, true otherwise.
*/
public function remove($datum)
{
$found = false;
foreach ($this->items as $key => $item) {
if ($item['data'] === $datum) {
$found = true;
break;
}
}
if ($found) {
unset($this->items[$key]);
$this->queue = null;
if (!$this->isEmpty()) {
$queue = $this->getQueue();
foreach ($this->items as $item) {
$queue->insert($item['data'], $item['priority']);
}
}
return true;
}
return false;
}
/**
* Is the queue empty?
*
* @return bool
*/
public function isEmpty()
{
return (0 === $this->count());
}
/**
* How many items are in the queue?
*
* @return int
*/
public function count()
{
return count($this->items);
}
/**
* Peek at the top node in the queue, based on priority.
*
* @return mixed
*/
public function top()
{
return $this->getIterator()->top();
}
/**
* Extract a node from the inner queue and sift up
*
* @return mixed
*/
public function extract()
{
return $this->getQueue()->extract();
}
/**
* Retrieve the inner iterator
*
* SplPriorityQueue acts as a heap, which typically implies that as items
* are iterated, they are also removed. This does not work for situations
* where the queue may be iterated multiple times. As such, this class
* aggregates the values, and also injects an SplPriorityQueue. This method
* retrieves the inner queue object, and clones it for purposes of
* iteration.
*
* @return SplPriorityQueue
*/
public function getIterator()
{
$queue = $this->getQueue();
return clone $queue;
}
/**
* Serialize the data structure
*
* @return string
*/
public function serialize()
{
return serialize($this->items);
}
/**
* Unserialize a string into a PriorityQueue object
*
* Serialization format is compatible with {@link Laminas\Stdlib\SplPriorityQueue}
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
foreach (unserialize($data) as $item) {
$this->insert($item['data'], $item['priority']);
}
}
/**
* Serialize to an array
*
* By default, returns only the item data, and in the order registered (not
* sorted). You may provide one of the EXTR_* flags as an argument, allowing
* the ability to return priorities or both data and priority.
*
* @param int $flag
* @return array
*/
public function toArray($flag = self::EXTR_DATA)
{
switch ($flag) {
case self::EXTR_BOTH:
return $this->items;
case self::EXTR_PRIORITY:
return array_map(function ($item) {
return $item['priority'];
}, $this->items);
case self::EXTR_DATA:
default:
return array_map(function ($item) {
return $item['data'];
}, $this->items);
}
}
/**
* Specify the internal queue class
*
* Please see {@link getIterator()} for details on the necessity of an
* internal queue class. The class provided should extend SplPriorityQueue.
*
* @param string $class
* @return PriorityQueue
*/
public function setInternalQueueClass($class)
{
$this->queueClass = (string) $class;
return $this;
}
/**
* Does the queue contain the given datum?
*
* @param mixed $datum
* @return bool
*/
public function contains($datum)
{
foreach ($this->items as $item) {
if ($item['data'] === $datum) {
return true;
}
}
return false;
}
/**
* Does the queue have an item with the given priority?
*
* @param int $priority
* @return bool
*/
public function hasPriority($priority)
{
foreach ($this->items as $item) {
if ($item['priority'] === $priority) {
return true;
}
}
return false;
}
/**
* Get the inner priority queue instance
*
* @throws Exception\DomainException
* @return SplPriorityQueue
*/
protected function getQueue()
{
if (null === $this->queue) {
$this->queue = new $this->queueClass();
if (!$this->queue instanceof \SplPriorityQueue) {
throw new Exception\DomainException(sprintf(
'PriorityQueue expects an internal queue of type SplPriorityQueue; received "%s"',
get_class($this->queue)
));
}
}
return $this->queue;
}
/**
* Add support for deep cloning
*
* @return void
*/
public function __clone()
{
if (null !== $this->queue) {
$this->queue = clone $this->queue;
}
}
}
src/Request.php 0000666 00000000633 13605043255 0007505 0 ustar 00 serial--];
}
parent::insert($datum, $priority);
}
/**
* Serialize to an array
*
* Array will be priority => data pairs
*
* @return array
*/
public function toArray()
{
$array = [];
foreach (clone $this as $item) {
$array[] = $item;
}
return $array;
}
/**
* Serialize
*
* @return string
*/
public function serialize()
{
$clone = clone $this;
$clone->setExtractFlags(self::EXTR_BOTH);
$data = [];
foreach ($clone as $item) {
$data[] = $item;
}
return serialize($data);
}
/**
* Deserialize
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
foreach (unserialize($data) as $item) {
$this->insert($item['data'], $item['priority']);
}
}
}
src/SplQueue.php 0000666 00000002055 13605043255 0007620 0 ustar 00 toArray());
}
/**
* Unserialize
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
foreach (unserialize($data) as $item) {
$this->push($item);
}
}
}
src/SplStack.php 0000666 00000002066 13605043255 0007603 0 ustar 00 toArray());
}
/**
* Unserialize
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
foreach (unserialize($data) as $item) {
$this->unshift($item);
}
}
}
src/StringUtils.php 0000666 00000012471 13605043255 0010347 0 ustar 00 setEncoding($encoding, $convertEncoding);
return $wrapper;
}
}
throw new Exception\RuntimeException(
'No wrapper found supporting "' . $encoding . '"'
. (($convertEncoding !== null) ? ' and "' . $convertEncoding . '"' : '')
);
}
/**
* Get a list of all known single-byte character encodings
*
* @return string[]
*/
public static function getSingleByteEncodings()
{
return static::$singleByteEncodings;
}
/**
* Check if a given encoding is a known single-byte character encoding
*
* @param string $encoding
* @return bool
*/
public static function isSingleByteEncoding($encoding)
{
return in_array(strtoupper($encoding), static::$singleByteEncodings);
}
/**
* Check if a given string is valid UTF-8 encoded
*
* @param string $str
* @return bool
*/
public static function isValidUtf8($str)
{
return is_string($str) && ($str === '' || preg_match('/^./su', $str) == 1);
}
/**
* Is PCRE compiled with Unicode support?
*
* @return bool
*/
public static function hasPcreUnicodeSupport()
{
if (static::$hasPcreUnicodeSupport === null) {
ErrorHandler::start();
static::$hasPcreUnicodeSupport = defined('PREG_BAD_UTF8_OFFSET_ERROR') && preg_match('/\pL/u', 'a') == 1;
ErrorHandler::stop();
}
return static::$hasPcreUnicodeSupport;
}
}
src/StringWrapper/AbstractStringWrapper.php 0000666 00000020566 13605043255 0015166 0 ustar 00 convertEncoding = $convertEncodingUpper;
} else {
$this->convertEncoding = null;
}
$this->encoding = $encodingUpper;
return $this;
}
/**
* Get the defined character encoding to work with
*
* @return string
* @throws Exception\LogicException If no encoding was defined
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Get the defined character encoding to convert to
*
* @return string|null
*/
public function getConvertEncoding()
{
return $this->convertEncoding;
}
/**
* Convert a string from defined character encoding to the defined convert encoding
*
* @param string $str
* @param bool $reverse
* @return string|false
*/
public function convert($str, $reverse = false)
{
$encoding = $this->getEncoding();
$convertEncoding = $this->getConvertEncoding();
if ($convertEncoding === null) {
throw new Exception\LogicException(
'No convert encoding defined'
);
}
if ($encoding === $convertEncoding) {
return $str;
}
$from = $reverse ? $convertEncoding : $encoding;
$to = $reverse ? $encoding : $convertEncoding;
throw new Exception\RuntimeException(sprintf(
'Converting from "%s" to "%s" isn\'t supported by this string wrapper',
$from,
$to
));
}
/**
* Wraps a string to a given number of characters
*
* @param string $string
* @param int $width
* @param string $break
* @param bool $cut
* @return string|false
*/
public function wordWrap($string, $width = 75, $break = "\n", $cut = false)
{
$string = (string) $string;
if ($string === '') {
return '';
}
$break = (string) $break;
if ($break === '') {
throw new Exception\InvalidArgumentException('Break string cannot be empty');
}
$width = (int) $width;
if ($width === 0 && $cut) {
throw new Exception\InvalidArgumentException('Cannot force cut when width is zero');
}
if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
return wordwrap($string, $width, $break, $cut);
}
$stringWidth = $this->strlen($string);
$breakWidth = $this->strlen($break);
$result = '';
$lastStart = $lastSpace = 0;
for ($current = 0; $current < $stringWidth; $current++) {
$char = $this->substr($string, $current, 1);
$possibleBreak = $char;
if ($breakWidth !== 1) {
$possibleBreak = $this->substr($string, $current, $breakWidth);
}
if ($possibleBreak === $break) {
$result .= $this->substr($string, $lastStart, $current - $lastStart + $breakWidth);
$current += $breakWidth - 1;
$lastStart = $lastSpace = $current + 1;
continue;
}
if ($char === ' ') {
if ($current - $lastStart >= $width) {
$result .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
$lastStart = $current + 1;
}
$lastSpace = $current;
continue;
}
if ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
$result .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
$lastStart = $lastSpace = $current;
continue;
}
if ($current - $lastStart >= $width && $lastStart < $lastSpace) {
$result .= $this->substr($string, $lastStart, $lastSpace - $lastStart) . $break;
$lastStart = $lastSpace = $lastSpace + 1;
continue;
}
}
if ($lastStart !== $current) {
$result .= $this->substr($string, $lastStart, $current - $lastStart);
}
return $result;
}
/**
* Pad a string to a certain length with another string
*
* @param string $input
* @param int $padLength
* @param string $padString
* @param int $padType
* @return string
*/
public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT)
{
if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
return str_pad($input, $padLength, $padString, $padType);
}
$lengthOfPadding = $padLength - $this->strlen($input);
if ($lengthOfPadding <= 0) {
return $input;
}
$padStringLength = $this->strlen($padString);
if ($padStringLength === 0) {
return $input;
}
$repeatCount = floor($lengthOfPadding / $padStringLength);
if ($padType === STR_PAD_BOTH) {
$repeatCountLeft = $repeatCountRight = ($repeatCount - $repeatCount % 2) / 2;
$lastStringLength = $lengthOfPadding - 2 * $repeatCountLeft * $padStringLength;
$lastStringLeftLength = $lastStringRightLength = floor($lastStringLength / 2);
$lastStringRightLength += $lastStringLength % 2;
$lastStringLeft = $this->substr($padString, 0, $lastStringLeftLength);
$lastStringRight = $this->substr($padString, 0, $lastStringRightLength);
return str_repeat($padString, $repeatCountLeft) . $lastStringLeft
. $input
. str_repeat($padString, $repeatCountRight) . $lastStringRight;
}
$lastString = $this->substr($padString, 0, $lengthOfPadding % $padStringLength);
if ($padType === STR_PAD_LEFT) {
return str_repeat($padString, $repeatCount) . $lastString . $input;
}
return $input . str_repeat($padString, $repeatCount) . $lastString;
}
}
src/StringWrapper/Iconv.php 0000666 00000014731 13605043255 0011746 0 ustar 00 getEncoding());
}
/**
* Returns the portion of string specified by the start and length parameters
*
* @param string $str
* @param int $offset
* @param int|null $length
* @return string|false
*/
public function substr($str, $offset = 0, $length = null)
{
return iconv_substr($str, $offset, $length, $this->getEncoding());
}
/**
* Find the position of the first occurrence of a substring in a string
*
* @param string $haystack
* @param string $needle
* @param int $offset
* @return int|false
*/
public function strpos($haystack, $needle, $offset = 0)
{
return iconv_strpos($haystack, $needle, $offset, $this->getEncoding());
}
/**
* Convert a string from defined encoding to the defined convert encoding
*
* @param string $str
* @param bool $reverse
* @return string|false
*/
public function convert($str, $reverse = false)
{
$encoding = $this->getEncoding();
$convertEncoding = $this->getConvertEncoding();
if ($convertEncoding === null) {
throw new Exception\LogicException(
'No convert encoding defined'
);
}
if ($encoding === $convertEncoding) {
return $str;
}
$fromEncoding = $reverse ? $convertEncoding : $encoding;
$toEncoding = $reverse ? $encoding : $convertEncoding;
// automatically add "//IGNORE" to not stop converting on invalid characters
// invalid characters triggers a notice anyway
return iconv($fromEncoding, $toEncoding . '//IGNORE', $str);
}
}
src/StringWrapper/Intl.php 0000666 00000004171 13605043255 0011573 0 ustar 00 getEncoding());
}
/**
* Returns the portion of string specified by the start and length parameters
*
* @param string $str
* @param int $offset
* @param int|null $length
* @return string|false
*/
public function substr($str, $offset = 0, $length = null)
{
return mb_substr($str, $offset, $length, $this->getEncoding());
}
/**
* Find the position of the first occurrence of a substring in a string
*
* @param string $haystack
* @param string $needle
* @param int $offset
* @return int|false
*/
public function strpos($haystack, $needle, $offset = 0)
{
return mb_strpos($haystack, $needle, $offset, $this->getEncoding());
}
/**
* Convert a string from defined encoding to the defined convert encoding
*
* @param string $str
* @param bool $reverse
* @return string|false
*/
public function convert($str, $reverse = false)
{
$encoding = $this->getEncoding();
$convertEncoding = $this->getConvertEncoding();
if ($convertEncoding === null) {
throw new Exception\LogicException(
'No convert encoding defined'
);
}
if ($encoding === $convertEncoding) {
return $str;
}
$fromEncoding = $reverse ? $convertEncoding : $encoding;
$toEncoding = $reverse ? $encoding : $convertEncoding;
return mb_convert_encoding($str, $toEncoding, $fromEncoding);
}
}
src/StringWrapper/Native.php 0000666 00000007314 13605043255 0012115 0 ustar 00 convertEncoding = $encodingUpper;
}
if ($convertEncoding !== null) {
if ($encodingUpper !== strtoupper($convertEncoding)) {
throw new Exception\InvalidArgumentException(
'Wrapper doesn\'t support to convert between character encodings'
);
}
$this->convertEncoding = $encodingUpper;
} else {
$this->convertEncoding = null;
}
$this->encoding = $encodingUpper;
return $this;
}
/**
* Returns the length of the given string
*
* @param string $str
* @return int|false
*/
public function strlen($str)
{
return strlen($str);
}
/**
* Returns the portion of string specified by the start and length parameters
*
* @param string $str
* @param int $offset
* @param int|null $length
* @return string|false
*/
public function substr($str, $offset = 0, $length = null)
{
return substr($str, $offset, $length);
}
/**
* Find the position of the first occurrence of a substring in a string
*
* @param string $haystack
* @param string $needle
* @param int $offset
* @return int|false
*/
public function strpos($haystack, $needle, $offset = 0)
{
return strpos($haystack, $needle, $offset);
}
}
src/StringWrapper/StringWrapperInterface.php 0000666 00000005757 13605043255 0015330 0 ustar 00