First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,3 @@
coverage_clover: clover.xml
json_path: coveralls-upload.json
src_dir: src

View file

@ -0,0 +1,229 @@
# CONTRIBUTING
## RESOURCES
If you wish to contribute to Zend Framework, please be sure to
read/subscribe to the following resources:
- [Coding Standards](https://github.com/zendframework/zf2/wiki/Coding-Standards)
- [Contributor's Guide](http://framework.zend.com/participate/contributor-guide)
- ZF Contributor's mailing list:
Archives: http://zend-framework-community.634137.n4.nabble.com/ZF-Contributor-f680267.html
Subscribe: zf-contributors-subscribe@lists.zend.com
- ZF Contributor's IRC channel:
#zftalk.dev on Freenode.net
If you are working on new features or refactoring [create a proposal](https://github.com/zendframework/zend-escaper/issues/new).
## Reporting Potential Security Issues
If you have encountered a potential security vulnerability, please **DO NOT** report it on the public
issue tracker: send it to us at [zf-security@zend.com](mailto:zf-security@zend.com) instead.
We will work with you to verify the vulnerability and patch it as soon as possible.
When reporting issues, please provide the following information:
- Component(s) affected
- A description indicating how to reproduce the issue
- A summary of the security vulnerability and impact
We request that you contact us via the email address above and give the project
contributors a chance to resolve the vulnerability and issue a new release prior
to any public exposure; this helps protect users and provides them with a chance
to upgrade and/or update in order to protect their applications.
For sensitive email communications, please use [our PGP key](http://framework.zend.com/zf-security-pgp-key.asc).
## RUNNING TESTS
> ### Note: testing versions prior to 2.4
>
> This component originates with Zend Framework 2. During the lifetime of ZF2,
> testing infrastructure migrated from PHPUnit 3 to PHPUnit 4. In most cases, no
> changes were necessary. However, due to the migration, tests may not run on
> versions < 2.4. As such, you may need to change the PHPUnit dependency if
> attempting a fix on such a version.
To run tests:
- Clone the repository:
```console
$ git clone git@github.com:zendframework/zend-escaper.git
$ cd
```
- Install dependencies via composer:
```console
$ curl -sS https://getcomposer.org/installer | php --
$ ./composer.phar install
```
If you don't have `curl` installed, you can also download `composer.phar` from https://getcomposer.org/
- Run the tests via `phpunit` and the provided PHPUnit config, like in this example:
```console
$ ./vendor/bin/phpunit
```
You can turn on conditional tests with the phpunit.xml file.
To do so:
- Copy `phpunit.xml.dist` file to `phpunit.xml`
- Edit `phpunit.xml` to enable any specific functionality you
want to test, as well as to provide test values to utilize.
## Running Coding Standards Checks
This component uses [php-cs-fixer](http://cs.sensiolabs.org/) for coding
standards checks, and provides configuration for our selected checks.
`php-cs-fixer` is installed by default via Composer.
To run checks only:
```console
$ ./vendor/bin/php-cs-fixer fix . -v --diff --dry-run --config-file=.php_cs
```
To have `php-cs-fixer` attempt to fix problems for you, omit the `--dry-run`
flag:
```console
$ ./vendor/bin/php-cs-fixer fix . -v --diff --config-file=.php_cs
```
If you allow php-cs-fixer to fix CS issues, please re-run the tests to ensure
they pass, and make sure you add and commit the changes after verification.
## Recommended Workflow for Contributions
Your first step is to establish a public repository from which we can
pull your work into the master repository. We recommend using
[GitHub](https://github.com), as that is where the component is already hosted.
1. Setup a [GitHub account](http://github.com/), if you haven't yet
2. Fork the repository (http://github.com/zendframework/zend-escaper)
3. Clone the canonical repository locally and enter it.
```console
$ git clone git://github.com:zendframework/zend-escaper.git
$ cd zend-escaper
```
4. Add a remote to your fork; substitute your GitHub username in the command
below.
```console
$ git remote add {username} git@github.com:{username}/zend-escaper.git
$ git fetch {username}
```
### Keeping Up-to-Date
Periodically, you should update your fork or personal repository to
match the canonical ZF repository. Assuming you have setup your local repository
per the instructions above, you can do the following:
```console
$ git checkout master
$ git fetch origin
$ git rebase origin/master
# OPTIONALLY, to keep your remote up-to-date -
$ git push {username} master:master
```
If you're tracking other branches -- for example, the "develop" branch, where
new feature development occurs -- you'll want to do the same operations for that
branch; simply substitute "develop" for "master".
### Working on a patch
We recommend you do each new feature or bugfix in a new branch. This simplifies
the task of code review as well as the task of merging your changes into the
canonical repository.
A typical workflow will then consist of the following:
1. Create a new local branch based off either your master or develop branch.
2. Switch to your new local branch. (This step can be combined with the
previous step with the use of `git checkout -b`.)
3. Do some work, commit, repeat as necessary.
4. Push the local branch to your remote repository.
5. Send a pull request.
The mechanics of this process are actually quite trivial. Below, we will
create a branch for fixing an issue in the tracker.
```console
$ git checkout -b hotfix/9295
Switched to a new branch 'hotfix/9295'
```
... do some work ...
```console
$ git commit
```
... write your log message ...
```console
$ git push {username} hotfix/9295:hotfix/9295
Counting objects: 38, done.
Delta compression using up to 2 threads.
Compression objects: 100% (18/18), done.
Writing objects: 100% (20/20), 8.19KiB, done.
Total 20 (delta 12), reused 0 (delta 0)
To ssh://git@github.com/{username}/zend-escaper.git
b5583aa..4f51698 HEAD -> master
```
To send a pull request, you have two options.
If using GitHub, you can do the pull request from there. Navigate to
your repository, select the branch you just created, and then select the
"Pull Request" button in the upper right. Select the user/organization
"zendframework" as the recipient.
If using your own repository - or even if using GitHub - you can use `git
format-patch` to create a patchset for us to apply; in fact, this is
**recommended** for security-related patches. If you use `format-patch`, please
send the patches as attachments to:
- zf-devteam@zend.com for patches without security implications
- zf-security@zend.com for security patches
#### What branch to issue the pull request against?
Which branch should you issue a pull request against?
- For fixes against the stable release, issue the pull request against the
"master" branch.
- For new features, or fixes that introduce new elements to the public API (such
as new public methods or properties), issue the pull request against the
"develop" branch.
### Branch Cleanup
As you might imagine, if you are a frequent contributor, you'll start to
get a ton of branches both locally and on your remote.
Once you know that your changes have been accepted to the master
repository, we suggest doing some cleanup of these branches.
- Local branch cleanup
```console
$ git branch -d <branchname>
```
- Remote branch removal
```console
$ git push {username} :<branchname>
```

View file

@ -0,0 +1,27 @@
Copyright (c) 2005-2015, Zend Technologies USA, Inc.
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 Zend Technologies USA, Inc. 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.

View file

@ -0,0 +1,11 @@
# zend-escaper
The OWASP Top 10 web security risks study lists Cross-Site Scripting (XSS) in
second place. PHPs sole functionality against XSS is limited to two functions
of which one is commonly misapplied. Thus, the `Zend\Escaper` component was written.
It offers developers a way to escape output and defend from XSS and related
vulnerabilities by introducing contextual escaping based on peer-reviewed rules.
- File issues at https://github.com/zendframework/zend-escaper/issues
- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-escaper

View file

@ -0,0 +1,34 @@
{
"name": "zendframework/zend-escaper",
"description": " ",
"license": "BSD-3-Clause",
"keywords": [
"zf2",
"escaper"
],
"homepage": "https://github.com/zendframework/zend-escaper",
"autoload": {
"psr-4": {
"Zend\\Escaper\\": "src/"
}
},
"require": {
"php": ">=5.3.23"
},
"extra": {
"branch-alias": {
"dev-master": "2.4-dev",
"dev-develop": "2.5-dev"
}
},
"autoload-dev": {
"psr-4": {
"ZendTest\\Escaper\\": "test/"
}
},
"require-dev": {
"fabpot/php-cs-fixer": "1.7.*",
"satooshi/php-coveralls": "dev-master",
"phpunit/PHPUnit": "~4.0"
}
}

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="./test/bootstrap.php"
colors="true">
<testsuites>
<testsuite name="zend-escaper Test Suite">
<directory>./test/</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>disable</group>
</exclude>
</groups>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
<php>
<ini name="date.timezone" value="UTC"/>
<!-- OB_ENABLED should be enabled for some tests to check if all
functionality works as expected. Such tests include those for
Zend\Soap and Zend\Session, which require that headers not be sent
in order to work. -->
<const name="TESTS_ZEND_OB_ENABLED" value="false" />
</php>
</phpunit>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="./test/bootstrap.php"
colors="true">
<testsuites>
<testsuite name="zend-escaper Test Suite">
<directory>./test/</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>disable</group>
</exclude>
</groups>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
<php>
<ini name="date.timezone" value="UTC"/>
<!-- OB_ENABLED should be enabled for some tests to check if all
functionality works as expected. Such tests include those for
Zend\Soap and Zend\Session, which require that headers not be sent
in order to work. -->
<const name="TESTS_ZEND_OB_ENABLED" value="false" />
</php>
</phpunit>

View file

@ -0,0 +1,386 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Escaper;
/**
* Context specific methods for use in secure output escaping
*/
class Escaper
{
/**
* Entity Map mapping Unicode codepoints to any available named HTML entities.
*
* While HTML supports far more named entities, the lowest common denominator
* has become HTML5's XML Serialisation which is restricted to the those named
* entities that XML supports. Using HTML entities would result in this error:
* XML Parsing Error: undefined entity
*
* @var array
*/
protected static $htmlNamedEntityMap = array(
34 => 'quot', // quotation mark
38 => 'amp', // ampersand
60 => 'lt', // less-than sign
62 => 'gt', // greater-than sign
);
/**
* Current encoding for escaping. If not UTF-8, we convert strings from this encoding
* pre-escaping and back to this encoding post-escaping.
*
* @var string
*/
protected $encoding = 'utf-8';
/**
* Holds the value of the special flags passed as second parameter to
* htmlspecialchars(). We modify these for PHP 5.4 to take advantage
* of the new ENT_SUBSTITUTE flag for correctly dealing with invalid
* UTF-8 sequences.
*
* @var string
*/
protected $htmlSpecialCharsFlags = ENT_QUOTES;
/**
* Static Matcher which escapes characters for HTML Attribute contexts
*
* @var callable
*/
protected $htmlAttrMatcher;
/**
* Static Matcher which escapes characters for Javascript contexts
*
* @var callable
*/
protected $jsMatcher;
/**
* Static Matcher which escapes characters for CSS Attribute contexts
*
* @var callable
*/
protected $cssMatcher;
/**
* List of all encoding supported by this class
*
* @var array
*/
protected $supportedEncodings = array(
'iso-8859-1', 'iso8859-1', 'iso-8859-5', 'iso8859-5',
'iso-8859-15', 'iso8859-15', 'utf-8', 'cp866',
'ibm866', '866', 'cp1251', 'windows-1251',
'win-1251', '1251', 'cp1252', 'windows-1252',
'1252', 'koi8-r', 'koi8-ru', 'koi8r',
'big5', '950', 'gb2312', '936',
'big5-hkscs', 'shift_jis', 'sjis', 'sjis-win',
'cp932', '932', 'euc-jp', 'eucjp',
'eucjp-win', 'macroman'
);
/**
* Constructor: Single parameter allows setting of global encoding for use by
* the current object. If PHP 5.4 is detected, additional ENT_SUBSTITUTE flag
* is set for htmlspecialchars() calls.
*
* @param string $encoding
* @throws Exception\InvalidArgumentException
*/
public function __construct($encoding = null)
{
if ($encoding !== null) {
$encoding = (string) $encoding;
if ($encoding === '') {
throw new Exception\InvalidArgumentException(
get_class($this) . ' constructor parameter does not allow a blank value'
);
}
$encoding = strtolower($encoding);
if (!in_array($encoding, $this->supportedEncodings)) {
throw new Exception\InvalidArgumentException(
'Value of \'' . $encoding . '\' passed to ' . get_class($this)
. ' constructor parameter is invalid. Provide an encoding supported by htmlspecialchars()'
);
}
$this->encoding = $encoding;
}
if (defined('ENT_SUBSTITUTE')) {
$this->htmlSpecialCharsFlags|= ENT_SUBSTITUTE;
}
// set matcher callbacks
$this->htmlAttrMatcher = array($this, 'htmlAttrMatcher');
$this->jsMatcher = array($this, 'jsMatcher');
$this->cssMatcher = array($this, 'cssMatcher');
}
/**
* Return the encoding that all output/input is expected to be encoded in.
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Escape a string for the HTML Body context where there are very few characters
* of special meaning. Internally this will use htmlspecialchars().
*
* @param string $string
* @return string
*/
public function escapeHtml($string)
{
return htmlspecialchars($string, $this->htmlSpecialCharsFlags, $this->encoding);
}
/**
* Escape a string for the HTML Attribute context. We use an extended set of characters
* to escape that are not covered by htmlspecialchars() to cover cases where an attribute
* might be unquoted or quoted illegally (e.g. backticks are valid quotes for IE).
*
* @param string $string
* @return string
*/
public function escapeHtmlAttr($string)
{
$string = $this->toUtf8($string);
if ($string === '' || ctype_digit($string)) {
return $string;
}
$result = preg_replace_callback('/[^a-z0-9,\.\-_]/iSu', $this->htmlAttrMatcher, $string);
return $this->fromUtf8($result);
}
/**
* Escape a string for the Javascript context. This does not use json_encode(). An extended
* set of characters are escaped beyond ECMAScript's rules for Javascript literal string
* escaping in order to prevent misinterpretation of Javascript as HTML leading to the
* injection of special characters and entities. The escaping used should be tolerant
* of cases where HTML escaping was not applied on top of Javascript escaping correctly.
* Backslash escaping is not used as it still leaves the escaped character as-is and so
* is not useful in a HTML context.
*
* @param string $string
* @return string
*/
public function escapeJs($string)
{
$string = $this->toUtf8($string);
if ($string === '' || ctype_digit($string)) {
return $string;
}
$result = preg_replace_callback('/[^a-z0-9,\._]/iSu', $this->jsMatcher, $string);
return $this->fromUtf8($result);
}
/**
* Escape a string for the URI or Parameter contexts. This should not be used to escape
* an entire URI - only a subcomponent being inserted. The function is a simple proxy
* to rawurlencode() which now implements RFC 3986 since PHP 5.3 completely.
*
* @param string $string
* @return string
*/
public function escapeUrl($string)
{
return rawurlencode($string);
}
/**
* Escape a string for the CSS context. CSS escaping can be applied to any string being
* inserted into CSS and escapes everything except alphanumerics.
*
* @param string $string
* @return string
*/
public function escapeCss($string)
{
$string = $this->toUtf8($string);
if ($string === '' || ctype_digit($string)) {
return $string;
}
$result = preg_replace_callback('/[^a-z0-9]/iSu', $this->cssMatcher, $string);
return $this->fromUtf8($result);
}
/**
* Callback function for preg_replace_callback that applies HTML Attribute
* escaping to all matches.
*
* @param array $matches
* @return string
*/
protected function htmlAttrMatcher($matches)
{
$chr = $matches[0];
$ord = ord($chr);
/**
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r")
|| ($ord >= 0x7f && $ord <= 0x9f)
) {
return '&#xFFFD;';
}
/**
* Check if the current character to escape has a name entity we should
* replace it with while grabbing the integer value of the character.
*/
if (strlen($chr) > 1) {
$chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8');
}
$hex = bin2hex($chr);
$ord = hexdec($hex);
if (isset(static::$htmlNamedEntityMap[$ord])) {
return '&' . static::$htmlNamedEntityMap[$ord] . ';';
}
/**
* Per OWASP recommendations, we'll use upper hex entities
* for any other characters where a named entity does not exist.
*/
if ($ord > 255) {
return sprintf('&#x%04X;', $ord);
}
return sprintf('&#x%02X;', $ord);
}
/**
* Callback function for preg_replace_callback that applies Javascript
* escaping to all matches.
*
* @param array $matches
* @return string
*/
protected function jsMatcher($matches)
{
$chr = $matches[0];
if (strlen($chr) == 1) {
return sprintf('\\x%02X', ord($chr));
}
$chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8');
return sprintf('\\u%04s', strtoupper(bin2hex($chr)));
}
/**
* Callback function for preg_replace_callback that applies CSS
* escaping to all matches.
*
* @param array $matches
* @return string
*/
protected function cssMatcher($matches)
{
$chr = $matches[0];
if (strlen($chr) == 1) {
$ord = ord($chr);
} else {
$chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8');
$ord = hexdec(bin2hex($chr));
}
return sprintf('\\%X ', $ord);
}
/**
* Converts a string to UTF-8 from the base encoding. The base encoding is set via this
* class' constructor.
*
* @param string $string
* @throws Exception\RuntimeException
* @return string
*/
protected function toUtf8($string)
{
if ($this->getEncoding() === 'utf-8') {
$result = $string;
} else {
$result = $this->convertEncoding($string, 'UTF-8', $this->getEncoding());
}
if (!$this->isUtf8($result)) {
throw new Exception\RuntimeException(
sprintf('String to be escaped was not valid UTF-8 or could not be converted: %s', $result)
);
}
return $result;
}
/**
* Converts a string from UTF-8 to the base encoding. The base encoding is set via this
* class' constructor.
* @param string $string
* @return string
*/
protected function fromUtf8($string)
{
if ($this->getEncoding() === 'utf-8') {
return $string;
}
return $this->convertEncoding($string, $this->getEncoding(), 'UTF-8');
}
/**
* Checks if a given string appears to be valid UTF-8 or not.
*
* @param string $string
* @return bool
*/
protected function isUtf8($string)
{
return ($string === '' || preg_match('/^./su', $string));
}
/**
* Encoding conversion helper which wraps iconv and mbstring where they exist or throws
* and exception where neither is available.
*
* @param string $string
* @param string $to
* @param array|string $from
* @throws Exception\RuntimeException
* @return string
*/
protected function convertEncoding($string, $to, $from)
{
if (function_exists('iconv')) {
$result = iconv($from, $to, $string);
} elseif (function_exists('mb_convert_encoding')) {
$result = mb_convert_encoding($string, $to, $from);
} else {
throw new Exception\RuntimeException(
get_class($this)
. ' requires either the iconv or mbstring extension to be installed'
. ' when escaping for non UTF-8 strings.'
);
}
if ($result === false) {
return ''; // return non-fatal blank string on encoding errors from users
}
return $result;
}
}

View file

@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Escaper\Exception;
interface ExceptionInterface
{
}

View file

@ -0,0 +1,18 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Escaper\Exception;
/**
* Invalid argument exception
*/
class InvalidArgumentException extends \InvalidArgumentException implements
ExceptionInterface
{
}

View file

@ -0,0 +1,18 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Escaper\Exception;
/**
* Invalid argument exception
*/
class RuntimeException extends \RuntimeException implements
ExceptionInterface
{
}

View file

@ -0,0 +1,3 @@
coverage_clover: clover.xml
json_path: coveralls-upload.json
src_dir: src

View file

@ -0,0 +1,23 @@
# Changelog
All notable changes to this project will be documented in this file, in reverse chronological order by release.
## 2.4.4 - 2015-07-21
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [#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.

View file

@ -0,0 +1,229 @@
# CONTRIBUTING
## RESOURCES
If you wish to contribute to Zend Framework, please be sure to
read/subscribe to the following resources:
- [Coding Standards](https://github.com/zendframework/zf2/wiki/Coding-Standards)
- [Contributor's Guide](http://framework.zend.com/participate/contributor-guide)
- ZF Contributor's mailing list:
Archives: http://zend-framework-community.634137.n4.nabble.com/ZF-Contributor-f680267.html
Subscribe: zf-contributors-subscribe@lists.zend.com
- ZF Contributor's IRC channel:
#zftalk.dev on Freenode.net
If you are working on new features or refactoring [create a proposal](https://github.com/zendframework/zend-stdlib/issues/new).
## Reporting Potential Security Issues
If you have encountered a potential security vulnerability, please **DO NOT** report it on the public
issue tracker: send it to us at [zf-security@zend.com](mailto:zf-security@zend.com) instead.
We will work with you to verify the vulnerability and patch it as soon as possible.
When reporting issues, please provide the following information:
- Component(s) affected
- A description indicating how to reproduce the issue
- A summary of the security vulnerability and impact
We request that you contact us via the email address above and give the project
contributors a chance to resolve the vulnerability and issue a new release prior
to any public exposure; this helps protect users and provides them with a chance
to upgrade and/or update in order to protect their applications.
For sensitive email communications, please use [our PGP key](http://framework.zend.com/zf-security-pgp-key.asc).
## RUNNING TESTS
> ### Note: testing versions prior to 2.4
>
> This component originates with Zend Framework 2. During the lifetime of ZF2,
> testing infrastructure migrated from PHPUnit 3 to PHPUnit 4. In most cases, no
> changes were necessary. However, due to the migration, tests may not run on
> versions < 2.4. As such, you may need to change the PHPUnit dependency if
> attempting a fix on such a version.
To run tests:
- Clone the repository:
```console
$ git clone git@github.com:zendframework/zend-stdlib.git
$ cd
```
- Install dependencies via composer:
```console
$ curl -sS https://getcomposer.org/installer | php --
$ ./composer.phar install
```
If you don't have `curl` installed, you can also download `composer.phar` from https://getcomposer.org/
- Run the tests via `phpunit` and the provided PHPUnit config, like in this example:
```console
$ ./vendor/bin/phpunit
```
You can turn on conditional tests with the phpunit.xml file.
To do so:
- Copy `phpunit.xml.dist` file to `phpunit.xml`
- Edit `phpunit.xml` to enable any specific functionality you
want to test, as well as to provide test values to utilize.
## Running Coding Standards Checks
This component uses [php-cs-fixer](http://cs.sensiolabs.org/) for coding
standards checks, and provides configuration for our selected checks.
`php-cs-fixer` is installed by default via Composer.
To run checks only:
```console
$ ./vendor/bin/php-cs-fixer fix . -v --diff --dry-run --config-file=.php_cs
```
To have `php-cs-fixer` attempt to fix problems for you, omit the `--dry-run`
flag:
```console
$ ./vendor/bin/php-cs-fixer fix . -v --diff --config-file=.php_cs
```
If you allow php-cs-fixer to fix CS issues, please re-run the tests to ensure
they pass, and make sure you add and commit the changes after verification.
## Recommended Workflow for Contributions
Your first step is to establish a public repository from which we can
pull your work into the master repository. We recommend using
[GitHub](https://github.com), as that is where the component is already hosted.
1. Setup a [GitHub account](http://github.com/), if you haven't yet
2. Fork the repository (http://github.com/zendframework/zend-stdlib)
3. Clone the canonical repository locally and enter it.
```console
$ git clone git://github.com:zendframework/zend-stdlib.git
$ cd zend-stdlib
```
4. Add a remote to your fork; substitute your GitHub username in the command
below.
```console
$ git remote add {username} git@github.com:{username}/zend-stdlib.git
$ git fetch {username}
```
### Keeping Up-to-Date
Periodically, you should update your fork or personal repository to
match the canonical ZF repository. Assuming you have setup your local repository
per the instructions above, you can do the following:
```console
$ git checkout master
$ git fetch origin
$ git rebase origin/master
# OPTIONALLY, to keep your remote up-to-date -
$ git push {username} master:master
```
If you're tracking other branches -- for example, the "develop" branch, where
new feature development occurs -- you'll want to do the same operations for that
branch; simply substitute "develop" for "master".
### Working on a patch
We recommend you do each new feature or bugfix in a new branch. This simplifies
the task of code review as well as the task of merging your changes into the
canonical repository.
A typical workflow will then consist of the following:
1. Create a new local branch based off either your master or develop branch.
2. Switch to your new local branch. (This step can be combined with the
previous step with the use of `git checkout -b`.)
3. Do some work, commit, repeat as necessary.
4. Push the local branch to your remote repository.
5. Send a pull request.
The mechanics of this process are actually quite trivial. Below, we will
create a branch for fixing an issue in the tracker.
```console
$ git checkout -b hotfix/9295
Switched to a new branch 'hotfix/9295'
```
... do some work ...
```console
$ git commit
```
... write your log message ...
```console
$ git push {username} hotfix/9295:hotfix/9295
Counting objects: 38, done.
Delta compression using up to 2 threads.
Compression objects: 100% (18/18), done.
Writing objects: 100% (20/20), 8.19KiB, done.
Total 20 (delta 12), reused 0 (delta 0)
To ssh://git@github.com/{username}/zend-stdlib.git
b5583aa..4f51698 HEAD -> master
```
To send a pull request, you have two options.
If using GitHub, you can do the pull request from there. Navigate to
your repository, select the branch you just created, and then select the
"Pull Request" button in the upper right. Select the user/organization
"zendframework" as the recipient.
If using your own repository - or even if using GitHub - you can use `git
format-patch` to create a patchset for us to apply; in fact, this is
**recommended** for security-related patches. If you use `format-patch`, please
send the patches as attachments to:
- zf-devteam@zend.com for patches without security implications
- zf-security@zend.com for security patches
#### What branch to issue the pull request against?
Which branch should you issue a pull request against?
- For fixes against the stable release, issue the pull request against the
"master" branch.
- For new features, or fixes that introduce new elements to the public API (such
as new public methods or properties), issue the pull request against the
"develop" branch.
### Branch Cleanup
As you might imagine, if you are a frequent contributor, you'll start to
get a ton of branches both locally and on your remote.
Once you know that your changes have been accepted to the master
repository, we suggest doing some cleanup of these branches.
- Local branch cleanup
```console
$ git branch -d <branchname>
```
- Remote branch removal
```console
$ git push {username} :<branchname>
```

View file

@ -0,0 +1,27 @@
Copyright (c) 2005-2015, Zend Technologies USA, Inc.
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 Zend Technologies USA, Inc. 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.

View file

@ -0,0 +1,15 @@
# zend-stdlib
`Zend\Stdlib` is a set of components that implements general purpose utility
class for different scopes like:
- array utilities functions;
- hydrators;
- json serialazible interfaces;
- general messaging systems;
- strin wrappers;
- etc
- File issues at https://github.com/zendframework/zend-stdlib/issues
- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-stdlib

View file

@ -0,0 +1,44 @@
{
"name": "zendframework/zend-stdlib",
"description": " ",
"license": "BSD-3-Clause",
"keywords": [
"zf2",
"stdlib"
],
"homepage": "https://github.com/zendframework/zend-stdlib",
"autoload": {
"psr-4": {
"Zend\\Stdlib\\": "src/"
}
},
"require": {
"php": ">=5.3.23"
},
"require-dev": {
"zendframework/zend-eventmanager": "self.version",
"zendframework/zend-serializer": "self.version",
"zendframework/zend-servicemanager": "self.version",
"zendframework/zend-filter": "self.version",
"fabpot/php-cs-fixer": "1.7.*",
"satooshi/php-coveralls": "dev-master",
"phpunit/PHPUnit": "~4.0"
},
"suggest": {
"zendframework/zend-eventmanager": "To support aggregate hydrator usage",
"zendframework/zend-serializer": "Zend\\Serializer component",
"zendframework/zend-servicemanager": "To support hydrator plugin manager usage",
"zendframework/zend-filter": "To support naming strategy hydrator usage"
},
"extra": {
"branch-alias": {
"dev-master": "2.4-dev",
"dev-develop": "2.5-dev"
}
},
"autoload-dev": {
"psr-4": {
"ZendTest\\Stdlib\\": "test/"
}
}
}

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="./test/bootstrap.php"
colors="true">
<testsuites>
<testsuite name="zend-stdlib Test Suite">
<directory>./test/</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>disable</group>
</exclude>
</groups>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
<php>
<ini name="date.timezone" value="UTC"/>
<!-- OB_ENABLED should be enabled for some tests to check if all
functionality works as expected. Such tests include those for
Zend\Soap and Zend\Session, which require that headers not be sent
in order to work. -->
<const name="TESTS_ZEND_OB_ENABLED" value="false" />
</php>
</phpunit>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="./test/bootstrap.php"
colors="true">
<testsuites>
<testsuite name="zend-stdlib Test Suite">
<directory>./test/</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>disable</group>
</exclude>
</groups>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
<php>
<ini name="date.timezone" value="UTC"/>
<!-- OB_ENABLED should be enabled for some tests to check if all
functionality works as expected. Such tests include those for
Zend\Soap and Zend\Session, which require that headers not be sent
in order to work. -->
<const name="TESTS_ZEND_OB_ENABLED" value="false" />
</php>
</phpunit>

View file

@ -0,0 +1,176 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use Traversable;
abstract class AbstractOptions implements ParameterObjectInterface
{
/**
* We use the __ prefix to avoid collisions with properties in
* user-implementations.
*
* @var bool
*/
protected $__strictMode__ = true;
/**
* Constructor
*
* @param array|Traversable|null $options
*/
public function __construct($options = null)
{
if (null !== $options) {
$this->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',
'Zend\Stdlib\AbstractOptions'
)
);
}
foreach ($options as $key => $value) {
$this->__set($key, $value);
}
return $this;
}
/**
* Cast to array
*
* @return array
*/
public function toArray()
{
$array = 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(array($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(array($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
);
}
}
}

View file

@ -0,0 +1,432 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use ArrayAccess;
use Countable;
use IteratorAggregate;
use Serializable;
/**
* Custom framework ArrayObject implementation
*
* Extends version-specific "abstract" implementation.
*/
class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable
{
/**
* Properties of the object have their normal functionality
* when accessed as list (var_dump, foreach, etc.).
*/
const STD_PROP_LIST = 1;
/**
* Entries can be accessed as properties (read and write).
*/
const ARRAY_AS_PROPS = 2;
/**
* @var array
*/
protected $storage;
/**
* @var int
*/
protected $flag;
/**
* @var string
*/
protected $iteratorClass;
/**
* @var array
*/
protected $protectedProperties;
/**
* Constructor
*
* @param array $input
* @param int $flags
* @param string $iteratorClass
*/
public function __construct($input = array(), $flags = self::STD_PROP_LIST, $iteratorClass = 'ArrayIterator')
{
$this->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);
}
}
}
}

View file

@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
interface ArraySerializableInterface
{
/**
* Exchange internal values from provided array
*
* @param array $array
* @return void
*/
public function exchangeArray(array $array);
/**
* Return an array representation of the object
*
* @return array
*/
public function getArrayCopy();
}

View file

@ -0,0 +1,33 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use ArrayIterator;
use ArrayObject as PhpArrayObject;
/**
* ArrayObject that acts as a stack with regards to iteration
*/
class ArrayStack extends PhpArrayObject
{
/**
* Retrieve iterator
*
* Retrieve an array copy of the object, reverse its order, and return an
* ArrayIterator with that reversed array.
*
* @return ArrayIterator
*/
public function getIterator()
{
$array = $this->getArrayCopy();
return new ArrayIterator(array_reverse($array));
}
}

View file

@ -0,0 +1,335 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use Traversable;
use Zend\Stdlib\ArrayUtils\MergeRemoveKey;
use Zend\Stdlib\ArrayUtils\MergeReplaceKeyInterface;
/**
* Utility class for testing and manipulation of PHP arrays.
*
* Declared abstract, as we have no need for instantiation.
*/
abstract class ArrayUtils
{
/**
* Compatibility Flag for ArrayUtils::filter
*/
const ARRAY_FILTER_USE_BOTH = 1;
/**
* Compatibility Flag for ArrayUtils::filter
*/
const ARRAY_FILTER_USE_KEY = 2;
/**
* Test whether an array contains one or more string keys
*
* @param mixed $value
* @param bool $allowEmpty Should an empty array() return true
* @return bool
*/
public static function hasStringKeys($value, $allowEmpty = false)
{
if (!is_array($value)) {
return false;
}
if (!$value) {
return $allowEmpty;
}
return count(array_filter(array_keys($value), 'is_string')) > 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:
* <code>
* $list = array('a', 'b', 'c', 'd');
* $list = array(
* 0 => 'foo',
* 1 => 'bar',
* 2 => array('foo' => 'baz'),
* );
* </code>
*
* @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:
* <code>
* $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 ),
* );
* </code>
*
* @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 = 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 = array();
foreach ($data as $key => $value) {
$params = array($value);
if ($flag === static::ARRAY_FILTER_USE_BOTH) {
$params[] = $key;
}
if ($flag === static::ARRAY_FILTER_USE_KEY) {
$params = array($key);
}
$response = call_user_func_array($callback, $params);
if ($response) {
$output[$key] = $value;
}
}
return $output;
}
}

View file

@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\ArrayUtils;
final class MergeRemoveKey
{
}

View file

@ -0,0 +1,34 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\ArrayUtils;
final class MergeReplaceKey implements MergeReplaceKeyInterface
{
/**
* @var mixed
*/
protected $data;
/**
* @param mixed $data
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* {@inheritDoc}
*/
public function getData()
{
return $this->data;
}
}

View file

@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\ArrayUtils;
/**
* Marker interface: can be used to replace keys completely in {@see ArrayUtils::merge()} operations
*/
interface MergeReplaceKeyInterface
{
/**
* @return mixed
*/
public function getData();
}

View file

@ -0,0 +1,217 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use ReflectionClass;
/**
* CallbackHandler
*
* A handler for an event, event, filterchain, etc. Abstracts PHP callbacks,
* primarily to allow for lazy-loading and ensuring availability of default
* arguments (currying).
*/
class CallbackHandler
{
/**
* @var string|array|callable PHP callback to invoke
*/
protected $callback;
/**
* Callback metadata, if any
* @var array
*/
protected $metadata;
/**
* PHP version is greater as 5.4rc1?
* @var bool
*/
protected static $isPhp54;
/**
* Constructor
*
* @param string|array|object|callable $callback PHP callback
* @param array $metadata Callback metadata
*/
public function __construct($callback, array $metadata = array())
{
$this->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 = array())
{
$callback = $this->getCallback();
// Minor performance tweak, if the callback gets called more than once
if (!isset(static::$isPhp54)) {
static::$isPhp54 = version_compare(PHP_VERSION, '5.4.0rc1', '>=');
}
$argCount = count($args);
if (static::$isPhp54 && 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:
if (static::$isPhp54) {
return $callback();
}
return call_user_func($callback);
case 1:
if (static::$isPhp54) {
return $callback(array_shift($args));
}
return call_user_func($callback, array_shift($args));
case 2:
$arg1 = array_shift($args);
$arg2 = array_shift($args);
if (static::$isPhp54) {
return $callback($arg1, $arg2);
}
return call_user_func($callback, $arg1, $arg2);
case 3:
$arg1 = array_shift($args);
$arg2 = array_shift($args);
$arg3 = array_shift($args);
if (static::$isPhp54) {
return $callback($arg1, $arg2, $arg3);
}
return call_user_func($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
*
* Validates that a static method call in PHP 5.4 will actually work
*
* @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 array($class, $method);
}
}

View file

@ -0,0 +1,47 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use DateTimeZone;
trigger_error('DateTime extension deprecated as of ZF 2.1.4; use the \DateTime constructor to parse extended ISO8601 dates instead', E_USER_DEPRECATED);
/**
* DateTime
*
* An extension of the \DateTime object.
*
* @deprecated
*/
class DateTime extends \DateTime
{
/**
* The DateTime::ISO8601 constant used by php's native DateTime object does
* not allow for fractions of a second. This function better handles ISO8601
* formatted date strings.
*
* @param string $time
* @param DateTimeZone $timezone
* @return mixed
*/
public static function createFromISO8601($time, DateTimeZone $timezone = null)
{
$format = self::ISO8601;
if (isset($time[19]) && $time[19] === '.') {
$format = 'Y-m-d\TH:i:s.uO';
}
if ($timezone !== null) {
return self::createFromFormat($format, $time, $timezone);
}
return self::createFromFormat($format, $time);
}
}

View file

@ -0,0 +1,22 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
interface DispatchableInterface
{
/**
* Dispatch a request
*
* @param RequestInterface $request
* @param null|ResponseInterface $response
* @return Response|mixed
*/
public function dispatch(RequestInterface $request, ResponseInterface $response = null);
}

View file

@ -0,0 +1,115 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use ErrorException;
/**
* ErrorHandler that can be used to catch internal PHP errors
* and convert to an ErrorException instance.
*/
abstract class ErrorHandler
{
/**
* Active stack
*
* @var array
*/
protected static $stack = array();
/**
* Check if this error handler is active
*
* @return bool
*/
public static function started()
{
return (bool) static::getNestedLevel();
}
/**
* Get the current nested level
*
* @return int
*/
public static function getNestedLevel()
{
return count(static::$stack);
}
/**
* Starting the error handler
*
* @param int $errorLevel
*/
public static function start($errorLevel = \E_WARNING)
{
if (!static::$stack) {
set_error_handler(array(get_called_class(), 'addError'), $errorLevel);
}
static::$stack[] = null;
}
/**
* Stopping the error handler
*
* @param bool $throw Throw the ErrorException if any
* @return null|ErrorException
* @throws ErrorException If an error has been catched and $throw is true
*/
public static function stop($throw = false)
{
$errorException = null;
if (static::$stack) {
$errorException = array_pop(static::$stack);
if (!static::$stack) {
restore_error_handler();
}
if ($errorException && $throw) {
throw $errorException;
}
}
return $errorException;
}
/**
* Stop all active handler
*
* @return void
*/
public static function clean()
{
if (static::$stack) {
restore_error_handler();
}
static::$stack = array();
}
/**
* Add an error to the stack
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return void
*/
public static function addError($errno, $errstr = '', $errfile = '', $errline = 0)
{
$stack = & static::$stack[count(static::$stack) - 1];
$stack = new ErrorException($errstr, 0, $errno, $errfile, $errline, $stack);
}
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Bad method call exception
*/
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Domain exception
*/
class DomainException extends \DomainException implements ExceptionInterface
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Exception marker interface
*/
interface ExceptionInterface
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Extension not loaded exception
*/
class ExtensionNotLoadedException extends RuntimeException
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Invalid Argument Exception
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Invalid callback exception
*/
class InvalidCallbackException extends DomainException implements ExceptionInterface
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Logic exception
*/
class LogicException extends \LogicException implements ExceptionInterface
{
}

View file

@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Exception;
/**
* Runtime exception
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View file

@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Extractor;
interface ExtractionInterface
{
/**
* Extract values from an object
*
* @param object $object
* @return array
*/
public function extract($object);
}

View file

@ -0,0 +1,202 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
/**
* Wrapper for glob with fallback if GLOB_BRACE is not available.
*/
abstract class Glob
{
/**#@+
* Glob constants.
*/
const GLOB_MARK = 0x01;
const GLOB_NOSORT = 0x02;
const GLOB_NOCHECK = 0x04;
const GLOB_NOESCAPE = 0x08;
const GLOB_BRACE = 0x10;
const GLOB_ONLYDIR = 0x20;
const GLOB_ERR = 0x40;
/**#@-*/
/**
* Find pathnames matching a pattern.
*
* @see http://docs.php.net/glob
* @param string $pattern
* @param int $flags
* @param bool $forceFallback
* @return array
* @throws Exception\RuntimeException
*/
public static function glob($pattern, $flags = 0, $forceFallback = false)
{
if (!defined('GLOB_BRACE') || $forceFallback) {
return static::fallbackGlob($pattern, $flags);
}
return static::systemGlob($pattern, $flags);
}
/**
* Use the glob function provided by the system.
*
* @param string $pattern
* @param int $flags
* @return array
* @throws Exception\RuntimeException
*/
protected static function systemGlob($pattern, $flags)
{
if ($flags) {
$flagMap = array(
self::GLOB_MARK => 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 = array();
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);
}
}

View file

@ -0,0 +1,20 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Guard;
/**
* An aggregate for all guard traits
*/
trait AllGuardsTrait
{
use ArrayOrTraversableGuardTrait;
use EmptyGuardTrait;
use NullGuardTrait;
}

View file

@ -0,0 +1,41 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Guard;
use Traversable;
/**
* Provide a guard method for array or Traversable data
*/
trait ArrayOrTraversableGuardTrait
{
/**
* Verifies that the data is an array or Traversable
*
* @param mixed $data the data to verify
* @param string $dataName the data name
* @param string $exceptionClass FQCN for the exception
* @throws \Exception
*/
protected function guardForArrayOrTraversable(
$data,
$dataName = 'Argument',
$exceptionClass = 'Zend\Stdlib\Exception\InvalidArgumentException'
) {
if (!is_array($data) && !($data instanceof Traversable)) {
$message = sprintf(
"%s must be an array or Traversable, [%s] given",
$dataName,
is_object($data) ? get_class($data) : gettype($data)
);
throw new $exceptionClass($message);
}
}
}

View file

@ -0,0 +1,35 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Guard;
/**
* Provide a guard method against empty data
*/
trait EmptyGuardTrait
{
/**
* Verify that the data is not empty
*
* @param mixed $data the data to verify
* @param string $dataName the data name
* @param string $exceptionClass FQCN for the exception
* @throws \Exception
*/
protected function guardAgainstEmpty(
$data,
$dataName = 'Argument',
$exceptionClass = 'Zend\Stdlib\Exception\InvalidArgumentException'
) {
if (empty($data)) {
$message = sprintf('%s cannot be empty', $dataName);
throw new $exceptionClass($message);
}
}
}

View file

@ -0,0 +1,85 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Guard;
use Traversable;
/**
* Static guard helper class
*
* Bridges the gap for allowing refactoring until traits can be used by default.
*
* @deprecated
*/
abstract class GuardUtils
{
const DEFAULT_EXCEPTION_CLASS = 'Zend\Stdlib\Exception\InvalidArgumentException';
/**
* Verifies that the data is an array or Traversable
*
* @param mixed $data the data to verify
* @param string $dataName the data name
* @param string $exceptionClass FQCN for the exception
* @throws \Exception
*/
public static function guardForArrayOrTraversable(
$data,
$dataName = 'Argument',
$exceptionClass = self::DEFAULT_EXCEPTION_CLASS
) {
if (!is_array($data) && !($data instanceof Traversable)) {
$message = sprintf(
'%s must be an array or Traversable, [%s] given',
$dataName,
is_object($data) ? get_class($data) : gettype($data)
);
throw new $exceptionClass($message);
}
}
/**
* Verify that the data is not empty
*
* @param mixed $data the data to verify
* @param string $dataName the data name
* @param string $exceptionClass FQCN for the exception
* @throws \Exception
*/
public static function guardAgainstEmpty(
$data,
$dataName = 'Argument',
$exceptionClass = self::DEFAULT_EXCEPTION_CLASS
) {
if (empty($data)) {
$message = sprintf('%s cannot be empty', $dataName);
throw new $exceptionClass($message);
}
}
/**
* Verify that the data is not null
*
* @param mixed $data the data to verify
* @param string $dataName the data name
* @param string $exceptionClass FQCN for the exception
* @throws \Exception
*/
public static function guardAgainstNull(
$data,
$dataName = 'Argument',
$exceptionClass = self::DEFAULT_EXCEPTION_CLASS
) {
if (null === $data) {
$message = sprintf('%s cannot be null', $dataName);
throw new $exceptionClass($message);
}
}
}

View file

@ -0,0 +1,35 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Guard;
/**
* Provide a guard method against null data
*/
trait NullGuardTrait
{
/**
* Verify that the data is not null
*
* @param mixed $data the data to verify
* @param string $dataName the data name
* @param string $exceptionClass FQCN for the exception
* @throws \Exception
*/
protected function guardAgainstNull(
$data,
$dataName = 'Argument',
$exceptionClass = 'Zend\Stdlib\Exception\InvalidArgumentException'
) {
if (null === $data) {
$message = sprintf('%s cannot be null', $dataName);
throw new $exceptionClass($message);
}
}
}

View file

@ -0,0 +1,287 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use ArrayObject;
use Zend\Stdlib\Exception;
use Zend\Stdlib\Hydrator\Filter\FilterComposite;
use Zend\Stdlib\Hydrator\NamingStrategy\NamingStrategyInterface;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;
abstract class AbstractHydrator implements
HydratorInterface,
StrategyEnabledInterface,
FilterEnabledInterface,
NamingStrategyEnabledInterface
{
/**
* The list with strategies that this hydrator has.
*
* @var ArrayObject
*/
protected $strategies;
/**
* An instance of NamingStrategyInterface
*
* @var NamingStrategyInterface
*/
protected $namingStrategy;
/**
* Composite to filter the methods, that need to be hydrated
*
* @var Filter\FilterComposite
*/
protected $filterComposite;
/**
* Initializes a new instance of this class.
*/
public function __construct()
{
$this->strategies = new ArrayObject();
$this->filterComposite = new FilterComposite();
}
/**
* Gets the strategy with the given name.
*
* @param string $name The name of the strategy to get.
*
* @throws \Zend\Stdlib\Exception\InvalidArgumentException
* @return StrategyInterface
*/
public function getStrategy($name)
{
if (isset($this->strategies[$name])) {
return $this->strategies[$name];
}
if (!isset($this->strategies['*'])) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: no strategy by name of "%s", and no wildcard strategy present',
__METHOD__,
$name
));
}
return $this->strategies['*'];
}
/**
* Checks if the strategy with the given name exists.
*
* @param string $name The name of the strategy to check for.
* @return bool
*/
public function hasStrategy($name)
{
return array_key_exists($name, $this->strategies)
|| array_key_exists('*', $this->strategies);
}
/**
* Adds the given strategy under the given name.
*
* @param string $name The name of the strategy to register.
* @param StrategyInterface $strategy The strategy to register.
* @return HydratorInterface
*/
public function addStrategy($name, StrategyInterface $strategy)
{
$this->strategies[$name] = $strategy;
return $this;
}
/**
* Removes the strategy with the given name.
*
* @param string $name The name of the strategy to remove.
* @return HydratorInterface
*/
public function removeStrategy($name)
{
unset($this->strategies[$name]);
return $this;
}
/**
* Converts a value for extraction. If no strategy exists the plain value is returned.
*
* @param string $name The name of the strategy to use.
* @param mixed $value The value that should be converted.
* @param mixed $object The object is optionally provided as context.
* @return mixed
*/
public function extractValue($name, $value, $object = null)
{
if ($this->hasStrategy($name)) {
$strategy = $this->getStrategy($name);
$value = $strategy->extract($value, $object);
}
return $value;
}
/**
* Converts a value for hydration. If no strategy exists the plain value is returned.
*
* @param string $name The name of the strategy to use.
* @param mixed $value The value that should be converted.
* @param array $data The whole data is optionally provided as context.
* @return mixed
*/
public function hydrateValue($name, $value, $data = null)
{
if ($this->hasStrategy($name)) {
$strategy = $this->getStrategy($name);
$value = $strategy->hydrate($value, $data);
}
return $value;
}
/**
* Convert a name for extraction. If no naming strategy exists, the plain value is returned.
*
* @param string $name The name to convert.
* @param null $object The object is optionally provided as context.
* @return mixed
*/
public function extractName($name, $object = null)
{
if ($this->hasNamingStrategy()) {
$name = $this->getNamingStrategy()->extract($name, $object);
}
return $name;
}
/**
* Converts a value for hydration. If no naming strategy exists, the plain value is returned.
*
* @param string $name The name to convert.
* @param array $data The whole data is optionally provided as context.
* @return mixed
*/
public function hydrateName($name, $data = null)
{
if ($this->hasNamingStrategy()) {
$name = $this->getNamingStrategy()->hydrate($name, $data);
}
return $name;
}
/**
* Get the filter instance
*
* @return Filter\FilterComposite
*/
public function getFilter()
{
return $this->filterComposite;
}
/**
* Add a new filter to take care of what needs to be hydrated.
* To exclude e.g. the method getServiceLocator:
*
* <code>
* $composite->addFilter("servicelocator",
* function ($property) {
* list($class, $method) = explode('::', $property);
* if ($method === 'getServiceLocator') {
* return false;
* }
* return true;
* }, FilterComposite::CONDITION_AND
* );
* </code>
*
* @param string $name Index in the composite
* @param callable|Filter\FilterInterface $filter
* @param int $condition
* @return Filter\FilterComposite
*/
public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR)
{
return $this->filterComposite->addFilter($name, $filter, $condition);
}
/**
* Check whether a specific filter exists at key $name or not
*
* @param string $name Index in the composite
* @return bool
*/
public function hasFilter($name)
{
return $this->filterComposite->hasFilter($name);
}
/**
* Remove a filter from the composition.
* To not extract "has" methods, you simply need to unregister it
*
* <code>
* $filterComposite->removeFilter('has');
* </code>
*
* @param $name
* @return Filter\FilterComposite
*/
public function removeFilter($name)
{
return $this->filterComposite->removeFilter($name);
}
/**
* Adds the given naming strategy
*
* @param NamingStrategyInterface $strategy The naming to register.
* @return self
*/
public function setNamingStrategy(NamingStrategyInterface $strategy)
{
$this->namingStrategy = $strategy;
return $this;
}
/**
* Gets the naming strategy.
*
* @return NamingStrategyInterface
*/
public function getNamingStrategy()
{
return $this->namingStrategy;
}
/**
* Checks if a naming strategy exists.
*
* @return bool
*/
public function hasNamingStrategy()
{
return isset($this->namingStrategy);
}
/**
* Removes the naming strategy
*
* @return self
*/
public function removeNamingStrategy()
{
$this->namingStrategy = null;
return $this;
}
}

View file

@ -0,0 +1,85 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Aggregate;
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\Stdlib\Hydrator\HydratorInterface;
/**
* Aggregate hydrator that composes multiple hydrators via events
*/
class AggregateHydrator implements HydratorInterface, EventManagerAwareInterface
{
const DEFAULT_PRIORITY = 1;
/**
* @var \Zend\EventManager\EventManagerInterface|null
*/
protected $eventManager;
/**
* Attaches the provided hydrator to the list of hydrators to be used while hydrating/extracting data
*
* @param \Zend\Stdlib\Hydrator\HydratorInterface $hydrator
* @param int $priority
*/
public function add(HydratorInterface $hydrator, $priority = self::DEFAULT_PRIORITY)
{
$this->getEventManager()->attachAggregate(new HydratorListener($hydrator), $priority);
}
/**
* {@inheritDoc}
*/
public function extract($object)
{
$event = new ExtractEvent($this, $object);
$this->getEventManager()->trigger($event);
return $event->getExtractedData();
}
/**
* {@inheritDoc}
*/
public function hydrate(array $data, $object)
{
$event = new HydrateEvent($this, $object, $data);
$this->getEventManager()->trigger($event);
return $event->getHydratedObject();
}
/**
* {@inheritDoc}
*/
public function setEventManager(EventManagerInterface $eventManager)
{
$eventManager->setIdentifiers(array(__CLASS__, get_class($this)));
$this->eventManager = $eventManager;
}
/**
* {@inheritDoc}
*/
public function getEventManager()
{
if (null === $this->eventManager) {
$this->setEventManager(new EventManager());
}
return $this->eventManager;
}
}

View file

@ -0,0 +1,98 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Aggregate;
use Zend\EventManager\Event;
/**
* Event triggered when the {@see \Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator} extracts
* data from an object
*/
class ExtractEvent extends Event
{
const EVENT_EXTRACT = 'extract';
/**
* {@inheritDoc}
*/
protected $name = self::EVENT_EXTRACT;
/**
* @var object
*/
protected $extractionObject;
/**
* @var array
*/
protected $extractedData = array();
/**
* @param object $target
* @param object $extractionObject
*/
public function __construct($target, $extractionObject)
{
$this->target = $target;
$this->extractionObject = $extractionObject;
}
/**
* Retrieves the object from which data is extracted
*
* @return object
*/
public function getExtractionObject()
{
return $this->extractionObject;
}
/**
* @param object $extractionObject
*
* @return void
*/
public function setExtractionObject($extractionObject)
{
$this->extractionObject = $extractionObject;
}
/**
* Retrieves the data that has been extracted
*
* @return array
*/
public function getExtractedData()
{
return $this->extractedData;
}
/**
* @param array $extractedData
*
* @return void
*/
public function setExtractedData(array $extractedData)
{
$this->extractedData = $extractedData;
}
/**
* Merge provided data with the extracted data
*
* @param array $additionalData
*
* @return void
*/
public function mergeExtractedData(array $additionalData)
{
$this->extractedData = array_merge($this->extractedData, $additionalData);
}
}

View file

@ -0,0 +1,84 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Aggregate;
use Zend\EventManager\Event;
/**
* Event triggered when the {@see \Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator} hydrates
* data into an object
*/
class HydrateEvent extends Event
{
const EVENT_HYDRATE = 'hydrate';
/**
* {@inheritDoc}
*/
protected $name = self::EVENT_HYDRATE;
/**
* @var object
*/
protected $hydratedObject;
/**
* @var array
*/
protected $hydrationData;
/**
* @param object $target
* @param object $hydratedObject
* @param array $hydrationData
*/
public function __construct($target, $hydratedObject, array $hydrationData)
{
$this->target = $target;
$this->hydratedObject = $hydratedObject;
$this->hydrationData = $hydrationData;
}
/**
* Retrieves the object that is being hydrated
*
* @return object
*/
public function getHydratedObject()
{
return $this->hydratedObject;
}
/**
* @param object $hydratedObject
*/
public function setHydratedObject($hydratedObject)
{
$this->hydratedObject = $hydratedObject;
}
/**
* Retrieves the data that is being used for hydration
*
* @return array
*/
public function getHydrationData()
{
return $this->hydrationData;
}
/**
* @param array $hydrationData
*/
public function setHydrationData(array $hydrationData)
{
$this->hydrationData = $hydrationData;
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Aggregate;
use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventManagerInterface;
use Zend\Stdlib\Hydrator\HydratorInterface;
/**
* Aggregate listener wrapping around a hydrator. Listens
* to {@see \Zend\Stdlib\Hydrator\Aggregate::EVENT_HYDRATE} and
* {@see \Zend\Stdlib\Hydrator\Aggregate::EVENT_EXTRACT}
*/
class HydratorListener extends AbstractListenerAggregate
{
/**
* @var \Zend\Stdlib\Hydrator\HydratorInterface
*/
protected $hydrator;
/**
* @param \Zend\Stdlib\Hydrator\HydratorInterface $hydrator
*/
public function __construct(HydratorInterface $hydrator)
{
$this->hydrator = $hydrator;
}
/**
* {@inheritDoc}
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$this->listeners[] = $events->attach(HydrateEvent::EVENT_HYDRATE, array($this, 'onHydrate'), $priority);
$this->listeners[] = $events->attach(ExtractEvent::EVENT_EXTRACT, array($this, 'onExtract'), $priority);
}
/**
* Callback to be used when {@see \Zend\Stdlib\Hydrator\Aggregate\HydrateEvent::EVENT_HYDRATE} is triggered
*
* @param \Zend\Stdlib\Hydrator\Aggregate\HydrateEvent $event
*
* @return object
*
* @internal
*/
public function onHydrate(HydrateEvent $event)
{
$object = $this->hydrator->hydrate($event->getHydrationData(), $event->getHydratedObject());
$event->setHydratedObject($object);
return $object;
}
/**
* Callback to be used when {@see \Zend\Stdlib\Hydrator\Aggregate\ExtractEvent::EVENT_EXTRACT} is triggered
*
* @param \Zend\Stdlib\Hydrator\Aggregate\ExtractEvent $event
*
* @return array
*
* @internal
*/
public function onExtract(ExtractEvent $event)
{
$data = $this->hydrator->extract($event->getExtractionObject());
$event->mergeExtractedData($data);
return $data;
}
}

View file

@ -0,0 +1,83 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\Stdlib\Exception;
class ArraySerializable extends AbstractHydrator
{
/**
* Extract values from the provided object
*
* Extracts values via the object's getArrayCopy() method.
*
* @param object $object
* @return array
* @throws Exception\BadMethodCallException for an $object not implementing getArrayCopy()
*/
public function extract($object)
{
if (!is_callable(array($object, 'getArrayCopy'))) {
throw new Exception\BadMethodCallException(
sprintf('%s expects the provided object to implement getArrayCopy()', __METHOD__)
);
}
$data = $object->getArrayCopy();
$filter = $this->getFilter();
foreach ($data as $name => $value) {
if (!$filter->filter($name)) {
unset($data[$name]);
continue;
}
$extractedName = $this->extractName($name, $object);
// replace the original key with extracted, if differ
if ($extractedName !== $name) {
unset($data[$name]);
$name = $extractedName;
}
$data[$name] = $this->extractValue($name, $value, $object);
}
return $data;
}
/**
* Hydrate an object
*
* Hydrates an object by passing $data to either its exchangeArray() or
* populate() method.
*
* @param array $data
* @param object $object
* @return object
* @throws Exception\BadMethodCallException for an $object not implementing exchangeArray() or populate()
*/
public function hydrate(array $data, $object)
{
$replacement = array();
foreach ($data as $key => $value) {
$name = $this->hydrateName($key, $data);
$replacement[$name] = $this->hydrateValue($name, $value, $data);
}
if (is_callable(array($object, 'exchangeArray'))) {
$object->exchangeArray($replacement);
} elseif (is_callable(array($object, 'populate'))) {
$object->populate($replacement);
} else {
throw new Exception\BadMethodCallException(
sprintf('%s expects the provided object to implement exchangeArray() or populate()', __METHOD__)
);
}
return $object;
}
}

View file

@ -0,0 +1,274 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Traversable;
use Zend\Stdlib\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\Hydrator\Filter\FilterComposite;
use Zend\Stdlib\Hydrator\Filter\FilterProviderInterface;
use Zend\Stdlib\Hydrator\Filter\GetFilter;
use Zend\Stdlib\Hydrator\Filter\HasFilter;
use Zend\Stdlib\Hydrator\Filter\IsFilter;
use Zend\Stdlib\Hydrator\Filter\MethodMatchFilter;
use Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter;
use Zend\Stdlib\Hydrator\NamingStrategy\NamingStrategyInterface;
use Zend\Stdlib\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface
{
/**
* Holds the names of the methods used for hydration, indexed by class::property name,
* false if the hydration method is not callable/usable for hydration purposes
*
* @var string[]|bool[]
*/
private $hydrationMethodsCache = array();
/**
* A map of extraction methods to property name to be used during extraction, indexed
* by class name and method name
*
* @var string[][]
*/
private $extractionMethodsCache = array();
/**
* Flag defining whether array keys are underscore-separated (true) or camel case (false)
*
* @var bool
*/
protected $underscoreSeparatedKeys = true;
/**
* @var \Zend\Stdlib\Hydrator\Filter\FilterInterface
*/
private $callableMethodFilter;
/**
* Define if extract values will use camel case or name with underscore
* @param bool|array $underscoreSeparatedKeys
*/
public function __construct($underscoreSeparatedKeys = true)
{
parent::__construct();
$this->setUnderscoreSeparatedKeys($underscoreSeparatedKeys);
$this->callableMethodFilter = new OptionalParametersFilter();
$this->filterComposite->addFilter('is', new IsFilter());
$this->filterComposite->addFilter('has', new HasFilter());
$this->filterComposite->addFilter('get', new GetFilter());
$this->filterComposite->addFilter('parameter', new OptionalParametersFilter(), FilterComposite::CONDITION_AND);
}
/**
* @param array|Traversable $options
* @return ClassMethods
* @throws Exception\InvalidArgumentException
*/
public function setOptions($options)
{
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
} elseif (!is_array($options)) {
throw new Exception\InvalidArgumentException(
'The options parameter must be an array or a Traversable'
);
}
if (isset($options['underscoreSeparatedKeys'])) {
$this->setUnderscoreSeparatedKeys($options['underscoreSeparatedKeys']);
}
return $this;
}
/**
* @param bool $underscoreSeparatedKeys
* @return ClassMethods
*/
public function setUnderscoreSeparatedKeys($underscoreSeparatedKeys)
{
$this->underscoreSeparatedKeys = (bool) $underscoreSeparatedKeys;
if ($this->underscoreSeparatedKeys) {
$this->setNamingStrategy(new UnderscoreNamingStrategy);
} elseif ($this->getNamingStrategy() instanceof UnderscoreNamingStrategy) {
$this->removeNamingStrategy();
}
return $this;
}
/**
* @return bool
*/
public function getUnderscoreSeparatedKeys()
{
return $this->underscoreSeparatedKeys;
}
/**
* Extract values from an object with class methods
*
* Extracts the getter/setter of the given $object.
*
* @param object $object
* @return array
* @throws Exception\BadMethodCallException for a non-object $object
*/
public function extract($object)
{
if (!is_object($object)) {
throw new Exception\BadMethodCallException(sprintf(
'%s expects the provided $object to be a PHP object)',
__METHOD__
));
}
$objectClass = get_class($object);
// reset the hydrator's hydrator's cache for this object, as the filter may be per-instance
if ($object instanceof FilterProviderInterface) {
$this->extractionMethodsCache[$objectClass] = null;
}
// pass 1 - finding out which properties can be extracted, with which methods (populate hydration cache)
if (! isset($this->extractionMethodsCache[$objectClass])) {
$this->extractionMethodsCache[$objectClass] = array();
$filter = $this->filterComposite;
$methods = get_class_methods($object);
if ($object instanceof FilterProviderInterface) {
$filter = new FilterComposite(
array($object->getFilter()),
array(new MethodMatchFilter('getFilter'))
);
}
foreach ($methods as $method) {
$methodFqn = $objectClass . '::' . $method;
if (! ($filter->filter($methodFqn) && $this->callableMethodFilter->filter($methodFqn))) {
continue;
}
$attribute = $method;
if (strpos($method, 'get') === 0) {
$attribute = substr($method, 3);
if (!property_exists($object, $attribute)) {
$attribute = lcfirst($attribute);
}
}
$this->extractionMethodsCache[$objectClass][$method] = $attribute;
}
}
$values = array();
// pass 2 - actually extract data
foreach ($this->extractionMethodsCache[$objectClass] as $methodName => $attributeName) {
$realAttributeName = $this->extractName($attributeName, $object);
$values[$realAttributeName] = $this->extractValue($realAttributeName, $object->$methodName(), $object);
}
return $values;
}
/**
* Hydrate an object by populating getter/setter methods
*
* Hydrates an object by getter/setter methods of the object.
*
* @param array $data
* @param object $object
* @return object
* @throws Exception\BadMethodCallException for a non-object $object
*/
public function hydrate(array $data, $object)
{
if (!is_object($object)) {
throw new Exception\BadMethodCallException(sprintf(
'%s expects the provided $object to be a PHP object)',
__METHOD__
));
}
$objectClass = get_class($object);
foreach ($data as $property => $value) {
$propertyFqn = $objectClass . '::$' . $property;
if (! isset($this->hydrationMethodsCache[$propertyFqn])) {
$setterName = 'set' . ucfirst($this->hydrateName($property, $data));
$this->hydrationMethodsCache[$propertyFqn] = is_callable(array($object, $setterName))
? $setterName
: false;
}
if ($this->hydrationMethodsCache[$propertyFqn]) {
$object->{$this->hydrationMethodsCache[$propertyFqn]}($this->hydrateValue($property, $value, $data));
}
}
return $object;
}
/**
* {@inheritDoc}
*/
public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR)
{
$this->resetCaches();
return parent::addFilter($name, $filter, $condition);
}
/**
* {@inheritDoc}
*/
public function removeFilter($name)
{
$this->resetCaches();
return parent::removeFilter($name);
}
/**
* {@inheritDoc}
*/
public function setNamingStrategy(NamingStrategyInterface $strategy)
{
$this->resetCaches();
return parent::setNamingStrategy($strategy);
}
/**
* {@inheritDoc}
*/
public function removeNamingStrategy()
{
$this->resetCaches();
return parent::removeNamingStrategy();
}
/**
* Reset all local hydration/extraction caches
*/
private function resetCaches()
{
$this->hydrationMethodsCache = $this->extractionMethodsCache = array();
}
}

View file

@ -0,0 +1,57 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\ServiceManager\ServiceLocatorInterface;
class DelegatingHydrator implements HydratorInterface
{
/**
* @var ServiceLocatorInterface
*/
protected $hydrators;
/**
* Constructor
*
* @param ServiceLocatorInterface $hydrators
*/
public function __construct(ServiceLocatorInterface $hydrators)
{
$this->hydrators = $hydrators;
}
/**
* {@inheritdoc}
*/
public function hydrate(array $data, $object)
{
return $this->getHydrator($object)->hydrate($data, $object);
}
/**
* {@inheritdoc}
*/
public function extract($object)
{
return $this->getHydrator($object)->extract($object);
}
/**
* Gets hydrator of an object
*
* @param object $object
* @return HydratorInterface
*/
protected function getHydrator($object)
{
return $this->hydrators->get(get_class($object));
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class DelegatingHydratorFactory implements FactoryInterface
{
/**
* Creates DelegatingHydrator
*
* @param ServiceLocatorInterface $serviceLocator
* @return DelegatingHydrator
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
// Assume that this factory is registered with the HydratorManager,
// and just pass it directly on.
return new DelegatingHydrator($serviceLocator);
}
}

View file

@ -0,0 +1,196 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
use ArrayObject;
use Zend\Stdlib\Exception\InvalidArgumentException;
class FilterComposite implements FilterInterface
{
/**
* @var ArrayObject
*/
protected $orFilter;
/**
* @var ArrayObject
*/
protected $andFilter;
/**
* Constant to add with "or" conditition
*/
const CONDITION_OR = 1;
/**
* Constant to add with "and" conditition
*/
const CONDITION_AND = 2;
/**
* Define default Filter
*
* @param array $orFilter
* @param array $andFilter
* @throws InvalidArgumentException
*/
public function __construct($orFilter = array(), $andFilter = array())
{
array_walk(
$orFilter,
function ($value, $key) {
if (!is_callable($value) && !$value instanceof FilterInterface) {
throw new InvalidArgumentException(
'The value of ' . $key . ' should be either a callable or ' .
'an instance of Zend\Stdlib\Hydrator\Filter\FilterInterface'
);
}
}
);
array_walk(
$andFilter,
function ($value, $key) {
if (!is_callable($value) && !$value instanceof FilterInterface) {
throw new InvalidArgumentException(
'The value of ' . $key . ' should be either a callable or ' .
'an instance of Zend\Stdlib\Hydrator\Filter\FilterInterface'
);
}
}
);
$this->orFilter = new ArrayObject($orFilter);
$this->andFilter = new ArrayObject($andFilter);
}
/**
* Add a filter to the composite. Has to be indexed with $name in
* order to identify a specific filter.
*
* This example will exclude all methods from the hydration, that starts with 'getService'
* <code>
* $composite->addFilter('exclude',
* function ($method) {
* if (preg_match('/^getService/', $method) {
* return false;
* }
* return true;
* }, FilterComposite::CONDITION_AND
* );
* </code>
*
* @param string $name
* @param callable|FilterInterface $filter
* @param int $condition Can be either FilterComposite::CONDITION_OR or FilterComposite::CONDITION_AND
* @throws InvalidArgumentException
* @return FilterComposite
*/
public function addFilter($name, $filter, $condition = self::CONDITION_OR)
{
if (!is_callable($filter) && !($filter instanceof FilterInterface)) {
throw new InvalidArgumentException(
'The value of ' . $name . ' should be either a callable or ' .
'an instance of Zend\Stdlib\Hydrator\Filter\FilterInterface'
);
}
if ($condition === self::CONDITION_OR) {
$this->orFilter[$name] = $filter;
} elseif ($condition === self::CONDITION_AND) {
$this->andFilter[$name] = $filter;
}
return $this;
}
/**
* Remove a filter from the composition
*
* @param $name string Identifier for the filter
* @return FilterComposite
*/
public function removeFilter($name)
{
if (isset($this->orFilter[$name])) {
unset($this->orFilter[$name]);
}
if (isset($this->andFilter[$name])) {
unset($this->andFilter[$name]);
}
return $this;
}
/**
* Check if $name has a filter registered
*
* @param $name string Identifier for the filter
* @return bool
*/
public function hasFilter($name)
{
return isset($this->orFilter[$name]) || isset($this->andFilter[$name]);
}
/**
* Filter the composite based on the AND and OR condition
* Will return true if one from the "or conditions" and all from
* the "and condition" returns true. Otherwise false
*
* @param $property string Parameter will be e.g. Parent\Namespace\Class::method
* @return bool
*/
public function filter($property)
{
$andCount = count($this->andFilter);
$orCount = count($this->orFilter);
// return true if no filters are registered
if ($orCount === 0 && $andCount === 0) {
return true;
} elseif ($orCount === 0 && $andCount !== 0) {
$returnValue = true;
} else {
$returnValue = false;
}
// Check if 1 from the or filters return true
foreach ($this->orFilter as $filter) {
if (is_callable($filter)) {
if ($filter($property) === true) {
$returnValue = true;
break;
}
continue;
} else {
if ($filter->filter($property) === true) {
$returnValue = true;
break;
}
}
}
// Check if all of the and condition return true
foreach ($this->andFilter as $filter) {
if (is_callable($filter)) {
if ($filter($property) === false) {
return false;
}
continue;
} else {
if ($filter->filter($property) === false) {
return false;
}
}
}
return $returnValue;
}
}

View file

@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
interface FilterInterface
{
/**
* Should return true, if the given filter
* does not match
*
* @param string $property The name of the property
* @return bool
*/
public function filter($property);
}

View file

@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
interface FilterProviderInterface
{
/**
* Provides a filter for hydration
*
* @return FilterInterface
*/
public function getFilter();
}

View file

@ -0,0 +1,27 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
class GetFilter implements FilterInterface
{
public function filter($property)
{
$pos = strpos($property, '::');
if ($pos !== false) {
$pos += 2;
} else {
$pos = 0;
}
if (substr($property, $pos, 3) === 'get') {
return true;
}
return false;
}
}

View file

@ -0,0 +1,27 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
class HasFilter implements FilterInterface
{
public function filter($property)
{
$pos = strpos($property, '::');
if ($pos !== false) {
$pos += 2;
} else {
$pos = 0;
}
if (substr($property, $pos, 3) === 'has') {
return true;
}
return false;
}
}

View file

@ -0,0 +1,27 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
class IsFilter implements FilterInterface
{
public function filter($property)
{
$pos = strpos($property, '::');
if ($pos !== false) {
$pos += 2;
} else {
$pos = 0;
}
if (substr($property, $pos, 2) === 'is') {
return true;
}
return false;
}
}

View file

@ -0,0 +1,48 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
class MethodMatchFilter implements FilterInterface
{
/**
* The method to exclude
* @var string
*/
protected $method = null;
/**
* Either an exclude or an include
* @var bool
*/
protected $exclude = null;
/**
* @param string $method The method to exclude or include
* @param bool $exclude If the method should be excluded
*/
public function __construct($method, $exclude = true)
{
$this->method = $method;
$this->exclude = $exclude;
}
public function filter($property)
{
$pos = strpos($property, '::');
if ($pos !== false) {
$pos += 2;
} else {
$pos = 0;
}
if (substr($property, $pos) === $this->method) {
return !$this->exclude;
}
return $this->exclude;
}
}

View file

@ -0,0 +1,49 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
use ReflectionException;
use ReflectionMethod;
use Zend\Stdlib\Exception\InvalidArgumentException;
class NumberOfParameterFilter implements FilterInterface
{
/**
* The number of parameters beeing accepted
* @var int
*/
protected $numberOfParameters = null;
/**
* @param int $numberOfParameters Number of accepted parameters
*/
public function __construct($numberOfParameters = 0)
{
$this->numberOfParameters = (int) $numberOfParameters;
}
/**
* @param string $property the name of the property
* @return bool
* @throws InvalidArgumentException
*/
public function filter($property)
{
try {
$reflectionMethod = new ReflectionMethod($property);
} catch (ReflectionException $exception) {
throw new InvalidArgumentException(
"Method $property doesn't exist"
);
}
return $reflectionMethod->getNumberOfParameters() === $this->numberOfParameters;
}
}

View file

@ -0,0 +1,54 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;
use InvalidArgumentException;
use ReflectionException;
use ReflectionMethod;
use ReflectionParameter;
/**
* Filter that includes methods which have no parameters or only optional parameters
*/
class OptionalParametersFilter implements FilterInterface
{
/**
* Map of methods already analyzed
* by {@see \Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter::filter()},
* cached for performance reasons
*
* @var bool[]
*/
protected static $propertiesCache = array();
/**
* {@inheritDoc}
*/
public function filter($property)
{
if (isset(static::$propertiesCache[$property])) {
return static::$propertiesCache[$property];
}
try {
$reflectionMethod = new ReflectionMethod($property);
} catch (ReflectionException $exception) {
throw new InvalidArgumentException(sprintf('Method %s doesn\'t exist', $property));
}
$mandatoryParameters = array_filter(
$reflectionMethod->getParameters(),
function (ReflectionParameter $parameter) {
return ! $parameter->isOptional();
}
);
return static::$propertiesCache[$property] = empty($mandatoryParameters);
}
}

View file

@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\Stdlib\Hydrator\Filter\FilterInterface;
use Zend\Stdlib\Hydrator\Filter\FilterComposite;
use Zend\Stdlib\Hydrator\Filter\FilterProviderInterface;
interface FilterEnabledInterface extends FilterProviderInterface
{
/**
* Add a new filter to take care of what needs to be hydrated.
* To exclude e.g. the method getServiceLocator:
*
* <code>
* $composite->addFilter(
* "servicelocator",
* function ($property) {
* list($class, $method) = explode('::', $property);
* if ($method === 'getServiceLocator') {
* return false;
* }
* return true;
* },
* FilterComposite::CONDITION_AND
* );
* </code>
*
* @param string $name Index in the composite
* @param callable|FilterInterface $filter
* @param int $condition
* @return FilterComposite
*/
public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR);
/**
* Check whether a specific filter exists at key $name or not
*
* @param string $name Index in the composite
* @return bool
*/
public function hasFilter($name);
/**
* Remove a filter from the composition.
* To not extract "has" methods, you simply need to unregister it
*
* <code>
* $filterComposite->removeFilter('has');
* </code>
*
* @param $name
* @return FilterComposite
*/
public function removeFilter($name);
}

View file

@ -0,0 +1,22 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
interface HydrationInterface
{
/**
* Hydrate $object with the provided $data.
*
* @param array $data
* @param object $object
* @return object
*/
public function hydrate(array $data, $object);
}

View file

@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
interface HydratorAwareInterface
{
/**
* Set hydrator
*
* @param HydratorInterface $hydrator
* @return HydratorAwareInterface
*/
public function setHydrator(HydratorInterface $hydrator);
/**
* Retrieve hydrator
*
* @return HydratorInterface
*/
public function getHydrator();
}

View file

@ -0,0 +1,47 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
trait HydratorAwareTrait
{
/**
* Hydrator instance
*
* @var HydratorInterface
* @access protected
*/
protected $hydrator = null;
/**
* Set hydrator
*
* @param HydratorInterface $hydrator
* @return self
* @access public
*/
public function setHydrator(HydratorInterface $hydrator)
{
$this->hydrator = $hydrator;
return $this;
}
/**
* Retrieve hydrator
*
* @param void
* @return null|HydratorInterface
* @access public
*/
public function getHydrator()
{
return $this->hydrator;
}
}

View file

@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\Stdlib\Extractor\ExtractionInterface;
interface HydratorInterface extends HydrationInterface, ExtractionInterface
{
}

View file

@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
interface HydratorOptionsInterface
{
/**
* @param array|\Traversable $options
* @return HydratorOptionsInterface
*/
public function setOptions($options);
}

View file

@ -0,0 +1,74 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\ServiceManager\AbstractPluginManager;
use Zend\Stdlib\Exception;
/**
* Plugin manager implementation for hydrators.
*
* Enforces that adapters retrieved are instances of HydratorInterface
*/
class HydratorPluginManager extends AbstractPluginManager
{
/**
* Whether or not to share by default
*
* @var bool
*/
protected $shareByDefault = false;
/**
* Default aliases
*
* @var array
*/
protected $aliases = array(
'delegatinghydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydrator',
);
/**
* Default set of adapters
*
* @var array
*/
protected $invokableClasses = array(
'arrayserializable' => 'Zend\Stdlib\Hydrator\ArraySerializable',
'classmethods' => 'Zend\Stdlib\Hydrator\ClassMethods',
'objectproperty' => 'Zend\Stdlib\Hydrator\ObjectProperty',
'reflection' => 'Zend\Stdlib\Hydrator\Reflection'
);
/**
* Default factory-based adapters
*
* @var array
*/
protected $factories = array(
'Zend\Stdlib\Hydrator\DelegatingHydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydratorFactory',
);
/**
* {@inheritDoc}
*/
public function validatePlugin($plugin)
{
if ($plugin instanceof HydratorInterface) {
// we're okay
return;
}
throw new Exception\RuntimeException(sprintf(
'Plugin of type %s is invalid; must implement Zend\Stdlib\Hydrator\HydratorInterface',
(is_object($plugin) ? get_class($plugin) : gettype($plugin))
));
}
}

View file

@ -0,0 +1,51 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\NamingStrategy;
final class ArrayMapNamingStrategy implements NamingStrategyInterface
{
/**
* @var string[]
*/
private $extractionMap = array();
/**
* @var string[]
*/
private $hydrationMap = array();
/**
* Constructor
*
* @param array $extractionMap A map of string keys and values for symmetric translation of hydrated
* and extracted field names
*/
public function __construct(array $extractionMap)
{
$this->extractionMap = $extractionMap;
$this->hydrationMap = array_flip($extractionMap);
}
/**
* {@inheritDoc}
*/
public function hydrate($name)
{
return isset($this->hydrationMap[$name]) ? $this->hydrationMap[$name] : $name;
}
/**
* {@inheritDoc}
*/
public function extract($name)
{
return isset($this->extractionMap[$name]) ? $this->extractionMap[$name] : $name;
}
}

View file

@ -0,0 +1,64 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\NamingStrategy;
final class CompositeNamingStrategy implements NamingStrategyInterface
{
/**
* @var array
*/
private $namingStrategies = array();
/**
* @var NamingStrategyInterface
*/
private $defaultNamingStrategy;
/**
* @param NamingStrategyInterface[] $strategies indexed by the name they translate
* @param NamingStrategyInterface|null $defaultNamingStrategy
*/
public function __construct(array $strategies, NamingStrategyInterface $defaultNamingStrategy = null)
{
$this->namingStrategies = array_map(
function (NamingStrategyInterface $strategy) {
// this callback is here only to ensure type-safety
return $strategy;
},
$strategies
);
$this->defaultNamingStrategy = $defaultNamingStrategy ?: new IdentityNamingStrategy();
}
/**
* {@inheritDoc}
*/
public function extract($name)
{
$strategy = isset($this->namingStrategies[$name])
? $this->namingStrategies[$name]
: $this->defaultNamingStrategy;
return $strategy->extract($name);
}
/**
* {@inheritDoc}
*/
public function hydrate($name)
{
$strategy = isset($this->namingStrategies[$name])
? $this->namingStrategies[$name]
: $this->defaultNamingStrategy;
return $strategy->hydrate($name);
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\NamingStrategy;
final class IdentityNamingStrategy implements NamingStrategyInterface
{
/**
* {@inheritDoc}
*/
public function hydrate($name)
{
return $name;
}
/**
* {@inheritDoc}
*/
public function extract($name)
{
return $name;
}
}

View file

@ -0,0 +1,89 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\NamingStrategy;
use Zend\Stdlib\Exception\InvalidArgumentException;
class MapNamingStrategy implements NamingStrategyInterface
{
/**
* Map for hydrate name conversion.
*
* @var array
*/
protected $mapping = array();
/**
* Reversed map for extract name conversion.
*
* @var array
*/
protected $reverse = array();
/**
* Initialize.
*
* @param array $mapping Map for name conversion on hydration
* @param array $reverse Reverse map for name conversion on extraction
*/
public function __construct(array $mapping, array $reverse = null)
{
$this->mapping = $mapping;
$this->reverse = $reverse ?: $this->flipMapping($mapping);
}
/**
* Safelly flip mapping array.
*
* @param array $array Array to flip
* @return array Flipped array
* @throws InvalidArgumentException
*/
protected function flipMapping(array $array)
{
array_walk($array, function ($value) {
if (!is_string($value) && !is_int($value)) {
throw new InvalidArgumentException('Mapping array can\'t be flipped because of invalid value');
}
});
return array_flip($array);
}
/**
* Converts the given name so that it can be extracted by the hydrator.
*
* @param string $name The original name
* @return mixed The hydrated name
*/
public function hydrate($name)
{
if (array_key_exists($name, $this->mapping)) {
return $this->mapping[$name];
}
return $name;
}
/**
* Converts the given name so that it can be hydrated by the hydrator.
*
* @param string $name The original name
* @return mixed The extracted name
*/
public function extract($name)
{
if (array_key_exists($name, $this->reverse)) {
return $this->reverse[$name];
}
return $name;
}
}

View file

@ -0,0 +1,37 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\NamingStrategy;
/**
* Allow property extraction / hydration for hydrator
*
* Interface PropertyStrategyInterface
* @package Zend\Stdlib\Hydrator\NamingStrategy
*/
interface NamingStrategyInterface
{
/**
* Converts the given name so that it can be extracted by the hydrator.
*
* @param string $name The original name
* @param object $object (optional) The original object for context.
* @return mixed The hydrated name
*/
public function hydrate($name);
/**
* Converts the given name so that it can be hydrated by the hydrator.
*
* @param string $name The original name
* @param array $data (optional) The original data for context.
* @return mixed The extracted name
*/
public function extract($name);
}

View file

@ -0,0 +1,80 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\NamingStrategy;
use Zend\Filter\FilterChain;
class UnderscoreNamingStrategy implements NamingStrategyInterface
{
/**
* @var FilterChain|null
*/
protected static $camelCaseToUnderscoreFilter;
/**
* @var FilterChain|null
*/
protected static $underscoreToStudlyCaseFilter;
/**
* Remove underscores and capitalize letters
*
* @param string $name
* @return string
*/
public function hydrate($name)
{
return $this->getUnderscoreToStudlyCaseFilter()->filter($name);
}
/**
* Remove capitalized letters and prepend underscores.
*
* @param string $name
* @return string
*/
public function extract($name)
{
return $this->getCamelCaseToUnderscoreFilter()->filter($name);
}
/**
* @return FilterChain
*/
protected function getUnderscoreToStudlyCaseFilter()
{
if (static::$underscoreToStudlyCaseFilter instanceof FilterChain) {
return static::$underscoreToStudlyCaseFilter;
}
$filter = new FilterChain();
$filter->attachByName('WordUnderscoreToStudlyCase');
return static::$underscoreToStudlyCaseFilter = $filter;
}
/**
* @return FilterChain
*/
protected function getCamelCaseToUnderscoreFilter()
{
if (static::$camelCaseToUnderscoreFilter instanceof FilterChain) {
return static::$camelCaseToUnderscoreFilter;
}
$filter = new FilterChain();
$filter->attachByName('WordCamelCaseToUnderscore');
$filter->attachByName('StringToLower');
return static::$camelCaseToUnderscoreFilter = $filter;
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\Stdlib\Hydrator\NamingStrategy\NamingStrategyInterface;
interface NamingStrategyEnabledInterface
{
/**
* Adds the given naming strategy
*
* @param NamingStrategyInterface $strategy The naming to register.
* @return NamingStrategyEnabledInterface
*/
public function setNamingStrategy(NamingStrategyInterface $strategy);
/**
* Gets the naming strategy.
*
* @return NamingStrategyInterface
*/
public function getNamingStrategy();
/**
* Checks if a naming strategy exists.
*
* @return bool
*/
public function hasNamingStrategy();
/**
* Removes the naming with the given name.
*
* @return NamingStrategyEnabledInterface
*/
public function removeNamingStrategy();
}

View file

@ -0,0 +1,110 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\Stdlib\Exception;
use ReflectionClass;
use ReflectionProperty;
class ObjectProperty extends AbstractHydrator
{
/**
* @var array[] indexed by class name and then property name
*/
private static $skippedPropertiesCache = array();
/**
* {@inheritDoc}
*
* Extracts the accessible non-static properties of the given $object.
*
* @throws Exception\BadMethodCallException for a non-object $object
*/
public function extract($object)
{
if (!is_object($object)) {
throw new Exception\BadMethodCallException(
sprintf('%s expects the provided $object to be a PHP object)', __METHOD__)
);
}
$data = get_object_vars($object);
$filter = $this->getFilter();
foreach ($data as $name => $value) {
// Filter keys, removing any we don't want
if (! $filter->filter($name)) {
unset($data[$name]);
continue;
}
// Replace name if extracted differ
$extracted = $this->extractName($name, $object);
if ($extracted !== $name) {
unset($data[$name]);
$name = $extracted;
}
$data[$name] = $this->extractValue($name, $value, $object);
}
return $data;
}
/**
* {@inheritDoc}
*
* Hydrate an object by populating public properties
*
* Hydrates an object by setting public properties of the object.
*
* @throws Exception\BadMethodCallException for a non-object $object
*/
public function hydrate(array $data, $object)
{
if (!is_object($object)) {
throw new Exception\BadMethodCallException(
sprintf('%s expects the provided $object to be a PHP object)', __METHOD__)
);
}
$properties = & self::$skippedPropertiesCache[get_class($object)];
if (! isset($properties)) {
$reflection = new ReflectionClass($object);
$properties = array_fill_keys(
array_map(
function (ReflectionProperty $property) {
return $property->getName();
},
$reflection->getProperties(
ReflectionProperty::IS_PRIVATE
+ ReflectionProperty::IS_PROTECTED
+ ReflectionProperty::IS_STATIC
)
),
true
);
}
foreach ($data as $name => $value) {
$property = $this->hydrateName($name, $data);
if (isset($properties[$property])) {
continue;
}
$object->$property = $this->hydrateValue($property, $value, $data);
}
return $object;
}
}

View file

@ -0,0 +1,95 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use ReflectionClass;
use Zend\Stdlib\Exception;
class Reflection extends AbstractHydrator
{
/**
* Simple in-memory array cache of ReflectionProperties used.
* @var \ReflectionProperty[]
*/
protected static $reflProperties = array();
/**
* Extract values from an object
*
* @param object $object
* @return array
*/
public function extract($object)
{
$result = array();
foreach (self::getReflProperties($object) as $property) {
$propertyName = $this->extractName($property->getName(), $object);
if (!$this->filterComposite->filter($propertyName)) {
continue;
}
$value = $property->getValue($object);
$result[$propertyName] = $this->extractValue($propertyName, $value, $object);
}
return $result;
}
/**
* Hydrate $object with the provided $data.
*
* @param array $data
* @param object $object
* @return object
*/
public function hydrate(array $data, $object)
{
$reflProperties = self::getReflProperties($object);
foreach ($data as $key => $value) {
$name = $this->hydrateName($key, $data);
if (isset($reflProperties[$name])) {
$reflProperties[$name]->setValue($object, $this->hydrateValue($name, $value, $data));
}
}
return $object;
}
/**
* Get a reflection properties from in-memory cache and lazy-load if
* class has not been loaded.
*
* @param string|object $input
* @throws Exception\InvalidArgumentException
* @return \ReflectionProperty[]
*/
protected static function getReflProperties($input)
{
if (is_object($input)) {
$input = get_class($input);
} elseif (!is_string($input)) {
throw new Exception\InvalidArgumentException('Input must be a string or an object.');
}
if (isset(static::$reflProperties[$input])) {
return static::$reflProperties[$input];
}
static::$reflProperties[$input] = array();
$reflClass = new ReflectionClass($input);
$reflProperties = $reflClass->getProperties();
foreach ($reflProperties as $property) {
$property->setAccessible(true);
static::$reflProperties[$input][$property->getName()] = $property;
}
return static::$reflProperties[$input];
}
}

View file

@ -0,0 +1,106 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
use Zend\Stdlib\Exception\InvalidArgumentException;
/**
* This Strategy extracts and hydrates int and string values to Boolean values
*
* @package Zend\Stdlib\Hydrator\Strategy
*/
final class BooleanStrategy implements StrategyInterface
{
/**
* @var int|string
*/
private $trueValue;
/**
* @var int|string
*/
private $falseValue;
/**
* @param int|string $trueValue
* @param int|string $falseValue
* @throws InvalidArgumentException
*/
public function __construct($trueValue, $falseValue)
{
if (!is_int($trueValue) && !is_string($trueValue)) {
throw new InvalidArgumentException(sprintf(
'Unable to instantiate BooleanStrategy. Expected int or string as $trueValue. %s was given',
is_object($trueValue) ? get_class($trueValue) : gettype($trueValue)
));
}
if (!is_int($falseValue) && !is_string($falseValue)) {
throw new InvalidArgumentException(sprintf(
'Unable to instantiate BooleanStrategy. Expected int or string as $falseValue. %s was given',
is_object($falseValue) ? get_class($falseValue) : gettype($falseValue)
));
}
$this->trueValue = $trueValue;
$this->falseValue = $falseValue;
}
/**
* Converts the given value so that it can be extracted by the hydrator.
*
* @param bool $value The original value.
* @throws InvalidArgumentException
* @return int|string Returns the value that should be extracted.
*/
public function extract($value)
{
if (!is_bool($value)) {
throw new InvalidArgumentException(sprintf(
'Unable to extract. Expected bool. %s was given.',
is_object($value) ? get_class($value) : gettype($value)
));
}
return $value === true ? $this->trueValue : $this->falseValue;
}
/**
* Converts the given value so that it can be hydrated by the hydrator.
*
* @param int|string $value The original value.
* @throws InvalidArgumentException
* @return bool Returns the value that should be hydrated.
*/
public function hydrate($value)
{
if (!is_string($value) && !is_int($value)) {
throw new InvalidArgumentException(sprintf(
'Unable to hydrate. Expected string or int. %s was given.',
is_object($value) ? get_class($value) : gettype($value)
));
}
if ($value === $this->trueValue) {
return true;
}
if ($value === $this->falseValue) {
return false;
}
throw new InvalidArgumentException(sprintf(
'Unexpected value %s can\'t be hydrated. Expect %s or %s as Value.',
$value,
$this->trueValue,
$this->falseValue
));
}
}

View file

@ -0,0 +1,102 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
class ClosureStrategy implements StrategyInterface
{
/**
* Function, used in extract method, default:
* function ($value) {
* return $value;
* };
* @var callable
*/
protected $extractFunc = null;
/**
* Function, used in hydrate method, default:
* function ($value) {
* return $value;
* };
* @var callable
*/
protected $hydrateFunc = null;
/**
* You can describe how your values will extract and hydrate, like this:
* $hydrator->addStrategy('category', new ClosureStrategy(
* function (Category $value) {
* return (int) $value->id;
* },
* function ($value) {
* return new Category((int) $value);
* }
* ));
*
* @param callable $extractFunc - anonymous function, that extract values
* from object
* @param callable $hydrateFunc - anonymous function, that hydrate values
* into object
*/
public function __construct($extractFunc = null, $hydrateFunc = null)
{
if (isset($extractFunc)) {
if (!is_callable($extractFunc)) {
throw new \Exception('$extractFunc must be callable');
}
$this->extractFunc = $extractFunc;
} else {
$this->extractFunc = function ($value) {
return $value;
};
}
if (isset($hydrateFunc)) {
if (!is_callable($hydrateFunc)) {
throw new \Exception('$hydrateFunc must be callable');
}
$this->hydrateFunc = $hydrateFunc;
} else {
$this->hydrateFunc = function ($value) {
return $value;
};
}
}
/**
* Converts the given value so that it can be extracted by the hydrator.
*
* @param mixed $value The original value.
* @param array $object The object is optionally provided as context.
* @return mixed Returns the value that should be extracted.
*/
public function extract($value, $object = null)
{
$func = $this->extractFunc;
return $func($value, $object);
}
/**
* Converts the given value so that it can be hydrated by the hydrator.
*
* @param mixed $value The original value.
* @param array $data The whole data is optionally provided as context.
* @return mixed Returns the value that should be hydrated.
*/
public function hydrate($value, $data = null)
{
$func = $this->hydrateFunc;
return $func($value, $data);
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
use DateTime;
use DateTimeZone;
final class DateTimeFormatterStrategy implements StrategyInterface
{
/**
* @var string
*/
private $format;
/**
* @var DateTimeZone|null
*/
private $timezone;
/**
* Constructor
*
* @param string $format
* @param DateTimeZone|null $timezone
*/
public function __construct($format = DateTime::RFC3339, DateTimeZone $timezone = null)
{
$this->format = (string) $format;
$this->timezone = $timezone;
}
/**
* {@inheritDoc}
*
* Converts to date time string
*
* @param mixed|DateTime $value
*
* @return mixed|string
*/
public function extract($value)
{
if ($value instanceof DateTime) {
return $value->format($this->format);
}
return $value;
}
/**
* Converts date time string to DateTime instance for injecting to object
*
* {@inheritDoc}
*
* @param mixed|string $value
*
* @return mixed|DateTime
*/
public function hydrate($value)
{
if ($value === '' || $value === null) {
return;
}
if ($this->timezone) {
$hydrated = DateTime::createFromFormat($this->format, $value, $this->timezone);
} else {
$hydrated = DateTime::createFromFormat($this->format, $value);
}
return $hydrated ?: $value;
}
}

View file

@ -0,0 +1,35 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
class DefaultStrategy implements StrategyInterface
{
/**
* Converts the given value so that it can be extracted by the hydrator.
*
* @param mixed $value The original value.
* @return mixed Returns the value that should be extracted.
*/
public function extract($value)
{
return $value;
}
/**
* Converts the given value so that it can be hydrated by the hydrator.
*
* @param mixed $value The original value.
* @return mixed Returns the value that should be hydrated.
*/
public function hydrate($value)
{
return $value;
}
}

View file

@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy\Exception;
interface ExceptionInterface
{
}

View file

@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View file

@ -0,0 +1,113 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
final class ExplodeStrategy implements StrategyInterface
{
/**
* @var string
*/
private $valueDelimiter;
/**
* @var int|null
*/
private $explodeLimit;
/**
* Constructor
*
* @param string $delimiter String that the values will be split upon
* @param int|null $explodeLimit Explode limit
*/
public function __construct($delimiter = ',', $explodeLimit = null)
{
$this->setValueDelimiter($delimiter);
$this->explodeLimit = ($explodeLimit === null) ? null : (int) $explodeLimit;
}
/**
* Sets the delimiter string that the values will be split upon
*
* @param string $delimiter
* @return self
*/
private function setValueDelimiter($delimiter)
{
if (!is_string($delimiter)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects Delimiter to be string, %s provided instead',
__METHOD__,
is_object($delimiter) ? get_class($delimiter) : gettype($delimiter)
));
}
if (empty($delimiter)) {
throw new Exception\InvalidArgumentException('Delimiter cannot be empty.');
}
$this->valueDelimiter = $delimiter;
}
/**
* {@inheritDoc}
*
* Split a string by delimiter
*
* @param string|null $value
*
* @return string[]
*
* @throws Exception\InvalidArgumentException
*/
public function hydrate($value)
{
if (null === $value) {
return array();
}
if (!(is_string($value) || is_numeric($value))) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects argument 1 to be string, %s provided instead',
__METHOD__,
is_object($value) ? get_class($value) : gettype($value)
));
}
if ($this->explodeLimit !== null) {
return explode($this->valueDelimiter, $value, $this->explodeLimit);
}
return explode($this->valueDelimiter, $value);
}
/**
* {@inheritDoc}
*
* Join array elements with delimiter
*
* @param string[] $value The original value.
*
* @return string|null
*/
public function extract($value)
{
if (!is_array($value)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects argument 1 to be array, %s provided instead',
__METHOD__,
is_object($value) ? get_class($value) : gettype($value)
));
}
return empty($value) ? null : implode($this->valueDelimiter, $value);
}
}

View file

@ -0,0 +1,123 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
use Zend\Stdlib\Exception\InvalidArgumentException;
use Zend\Serializer\Adapter\AdapterInterface as SerializerAdapter;
use Zend\Serializer\Serializer as SerializerFactory;
class SerializableStrategy implements StrategyInterface
{
/**
* @var string|SerializerAdapter
*/
protected $serializer;
/**
* @var array
*/
protected $serializerOptions = array();
/**
*
* @param mixed $serializer string or SerializerAdapter
* @param mixed $serializerOptions
*/
public function __construct($serializer, $serializerOptions = null)
{
$this->setSerializer($serializer);
if ($serializerOptions) {
$this->setSerializerOptions($serializerOptions);
}
}
/**
* Serialize the given value so that it can be extracted by the hydrator.
*
* @param mixed $value The original value.
* @return mixed Returns the value that should be extracted.
*/
public function extract($value)
{
$serializer = $this->getSerializer();
return $serializer->serialize($value);
}
/**
* Unserialize the given value so that it can be hydrated by the hydrator.
*
* @param mixed $value The original value.
* @return mixed Returns the value that should be hydrated.
*/
public function hydrate($value)
{
$serializer = $this->getSerializer();
return $serializer->unserialize($value);
}
/**
* Set serializer
*
* @param string|SerializerAdapter $serializer
* @return SerializableStrategy
*/
public function setSerializer($serializer)
{
if (!is_string($serializer) && !$serializer instanceof SerializerAdapter) {
throw new InvalidArgumentException(sprintf(
'%s expects either a string serializer name or Zend\Serializer\Adapter\AdapterInterface instance; '
. 'received "%s"',
__METHOD__,
(is_object($serializer) ? get_class($serializer) : gettype($serializer))
));
}
$this->serializer = $serializer;
return $this;
}
/**
* Get serializer
*
* @return SerializerAdapter
*/
public function getSerializer()
{
if (is_string($this->serializer)) {
$options = $this->getSerializerOptions();
$this->setSerializer(SerializerFactory::factory($this->serializer, $options));
} elseif (null === $this->serializer) {
$this->setSerializer(SerializerFactory::getDefaultAdapter());
}
return $this->serializer;
}
/**
* Set configuration options for instantiating a serializer adapter
*
* @param mixed $serializerOptions
* @return SerializableStrategy
*/
public function setSerializerOptions($serializerOptions)
{
$this->serializerOptions = $serializerOptions;
return $this;
}
/**
* Get configuration options for instantiating a serializer adapter
*
* @return mixed
*/
public function getSerializerOptions()
{
return $this->serializerOptions;
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
use Traversable;
use Zend\Stdlib\ArrayUtils;
final class StrategyChain implements StrategyInterface
{
/**
* Strategy chain for extraction
*
* @var StrategyInterface[]
*/
private $extractionStrategies;
/**
* Strategy chain for hydration
*
* @var StrategyInterface[]
*/
private $hydrationStrategies;
/**
* Constructor
*
* @param array|Traversable $extractionStrategies
*/
public function __construct($extractionStrategies)
{
$extractionStrategies = ArrayUtils::iteratorToArray($extractionStrategies);
$this->extractionStrategies = array_map(
function (StrategyInterface $strategy) {
// this callback is here only to ensure type-safety
return $strategy;
},
$extractionStrategies
);
$this->hydrationStrategies = array_reverse($extractionStrategies);
}
/**
* {@inheritDoc}
*/
public function extract($value)
{
foreach ($this->extractionStrategies as $strategy) {
$value = $strategy->extract($value);
}
return $value;
}
/**
* {@inheritDoc}
*/
public function hydrate($value)
{
foreach ($this->hydrationStrategies as $strategy) {
$value = $strategy->hydrate($value);
}
return $value;
}
}

View file

@ -0,0 +1,34 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Strategy;
/**
* @todo v3.0, add optional object/data to extract/hydrate.
*/
interface StrategyInterface
{
/**
* Converts the given value so that it can be extracted by the hydrator.
*
* @param mixed $value The original value.
* @param object $object (optional) The original object for context.
* @return mixed Returns the value that should be extracted.
*/
public function extract($value);
/**
* Converts the given value so that it can be hydrated by the hydrator.
*
* @param mixed $value The original value.
* @param array $data (optional) The original data for context.
* @return mixed Returns the value that should be hydrated.
*/
public function hydrate($value);
}

View file

@ -0,0 +1,48 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;
interface StrategyEnabledInterface
{
/**
* Adds the given strategy under the given name.
*
* @param string $name The name of the strategy to register.
* @param StrategyInterface $strategy The strategy to register.
* @return StrategyEnabledInterface
*/
public function addStrategy($name, StrategyInterface $strategy);
/**
* Gets the strategy with the given name.
*
* @param string $name The name of the strategy to get.
* @return StrategyInterface
*/
public function getStrategy($name);
/**
* Checks if the strategy with the given name exists.
*
* @param string $name The name of the strategy to check for.
* @return bool
*/
public function hasStrategy($name);
/**
* Removes the strategy with the given name.
*
* @param string $name The name of the strategy to remove.
* @return StrategyEnabledInterface
*/
public function removeStrategy($name);
}

View file

@ -0,0 +1,23 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
/**
* Interface to allow objects to have initialization logic
*/
interface InitializableInterface
{
/**
* Init an object
*
* @return void
*/
public function init();
}

View file

@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
if (PHP_VERSION_ID < 50400) {
class_alias(
'Zend\Stdlib\JsonSerializable\PhpLegacyCompatibility',
'JsonSerializable'
);
}
/**
* Polyfill for JsonSerializable
*
* JsonSerializable was introduced in PHP 5.4.0.
*
* @see http://php.net/manual/class.jsonserializable.php
*/
interface JsonSerializable extends \JsonSerializable
{
}

View file

@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\JsonSerializable;
/**
* Interface compatible with the built-in JsonSerializable interface
*
* JsonSerializable was introduced in PHP 5.4.0.
*
* @see http://php.net/manual/class.jsonserializable.php
*/
interface PhpLegacyCompatibility
{
/**
* Returns data which can be serialized by json_encode().
*
* @return mixed
* @see http://php.net/manual/jsonserializable.jsonserialize.php
*/
public function jsonSerialize();
}

View file

@ -0,0 +1,118 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use Traversable;
class Message implements MessageInterface
{
/**
* @var array
*/
protected $metadata = array();
/**
* @var string
*/
protected $content = '';
/**
* Set message metadata
*
* Non-destructive setting of message metadata; always adds to the metadata, never overwrites
* the entire metadata container.
*
* @param string|int|array|Traversable $spec
* @param mixed $value
* @throws Exception\InvalidArgumentException
* @return Message
*/
public function setMetadata($spec, $value = null)
{
if (is_scalar($spec)) {
$this->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;
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
interface MessageInterface
{
/**
* Set metadata
*
* @param string|int|array|\Traversable $spec
* @param mixed $value
*/
public function setMetadata($spec, $value = null);
/**
* Get metadata
*
* @param null|string|int $key
* @return mixed
*/
public function getMetadata($key = null);
/**
* Set content
*
* @param mixed $content
* @return mixed
*/
public function setContent($content);
/**
* Get content
*
* @return mixed
*/
public function getContent();
}

View file

@ -0,0 +1,38 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
interface ParameterObjectInterface
{
/**
* @param string $key
* @param mixed $value
* @return void
*/
public function __set($key, $value);
/**
* @param string $key
* @return mixed
*/
public function __get($key);
/**
* @param string $key
* @return bool
*/
public function __isset($key);
/**
* @param string $key
* @return void
*/
public function __unset($key);
}

View file

@ -0,0 +1,115 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use ArrayObject as PhpArrayObject;
class Parameters extends PhpArrayObject implements ParametersInterface
{
/**
* Constructor
*
* Enforces that we have an array, and enforces parameter access to array
* elements.
*
* @param array $values
*/
public function __construct(array $values = null)
{
if (null === $values) {
$values = array();
}
parent::__construct($values, ArrayObject::ARRAY_AS_PROPS);
}
/**
* Populate from native PHP array
*
* @param array $values
* @return void
*/
public function fromArray(array $values)
{
$this->exchangeArray($values);
}
/**
* Populate from query string
*
* @param string $string
* @return void
*/
public function fromString($string)
{
$array = 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;
}
}

View file

@ -0,0 +1,86 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use ArrayAccess;
use Countable;
use Serializable;
use Traversable;
/*
* Basically, an ArrayObject. You could simply define something like:
* class QueryParams extends ArrayObject implements Parameters {}
* and have 90% of the functionality
*/
interface ParametersInterface extends ArrayAccess, Countable, Serializable, Traversable
{
/**
* Constructor
*
* @param array $values
*/
public function __construct(array $values = null);
/**
* From array
*
* Allow deserialization from standard array
*
* @param array $values
* @return mixed
*/
public function fromArray(array $values);
/**
* From string
*
* Allow deserialization from raw body; e.g., for PUT requests
*
* @param $string
* @return mixed
*/
public function fromString($string);
/**
* To array
*
* Allow serialization back to standard array
*
* @return mixed
*/
public function toArray();
/**
* To string
*
* Allow serialization to query format; e.g., for PUT or POST requests
*
* @return mixed
*/
public function toString();
/**
* Get
*
* @param string $name
* @param mixed|null $default
* @return mixed
*/
public function get($name, $default = null);
/**
* Set
*
* @param string $name
* @param mixed $value
* @return ParametersInterface
*/
public function set($name, $value);
}

View file

@ -0,0 +1,274 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib;
use Countable;
use Iterator;
class PriorityList implements Iterator, Countable
{
const EXTR_DATA = 0x00000001;
const EXTR_PRIORITY = 0x00000002;
const EXTR_BOTH = 0x00000003;
/**
* Internal list of all items.
*
* @var array[]
*/
protected $items = array();
/**
* Serial assigned to items to preserve LIFO.
*
* @var int
*/
protected $serial = 0;
/**
* Serial order mode
* @var integer
*/
protected $isLIFO = 1;
/**
* Internal counter to avoid usage of count().
*
* @var int
*/
protected $count = 0;
/**
* Whether the list was already sorted.
*
* @var bool
*/
protected $sorted = false;
/**
* Insert a new item.
*
* @param string $name
* @param mixed $value
* @param int $priority
*
* @return void
*/
public function insert($name, $value, $priority = 0)
{
if (!isset($this->items[$name])) {
$this->count++;
}
$this->sorted = false;
$this->items[$name] = array(
'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 = array();
$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, array($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
);
}
}

Some files were not shown because too many files have changed in this diff Show more