diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5466cb609d9..6bc478269f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,205 +1,11 @@
# CHANGELOG
-## 2.0.3:
-- 2244: Fix for issue ZF2-503 (https://github.com/zendframework/zf2/issues/2244)
-- 2318: Allow to remove decimals in CurrencyFormat
- (https://github.com/zendframework/zf2/issues/2318)
-- 2363: Hotfix db features with eventfeature
- (https://github.com/zendframework/zf2/issues/2363)
-- 2380: ZF2-482 Attempt to fix the buffer. Also added extra unit tests.
- (https://github.com/zendframework/zf2/issues/2380)
-- 2392: Update library/Zend/Db/Adapter/Platform/Mysql.php
- (https://github.com/zendframework/zf2/issues/2392)
-- 2395: Fix for http://framework.zend.com/issues/browse/ZF2-571
- (https://github.com/zendframework/zf2/issues/2395)
-- 2397: Memcached option merge issuse
- (https://github.com/zendframework/zf2/issues/2397)
-- 2402: Adding missing dependencies
- (https://github.com/zendframework/zf2/issues/2402)
-- 2404: Fix to comments (https://github.com/zendframework/zf2/issues/2404)
-- 2416: Fix expressionParamIndex for AbstractSql
- (https://github.com/zendframework/zf2/issues/2416)
-- 2420: Zend\Db\Sql\Select: Fixed issue with join expression named parameters
- overlapping. (https://github.com/zendframework/zf2/issues/2420)
-- 2421: Update library/Zend/Http/Header/SetCookie.php
- (https://github.com/zendframework/zf2/issues/2421)
-- 2422: fix add 2 space after @param in Zend\Loader
- (https://github.com/zendframework/zf2/issues/2422)
-- 2423: ManagerInterface must be interface, remove 'interface' description
- (https://github.com/zendframework/zf2/issues/2423)
-- 2425: Use built-in Travis composer
- (https://github.com/zendframework/zf2/issues/2425)
-- 2426: Remove need of setter in ClassMethods hydrator
- (https://github.com/zendframework/zf2/issues/2426)
-- 2432: Prevent space before end of tag with HTML5 doctype
- (https://github.com/zendframework/zf2/issues/2432)
-- 2433: fix for setJsonpCallback not called when recieved JsonModel + test
- (https://github.com/zendframework/zf2/issues/2433)
-- 2434: added phpdoc in Zend\Db
- (https://github.com/zendframework/zf2/issues/2434)
-- 2437: Hotfix/console 404 reporting
- (https://github.com/zendframework/zf2/issues/2437)
-- 2438: Improved previous fix for ZF2-558.
- (https://github.com/zendframework/zf2/issues/2438)
-- 2440: Turkish Translations for Captcha and Validate
- (https://github.com/zendframework/zf2/issues/2440)
-- 2441: Allow form collection to have any helper
- (https://github.com/zendframework/zf2/issues/2441)
-- 2516: limit(20) -> generates LIMIT '20' and throws an IllegalQueryException
- (https://github.com/zendframework/zf2/issues/2516)
-- 2545: getSqlStringForSqlObject() returns an invalid SQL statement with LIMIT
- and OFFSET clauses (https://github.com/zendframework/zf2/issues/2545)
-- 2595: Pgsql adapater has codes related to MySQL
- (https://github.com/zendframework/zf2/issues/2595)
-- 2613: Prevent password to be rendered if form validation fails
- (https://github.com/zendframework/zf2/issues/2613)
-- 2617: Fixed Zend\Validator\Iban class name
- (https://github.com/zendframework/zf2/issues/2617)
-- 2619: Form enctype fix when File elements are within a collection
- (https://github.com/zendframework/zf2/issues/2619)
-- 2620: InputFilter/Input when merging was not using raw value
- (https://github.com/zendframework/zf2/issues/2620)
-- 2622: Added ability to specify port
- (https://github.com/zendframework/zf2/issues/2622)
-- 2624: Form's default input filters added multiple times
- (https://github.com/zendframework/zf2/issues/2624)
-- 2630: fix relative link ( remove the relative links ) in README.md
- (https://github.com/zendframework/zf2/issues/2630)
-- 2631: Update library/Zend/Loader/AutoloaderFactory.php
- (https://github.com/zendframework/zf2/issues/2631)
-- 2633: fix redundance errors "The input does not appear to be a valid date"
- show twice (https://github.com/zendframework/zf2/issues/2633)
-- 2635: Fix potential issue with Sitemap test
- (https://github.com/zendframework/zf2/issues/2635)
-- 2636: add isset checks around timeout and maxredirects
- (https://github.com/zendframework/zf2/issues/2636)
-- 2641: hotfix : formRow() element error multi-checkbox and radio renderError
- not shown (https://github.com/zendframework/zf2/issues/2641)
-- 2642: Fix Travis build for CS issue
- (https://github.com/zendframework/zf2/issues/2642)
-- 2643: fix for setJsonpCallback not called when recieved JsonModel + test
- (https://github.com/zendframework/zf2/issues/2643)
-- 2644: Add fluidity to the prepare() function for a form
- (https://github.com/zendframework/zf2/issues/2644)
-- 2652: Zucchi/filter tweaks (https://github.com/zendframework/zf2/issues/2652)
-- 2665: pdftest fix (https://github.com/zendframework/zf2/issues/2665)
-- 2666: fixed url change (https://github.com/zendframework/zf2/issues/2666)
-- 2667: Possible fix for rartests
- (https://github.com/zendframework/zf2/issues/2667)
-- 2669: skip whem gmp is loaded
- (https://github.com/zendframework/zf2/issues/2669)
-- 2673: Input fallback value option
- (https://github.com/zendframework/zf2/issues/2673)
-- 2676: mysqli::close() never called
- (https://github.com/zendframework/zf2/issues/2676)
-- 2677: added phpdoc to Zend\Stdlib
- (https://github.com/zendframework/zf2/issues/2677)
-- 2678: Zend\Db\Adapter\Sqlsrv\Sqlsrv never calls Statement\initialize() (fix
- within) (https://github.com/zendframework/zf2/issues/2678)
-- 2679: Zend/Log/Logger.php using incorrect php errorLevel
- (https://github.com/zendframework/zf2/issues/2679)
-- 2680: Cache: fixed bug on getTotalSpace of filesystem and dba adapter
- (https://github.com/zendframework/zf2/issues/2680)
-- 2681: Cache/Dba: fixed notices on tearDown db4 tests
- (https://github.com/zendframework/zf2/issues/2681)
-- 2682: Replace 'Configuration' with 'Config' when retrieving configuration
- (https://github.com/zendframework/zf2/issues/2682)
-- 2683: Hotfix: Allow items from Abstract Factories to have setShared() called
- (https://github.com/zendframework/zf2/issues/2683)
-- 2685: Remove unused Uses (https://github.com/zendframework/zf2/issues/2685)
-- 2686: Adding code to allow EventManager trigger listeners using wildcard
- identifier (https://github.com/zendframework/zf2/issues/2686)
-- 2687: Hotfix/db sql nested expressions
- (https://github.com/zendframework/zf2/issues/2687)
-- 2688: Hotfix/tablegateway event feature
- (https://github.com/zendframework/zf2/issues/2688)
-- 2689: Hotfix/composer phpunit
- (https://github.com/zendframework/zf2/issues/2689)
-- 2690: Use RFC-3339 full-date format (Y-m-d) in Date element
- (https://github.com/zendframework/zf2/issues/2690)
-- 2691: join on conditions don't accept alternatives to columns
- (https://github.com/zendframework/zf2/issues/2691)
-- 2693: Update library/Zend/Db/Adapter/Driver/Mysqli/Connection.php
- (https://github.com/zendframework/zf2/issues/2693)
-- 2694: Bring fluid interface to Feed Writer
- (https://github.com/zendframework/zf2/issues/2694)
-- 2698: fix typo in # should be :: in exception
- (https://github.com/zendframework/zf2/issues/2698)
-- 2699: fix elseif in javascript Upload Demo
- (https://github.com/zendframework/zf2/issues/2699)
-- 2700: fix cs in casting variable
- (https://github.com/zendframework/zf2/issues/2700)
-- 2705: Fix french translation
- (https://github.com/zendframework/zf2/issues/2705)
-- 2707: Improved error message when ServiceManager does not find an invokable
- class (https://github.com/zendframework/zf2/issues/2707)
-- 2710: #2461 - correcting the url encoding of path segments
- (https://github.com/zendframework/zf2/issues/2710)
-- 2711: Fix/demos ProgressBar/ZendForm.php : Object of class Zend\Form\Form
- could not be converted to string
- (https://github.com/zendframework/zf2/issues/2711)
-- 2712: fix cs casting variable for (array)
- (https://github.com/zendframework/zf2/issues/2712)
-- 2713: Update library/Zend/Mvc/Service/ViewHelperManagerFactory.php
- (https://github.com/zendframework/zf2/issues/2713)
-- 2714: Don't add separator if not prefixing columns
- (https://github.com/zendframework/zf2/issues/2714)
-- 2717: Extends when it can : Validator\DateStep extends Validator\Date to
- reduce code redundancy (https://github.com/zendframework/zf2/issues/2717)
-- 2719: Fixing the Cache Storage Factory Adapter Factory
- (https://github.com/zendframework/zf2/issues/2719)
-- 2728: Bad Regex for Content Type header
- (https://github.com/zendframework/zf2/issues/2728)
-- 2731: Reset the Order part when resetting Select
- (https://github.com/zendframework/zf2/issues/2731)
-- 2732: Removed references to Mysqli in Zend\Db\Adapter\Driver\Pgsql
- (https://github.com/zendframework/zf2/issues/2732)
-- 2733: fix @package Zend_Validate should be Zend_Validator
- (https://github.com/zendframework/zf2/issues/2733)
-- 2734: fix i18n @package and @subpackage value
- (https://github.com/zendframework/zf2/issues/2734)
-- 2736: fix captcha helper test.
- (https://github.com/zendframework/zf2/issues/2736)
-- 2737: Issue #2728 - Bad Regex for Content Type header
- (https://github.com/zendframework/zf2/issues/2737)
-- 2738: fix link 'quickstart' to version 2.0
- (https://github.com/zendframework/zf2/issues/2738)
-- 2739: remove '@subpackage' because Zend\Math is not in subpackage
- (https://github.com/zendframework/zf2/issues/2739)
-- 2742: remove () in echo-ing (https://github.com/zendframework/zf2/issues/2742)
-- 2749: Fix for #2678 (Zend\Db's Sqlsrv Driver)
- (https://github.com/zendframework/zf2/issues/2749)
-- 2750: Adds the ability to instanciate by factory to AbstractPluginManager
- (https://github.com/zendframework/zf2/issues/2750)
-- 2754: add the support to register module paths over namespace
- (https://github.com/zendframework/zf2/issues/2754)
-- 2755: remove Zend\Mvc\Controller\PluginBroker from aliases in
- "$defaultServiceConfig" (https://github.com/zendframework/zf2/issues/2755)
-- 2759: Fix Zend\Code\Scanner\TokenArrayScanner
- (https://github.com/zendframework/zf2/issues/2759)
-- 2764: Fixed Zend\Math\Rand::getString() to pass the parameter $strong to
- ::getBytes() (https://github.com/zendframework/zf2/issues/2764)
-- 2765: Csrf: always use dedicated setter
- (https://github.com/zendframework/zf2/issues/2765)
-- 2766: Session\Storage: always preserve REQUEST_ACCESS_TIME
- (https://github.com/zendframework/zf2/issues/2766)
-- 2768: Zend\Validator dependency is missed in Zend\Cache composer.json
- (https://github.com/zendframework/zf2/issues/2768)
-- 2769: change valueToLDAP to valueToLdap and valueFromLDAP to valueFromLdap
- (https://github.com/zendframework/zf2/issues/2769)
-- 2770: Memcached (https://github.com/zendframework/zf2/issues/2770)
-- 2775: Zend\Db\Sql: Fix for Mysql quoting during limit and offset
- (https://github.com/zendframework/zf2/issues/2775)
-- 2776: Allow whitespace in Iban
- (https://github.com/zendframework/zf2/issues/2776)
-- 2777: Fix issue when PREG_BAD_UTF8_OFFSET_ERROR is defined but Unicode support
- is not enabled on PCRE (https://github.com/zendframework/zf2/issues/2777)
-- 2778: Undefined Index fix in ViewHelperManagerFactory
- (https://github.com/zendframework/zf2/issues/2778)
-- 2779: Allow forms that have been added as fieldsets to bind values to bound
- ob... (https://github.com/zendframework/zf2/issues/2779)
-- 2782: Issue 2781 (https://github.com/zendframework/zf2/issues/2782)
+## 2.1.0:
+
+- The initializer for ServiceManagerAwareInterface was removed to prevent
+ confusion between ServiceManagerAwareInterface and
+ ServiceLocatorAwareInterface, and to promote using the latter interface.
## 2.0.2:
diff --git a/library/Zend/Barcode/Barcode.php b/library/Zend/Barcode/Barcode.php
index 35911e80830..31f464640c4 100644
--- a/library/Zend/Barcode/Barcode.php
+++ b/library/Zend/Barcode/Barcode.php
@@ -20,7 +20,7 @@
* @category Zend
* @package Zend_Barcode
*/
-class Barcode
+abstract class Barcode
{
const OBJECT = 'OBJECT';
const RENDERER = 'RENDERER';
diff --git a/library/Zend/Cache/PatternFactory.php b/library/Zend/Cache/PatternFactory.php
index 5a9de1bc924..66b8357f2cd 100644
--- a/library/Zend/Cache/PatternFactory.php
+++ b/library/Zend/Cache/PatternFactory.php
@@ -17,7 +17,7 @@
* @category Zend
* @package Zend_Cache
*/
-class PatternFactory
+abstract class PatternFactory
{
/**
* The pattern manager
diff --git a/library/Zend/Cache/StorageFactory.php b/library/Zend/Cache/StorageFactory.php
index 329874dd704..5550cbe4b9d 100644
--- a/library/Zend/Cache/StorageFactory.php
+++ b/library/Zend/Cache/StorageFactory.php
@@ -18,7 +18,7 @@
* @package Zend_Cache
* @subpackage Storage
*/
-class StorageFactory
+abstract class StorageFactory
{
/**
* Plugin manager for loading adapters
diff --git a/library/Zend/Code/Generator/ClassGenerator.php b/library/Zend/Code/Generator/ClassGenerator.php
index c17b66a97bf..123aca150f6 100644
--- a/library/Zend/Code/Generator/ClassGenerator.php
+++ b/library/Zend/Code/Generator/ClassGenerator.php
@@ -67,6 +67,11 @@ class ClassGenerator extends AbstractGenerator
*/
protected $methods = array();
+ /**
+ * @var array Array of string names
+ */
+ protected $uses = array();
+
/**
* fromReflection() - build a Code Generation Php Object from a Class Reflection
*
@@ -479,6 +484,19 @@ public function addPropertyFromGenerator(PropertyGenerator $property)
return $this;
}
+ /**
+ * Add a class to "use" classes
+ *
+ * @param string $useClass
+ */
+ public function addUse($use, $useAlias = null)
+ {
+ if (!empty($useAlias)) {
+ $use .= ' as ' . $useAlias;
+ }
+ $this->uses[] = $use;
+ }
+
/**
* getProperties()
*
@@ -505,6 +523,16 @@ public function getProperty($propertyName)
return false;
}
+ /**
+ * Returns the "use" classes
+ *
+ * @return array
+ */
+ public function getUses()
+ {
+ return $this->uses;
+ }
+
/**
* hasProperty()
*
@@ -664,6 +692,14 @@ public function generate()
$output .= 'namespace ' . $namespace . ';' . self::LINE_FEED . self::LINE_FEED;
}
+ $uses = $this->getUses();
+ if (!empty($uses)) {
+ foreach ($uses as $use) {
+ $output .= 'use ' . $use . ';' . self::LINE_FEED;
+ }
+ $output .= self::LINE_FEED;
+ }
+
if (null !== ($docBlock = $this->getDocBlock())) {
$docBlock->setIndentation('');
$output .= $docBlock->generate();
diff --git a/library/Zend/Code/Scanner/ClassScanner.php b/library/Zend/Code/Scanner/ClassScanner.php
index 241cf868021..b68afc58fcc 100644
--- a/library/Zend/Code/Scanner/ClassScanner.php
+++ b/library/Zend/Code/Scanner/ClassScanner.php
@@ -10,6 +10,7 @@
namespace Zend\Code\Scanner;
+use Zend\Code\Annotation;
use Zend\Code\Exception;
use Zend\Code\NameInformation;
@@ -106,9 +107,17 @@ public function __construct(array $classTokens, NameInformation $nameInformation
$this->nameInformation = $nameInformation;
}
- public function getAnnotations()
+ /**
+ * @param Annotation\AnnotationManager $annotationManager
+ * @return Annotation\AnnotationCollection
+ */
+ public function getAnnotations(Annotation\AnnotationManager $annotationManager)
{
- return array();
+ if (($docComment = $this->getDocComment()) == '') {
+ return false;
+ }
+
+ return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
}
public function getDocComment()
@@ -206,6 +215,11 @@ public function getConstants()
return $return;
}
+ /**
+ * Returns a list of property names
+ *
+ * @return array
+ */
public function getPropertyNames()
{
$this->scan();
@@ -222,6 +236,11 @@ public function getPropertyNames()
return $return;
}
+ /**
+ * Returns a list of properties
+ *
+ * @return array
+ */
public function getProperties()
{
$this->scan();
@@ -238,6 +257,41 @@ public function getProperties()
return $return;
}
+ public function getProperty($propertyNameOrInfoIndex)
+ {
+ $this->scan();
+
+ if (is_int($propertyNameOrInfoIndex)) {
+ $info = $this->infos[$propertyNameOrInfoIndex];
+ if ($info['type'] != 'property') {
+ throw new Exception\InvalidArgumentException('Index of info offset is not about a property');
+ }
+ } elseif (is_string($propertyNameOrInfoIndex)) {
+ $propertyFound = false;
+ foreach ($this->infos as $info) {
+ if ($info['type'] === 'property' && $info['name'] === $propertyNameOrInfoIndex) {
+ $propertyFound = true;
+ break;
+ }
+ }
+ if (!$propertyFound) {
+ return false;
+ }
+ } else {
+ throw new Exception\InvalidArgumentException('Invalid property name of info index type. Must be of type int or string');
+ }
+ if (!isset($info)) {
+ return false;
+ }
+ $p = new PropertyScanner(
+ array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1),
+ $this->nameInformation
+ );
+ $p->setClass($this->name);
+ $p->setScannerClass($this);
+ return $p;
+ }
+
public function getMethodNames()
{
$this->scan();
diff --git a/library/Zend/Code/Scanner/MethodScanner.php b/library/Zend/Code/Scanner/MethodScanner.php
index d7c3ca90f26..e093bfa2ae0 100644
--- a/library/Zend/Code/Scanner/MethodScanner.php
+++ b/library/Zend/Code/Scanner/MethodScanner.php
@@ -84,7 +84,7 @@ public function getDocComment()
/**
* @param Annotation\AnnotationManager $annotationManager
- * @return Annotation\AnnotationCollection
+ * @return AnnotationScanner
*/
public function getAnnotations(Annotation\AnnotationManager $annotationManager)
{
diff --git a/library/Zend/Code/Scanner/PropertyScanner.php b/library/Zend/Code/Scanner/PropertyScanner.php
index b3d9bbc7f37..1de3e988889 100644
--- a/library/Zend/Code/Scanner/PropertyScanner.php
+++ b/library/Zend/Code/Scanner/PropertyScanner.php
@@ -1 +1,285 @@
tokens = $propertyTokens;
+ $this->nameInformation = $nameInformation;
+ }
+
+ /**
+ * @param string $class
+ */
+ public function setClass($class)
+ {
+ $this->class = $class;
+ }
+
+ /**
+ * @param ClassScanner $scannerClass
+ */
+ public function setScannerClass(ClassScanner $scannerClass)
+ {
+ $this->scannerClass = $scannerClass;
+ }
+
+ /**
+ * @return ClassScanner
+ */
+ public function getClassScanner()
+ {
+ return $this->scannerClass;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ $this->scan();
+ return $this->name;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isPublic()
+ {
+ $this->scan();
+ return $this->isPublic;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isPrivate()
+ {
+ $this->scan();
+ return $this->isPrivate;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isProtected()
+ {
+ $this->scan();
+ return $this->isProtected;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isStatic()
+ {
+ $this->scan();
+ return $this->isStatic;
+ }
+
+ /**
+ * @return string
+ */
+ public function getValue()
+ {
+ $this->scan();
+ return $this->value;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDocComment()
+ {
+ $this->scan();
+ return $this->docComment;
+ }
+
+ /**
+ * @param Annotation\AnnotationManager $annotationManager
+ * @return AnnotationScanner
+ */
+ public function getAnnotations(Annotation\AnnotationManager $annotationManager)
+ {
+ if (($docComment = $this->getDocComment()) == '') {
+ return false;
+ }
+
+ return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ $this->scan();
+ return var_export($this, true);
+ }
+
+ /**
+ * Scan tokens
+ *
+ * @throws \Zend\Code\Exception\RuntimeException
+ */
+ protected function scan()
+ {
+ if ($this->isScanned) {
+ return;
+ }
+
+ if (!$this->tokens) {
+ throw new Exception\RuntimeException('No tokens were provided');
+ }
+
+ /**
+ * Variables & Setup
+ */
+ $tokens = &$this->tokens;
+
+ reset($tokens);
+
+ SCANNER_TOP:
+
+ $token = current($tokens);
+
+ if (!is_string($token)) {
+ list($tokenType, $tokenContent, $tokenLine) = $token;
+
+ switch ($tokenType) {
+ case T_DOC_COMMENT:
+ if ($this->docComment === null && $this->name === null) {
+ $this->docComment = $tokenContent;
+ }
+ goto SCANNER_CONTINUE;
+
+ case T_VARIABLE:
+ $this->name = ltrim($tokenContent, '$');
+ goto SCANNER_CONTINUE;
+
+ case T_PUBLIC:
+ // use defaults
+ goto SCANNER_CONTINUE;
+
+ case T_PROTECTED:
+ $this->isProtected = true;
+ $this->isPublic = false;
+ goto SCANNER_CONTINUE;
+
+ case T_PRIVATE:
+ $this->isPrivate = true;
+ $this->isPublic = false;
+ goto SCANNER_CONTINUE;
+
+ case T_STATIC:
+ $this->isStatic = true;
+ goto SCANNER_CONTINUE;
+
+ default:
+ if ($this->name !== null && trim($tokenContent) !== '') {
+ $this->value .= (is_string($token)) ? $token : $tokenContent;
+ if (substr($this->value, 0, 1) === '"' || substr($this->value, 0, 1) === "'") {
+ $this->value = substr($this->value, 1, -1); // Remove quotes
+ }
+ }
+ goto SCANNER_CONTINUE;
+ }
+ }
+
+ SCANNER_CONTINUE:
+
+ if (next($this->tokens) === false) {
+ goto SCANNER_END;
+ }
+ goto SCANNER_TOP;
+
+ SCANNER_END:
+
+ $this->isScanned = true;
+ }
+}
diff --git a/library/Zend/Config/Factory.php b/library/Zend/Config/Factory.php
index 53e5b41c59a..25986d23aa1 100644
--- a/library/Zend/Config/Factory.php
+++ b/library/Zend/Config/Factory.php
@@ -25,6 +25,13 @@ class Factory
*/
public static $readers = null;
+ /**
+ * Plugin manager for loading writers
+ *
+ * @var null|WriterPluginManager
+ */
+ public static $writers = null;
+
/**
* Registered config file extensions.
* key is extension, value is reader instance or plugin name
@@ -38,6 +45,19 @@ class Factory
'yaml' => 'yaml',
);
+ /**
+ * Register config file extensions for writing
+ * key is extension, value is writer instance or plugin name
+ *
+ * @var array
+ */
+ protected static $writerExtensions = array(
+ 'php' => 'php',
+ 'ini' => 'ini',
+ 'json' => 'json',
+ 'xml' => 'xml',
+ 'yaml' => 'yaml',
+ );
/**
* Read a config from a file.
@@ -107,10 +127,67 @@ public static function fromFiles(array $files, $returnConfigObject = false)
return ($returnConfigObject) ? new Config($config) : $config;
}
+ /**
+ * Writes a config to a file
+ *
+ * @param string $filename
+ * @param array|Config $config
+ * @return boolean TRUE on success | FALSE on failure
+ * @throws Exception\RuntimeException
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function toFile($filename, $config)
+ {
+ if (
+ (is_object($config) && !($config instanceOf Config)) ||
+ (!is_object($config) && !is_array($config))
+ ) {
+ throw new Exception\InvalidArgumentException(
+ __METHOD__." \$config should be an array or instance of Zend\\Config\\Config"
+ );
+ }
+
+ $extension = substr(strrchr($filename, '.'), 1);
+ $directory = dirname($filename);
+
+ if (!is_dir($directory)) {
+ throw new Exception\RuntimeException(
+ "Directory '{$directory}' does not exists!"
+ );
+ }
+
+ if (!is_writable($directory)) {
+ throw new Exception\RuntimeException(
+ "Cannot write in directory '{$directory}'"
+ );
+ }
+
+ if(!isset(self::$writerExtensions[$extension])) {
+ throw new Exception\RuntimeException(
+ "Unsupported config file extension: '.{$extension}' for writing."
+ );
+ }
+
+ $writer = self::$writerExtensions[$extension];
+ if (($writer instanceOf Writer\AbstractWriter) === false) {
+ $writer = self::getWriterPluginManager()->get($writer);
+ self::$writerExtensions[$extension] = $writer;
+ }
+
+ if (is_object($config)) {
+ $config = $config->toArray();
+ }
+
+ $content = $writer->processConfig($config);
+
+ return (bool) (file_put_contents($filename, $content) !== false);
+ }
+
/**
* Set reader plugin manager
*
* @param ReaderPluginManager $readers
+ * @return void
*/
public static function setReaderPluginManager(ReaderPluginManager $readers)
{
@@ -130,12 +207,38 @@ public static function getReaderPluginManager()
return static::$readers;
}
+ /**
+ * Set writer plugin manager
+ *
+ * @param WriterPluginManager $writers
+ * @return void
+ */
+ public static function setWriterPluginManager(WriterPluginManager $writers)
+ {
+ self::$writers = $writers;
+ }
+
+ /**
+ * Get the writer plugin manager
+ *
+ * @return WriterPluginManager
+ */
+ public static function getWriterPluginManager()
+ {
+ if (static::$writers === null) {
+ static::$writers = new WriterPluginManager();
+ }
+
+ return static::$writers;
+ }
+
/**
* Set config reader for file extension
*
* @param string $extension
* @param string|Reader\ReaderInterface $reader
* @throws Exception\InvalidArgumentException
+ * @return void
*/
public static function registerReader($extension, $reader)
{
@@ -152,4 +255,28 @@ public static function registerReader($extension, $reader)
self::$extensions[$extension] = $reader;
}
+
+ /**
+ * Set config writer for file extension
+ *
+ * @param string $extension
+ * @param string|Writer\AbstractWriter $writer
+ * @throw Exception\InvalidArgumentException
+ * @return void
+ */
+ public static function registerWriter($extension, $writer)
+ {
+ $extension = strtolower($extension);
+
+ if (!is_string($writer) && !$writer instanceof Writer\AbstractWriter) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Writer should be plugin name, class name or ' .
+ 'instance of %s\Writer\AbstractWriter; received "%s"',
+ __NAMESPACE__,
+ (is_object($writer) ? get_class($writer) : gettype($writer))
+ ));
+ }
+
+ self::$writerExtensions[$extension] = $writer;
+ }
}
diff --git a/library/Zend/Config/WriterPluginManager.php b/library/Zend/Config/WriterPluginManager.php
new file mode 100755
index 00000000000..35717f51788
--- /dev/null
+++ b/library/Zend/Config/WriterPluginManager.php
@@ -0,0 +1,29 @@
+ 'Zend\Config\Writer\PhpArray',
+ 'ini' => 'Zend\Config\Writer\Ini',
+ 'json' => 'Zend\Config\Writer\Json',
+ 'yaml' => 'Zend\Config\Writer\Yaml',
+ 'xml' => 'Zend\Config\Writer\Xml',
+ );
+
+ public function validatePlugin($plugin)
+ {
+ if ($plugin instanceOf Writer\AbstractWriter) {
+ return;
+ }
+
+ $type = is_object($plugin) ? get_class($plugin) : gettype($plugin);
+
+ throw new Exception\InvalidArgumentException(
+ "Plugin of type {$type} is invalid. Plugin must extend ".
+ __NAMESPACE__.'\Writer\AbstractWriter'
+ );
+ }
+}
diff --git a/library/Zend/Crypt/Hmac.php b/library/Zend/Crypt/Hmac.php
index 8c14f273da2..fc7dd2ba7bf 100644
--- a/library/Zend/Crypt/Hmac.php
+++ b/library/Zend/Crypt/Hmac.php
@@ -42,10 +42,6 @@ class Hmac
*/
public static function compute($key, $hash, $data, $output = self::OUTPUT_STRING)
{
- if (!isset($key) || empty($key)) {
- throw new Exception\InvalidArgumentException('Provided key is null or empty');
- }
-
$hash = strtolower($hash);
if (!self::isSupported($hash)) {
throw new Exception\InvalidArgumentException(
diff --git a/library/Zend/Crypt/Key/Derivation/Scrypt.php b/library/Zend/Crypt/Key/Derivation/Scrypt.php
new file mode 100644
index 00000000000..cd6d82ab6e0
--- /dev/null
+++ b/library/Zend/Crypt/Key/Derivation/Scrypt.php
@@ -0,0 +1,345 @@
+ 0 and a power of 2");
+ }
+ if ($n > PHP_INT_MAX / 128 / $r) {
+ throw new Exception\InvalidArgumentException("Parameter n is too large");
+ }
+ if ($r > PHP_INT_MAX / 128 / $p) {
+ throw new Exception\InvalidArgumentException("Parameter r is too large");
+ }
+
+ if (extension_loaded('Scrypt')) {
+ if ($length < 16) {
+ throw new Exception\InvalidArgumentException("Key length is too low, must be greater or equal to 16");
+ }
+ return self::hex2bin(scrypt($password, $salt, $n, $r, $p, $length));
+ }
+
+ $b = Pbkdf2::calc('sha256', $password, $salt, 1, $p * 128 * $r);
+
+ $s = '';
+ for ($i = 0; $i < $p; $i++) {
+ $s .= self::scryptROMix(substr($b, $i * 128 * $r, 128 * $r), $n, $r);
+ }
+
+ return Pbkdf2::calc('sha256', $password, $s, 1, $length);
+ }
+
+ /**
+ * scryptROMix
+ *
+ * @param string $b
+ * @param integer $n
+ * @param integer $r
+ * @return string
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4
+ */
+ protected static function scryptROMix($b, $n, $r)
+ {
+ $x = $b;
+ $v = array();
+ for ($i = 0; $i < $n; $i++) {
+ $v[$i] = $x;
+ $x = self::scryptBlockMix($x, $r);
+ }
+ for ($i = 0; $i < $n; $i++) {
+ $j = self::integerify($x) % $n;
+ $t = $x ^ $v[$j];
+ $x = self::scryptBlockMix($t, $r);
+ }
+ return $x;
+ }
+
+ /**
+ * scryptBlockMix
+ *
+ * @param string $b
+ * @param integer $r
+ * @return string
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-3
+ */
+ protected static function scryptBlockMix($b, $r)
+ {
+ $x = substr($b, -64);
+ $even = '';
+ $odd = '';
+ $len = 2 * $r;
+
+ for ($i = 0; $i < $len; $i++) {
+ if (PHP_INT_SIZE === 4) {
+ $x = self::salsa208Core32($x ^ substr($b, 64 * $i, 64));
+ } else {
+ $x = self::salsa208Core64($x ^ substr($b, 64 * $i, 64));
+ }
+ if ($i % 2 == 0) {
+ $even .= $x;
+ } else {
+ $odd .= $x;
+ }
+ }
+ return $even . $odd;
+ }
+
+ /**
+ * Salsa 20/8 core (32 bit version)
+ *
+ * @param string $b
+ * @return string
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2
+ * @see http://cr.yp.to/salsa20.html
+ */
+ protected static function salsa208Core32($b)
+ {
+ $b32 = array();
+ for ($i = 0; $i < 16; $i++) {
+ list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4));
+ }
+
+ $x = $b32;
+ for ($i = 0; $i < 8; $i += 2) {
+ $a = ($x[ 0] + $x[12]);
+ $x[ 4] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[ 4] + $x[ 0]);
+ $x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[ 8] + $x[ 4]);
+ $x[12] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[12] + $x[ 8]);
+ $x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[ 5] + $x[ 1]);
+ $x[ 9] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[ 9] + $x[ 5]);
+ $x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[13] + $x[ 9]);
+ $x[ 1] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[ 1] + $x[13]);
+ $x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[10] + $x[ 6]);
+ $x[14] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[14] + $x[10]);
+ $x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[ 2] + $x[14]);
+ $x[ 6] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[ 6] + $x[ 2]);
+ $x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[15] + $x[11]);
+ $x[ 3] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[ 3] + $x[15]);
+ $x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[ 7] + $x[ 3]);
+ $x[11] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[11] + $x[ 7]);
+ $x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[ 0] + $x[ 3]);
+ $x[ 1] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[ 1] + $x[ 0]);
+ $x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[ 2] + $x[ 1]);
+ $x[ 3] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[ 3] + $x[ 2]);
+ $x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[ 5] + $x[ 4]);
+ $x[ 6] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[ 6] + $x[ 5]);
+ $x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[ 7] + $x[ 6]);
+ $x[ 4] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[ 4] + $x[ 7]);
+ $x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[10] + $x[ 9]);
+ $x[11] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[11] + $x[10]);
+ $x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[ 8] + $x[11]);
+ $x[ 9] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[ 9] + $x[ 8]);
+ $x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ $a = ($x[15] + $x[14]);
+ $x[12] ^= ($a << 7) | ($a >> 25) & 0x7f;
+ $a = ($x[12] + $x[15]);
+ $x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff;
+ $a = ($x[13] + $x[12]);
+ $x[14] ^= ($a << 13) | ($a >> 19) & 0x1fff;
+ $a = ($x[14] + $x[13]);
+ $x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
+ }
+ for ($i = 0; $i < 16; $i++) {
+ $b32[$i] = $b32[$i] + $x[$i];
+ }
+ $result = '';
+ for ($i = 0; $i < 16; $i++) {
+ $result .= pack("V", $b32[$i]);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Salsa 20/8 core (64 bit version)
+ *
+ * @param string $b
+ * @return string
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2
+ * @see http://cr.yp.to/salsa20.html
+ */
+ protected static function salsa208Core64($b)
+ {
+ $b32 = array();
+ for ($i = 0; $i < 16; $i++) {
+ list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4));
+ }
+
+ $x = $b32;
+ for ($i = 0; $i < 8; $i += 2) {
+ $a = ($x[ 0] + $x[12]) & 0xffffffff;
+ $x[ 4] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[ 4] + $x[ 0]) & 0xffffffff;
+ $x[ 8] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[ 8] + $x[ 4]) & 0xffffffff;
+ $x[12] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[12] + $x[ 8]) & 0xffffffff;
+ $x[ 0] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[ 5] + $x[ 1]) & 0xffffffff;
+ $x[ 9] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[ 9] + $x[ 5]) & 0xffffffff;
+ $x[13] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[13] + $x[ 9]) & 0xffffffff;
+ $x[ 1] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[ 1] + $x[13]) & 0xffffffff;
+ $x[ 5] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[10] + $x[ 6]) & 0xffffffff;
+ $x[14] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[14] + $x[10]) & 0xffffffff;
+ $x[ 2] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[ 2] + $x[14]) & 0xffffffff;
+ $x[ 6] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[ 6] + $x[ 2]) & 0xffffffff;
+ $x[10] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[15] + $x[11]) & 0xffffffff;
+ $x[ 3] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[ 3] + $x[15]) & 0xffffffff;
+ $x[ 7] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[ 7] + $x[ 3]) & 0xffffffff;
+ $x[11] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[11] + $x[ 7]) & 0xffffffff;
+ $x[15] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[ 0] + $x[ 3]) & 0xffffffff;
+ $x[ 1] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[ 1] + $x[ 0]) & 0xffffffff;
+ $x[ 2] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[ 2] + $x[ 1]) & 0xffffffff;
+ $x[ 3] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[ 3] + $x[ 2]) & 0xffffffff;
+ $x[ 0] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[ 5] + $x[ 4]) & 0xffffffff;
+ $x[ 6] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[ 6] + $x[ 5]) & 0xffffffff;
+ $x[ 7] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[ 7] + $x[ 6]) & 0xffffffff;
+ $x[ 4] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[ 4] + $x[ 7]) & 0xffffffff;
+ $x[ 5] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[10] + $x[ 9]) & 0xffffffff;
+ $x[11] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[11] + $x[10]) & 0xffffffff;
+ $x[ 8] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[ 8] + $x[11]) & 0xffffffff;
+ $x[ 9] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[ 9] + $x[ 8]) & 0xffffffff;
+ $x[10] ^= ($a << 18) | ($a >> 14);
+ $a = ($x[15] + $x[14]) & 0xffffffff;
+ $x[12] ^= ($a << 7) | ($a >> 25);
+ $a = ($x[12] + $x[15]) & 0xffffffff;
+ $x[13] ^= ($a << 9) | ($a >> 23);
+ $a = ($x[13] + $x[12]) & 0xffffffff;
+ $x[14] ^= ($a << 13) | ($a >> 19);
+ $a = ($x[14] + $x[13]) & 0xffffffff;
+ $x[15] ^= ($a << 18) | ($a >> 14);
+ }
+ for ($i = 0; $i < 16; $i++) {
+ $b32[$i] = ($b32[$i] + $x[$i]) & 0xffffffff;
+ }
+ $result = '';
+ for ($i = 0; $i < 16; $i++) {
+ $result .= pack("V", $b32[$i]);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Integerify
+ *
+ * Integerify (B[0] ... B[2 * r - 1]) is defined as the result
+ * of interpreting B[2 * r - 1] as a little-endian integer.
+ * Each block B is a string of 64 bytes.
+ *
+ * @param string $b
+ * @return integer
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4
+ */
+ protected static function integerify($b)
+ {
+ $v = 'v';
+ if (PHP_INT_SIZE === 8) {
+ $v = 'V';
+ }
+ list(,$n) = unpack($v, substr($b, -64));
+ return $n;
+ }
+
+ /**
+ * Convert hex string in a binary string
+ *
+ * @param string $hex
+ * @return string
+ */
+ protected static function hex2bin($hex)
+ {
+ if (version_compare(PHP_VERSION, '5.4') >= 0) {
+ return hex2bin($hex);
+ }
+ $len = strlen($hex);
+ $result = '';
+ for ($i = 0; $i < $len; $i+=2) {
+ $result .= chr(hexdec($hex[$i] . $hex[$i+1]));
+ }
+ return $result;
+ }
+}
diff --git a/library/Zend/Crypt/Password/Bcrypt.php b/library/Zend/Crypt/Password/Bcrypt.php
index e8dc522723d..5ff12f866f0 100644
--- a/library/Zend/Crypt/Password/Bcrypt.php
+++ b/library/Zend/Crypt/Password/Bcrypt.php
@@ -34,6 +34,11 @@ class Bcrypt implements PasswordInterface
*/
protected $salt;
+ /**
+ * @var boolean
+ */
+ protected $backwardCompatibility = false;
+
/**
* Constructor
*
@@ -82,7 +87,7 @@ public function create($password)
* Check for security flaw in the bcrypt implementation used by crypt()
* @see http://php.net/security/crypt_blowfish.php
*/
- if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
+ if ((version_compare(PHP_VERSION, '5.3.7') >= 0) && !$this->backwardCompatibility) {
$prefix = '$2y$';
} else {
$prefix = '$2a$';
@@ -172,4 +177,25 @@ public function getSalt()
{
return $this->salt;
}
+
+ /**
+ * Set the backward compatibility $2a$ instead of $2y$ for PHP 5.3.7+
+ *
+ * @param boolean $value
+ */
+ public function setBackwardCompatibility($value)
+ {
+ $this->backwardCompatibility = (boolean) $value;
+ return $this;
+ }
+
+ /**
+ * Get the backward compatibility
+ *
+ * @return boolean
+ */
+ public function getBackwardCompatibility()
+ {
+ return $this->backwardCompatibility;
+ }
}
diff --git a/library/Zend/Db/Sql/AbstractSql.php b/library/Zend/Db/Sql/AbstractSql.php
index 0627e678a32..2cf0cde604e 100644
--- a/library/Zend/Db/Sql/AbstractSql.php
+++ b/library/Zend/Db/Sql/AbstractSql.php
@@ -27,6 +27,11 @@ abstract class AbstractSql
*/
protected $processInfo = array('paramPrefix' => '', 'subselectCount' => 0);
+ /**
+ * @var array
+ */
+ protected $instanceParameterIndex = array();
+
protected function processExpression(ExpressionInterface $expression, PlatformInterface $platform, Adapter $adapter = null, $namedParameterPrefix = null)
{
// static counter for the number of times this method was invoked across the PHP runtime
@@ -42,7 +47,12 @@ protected function processExpression(ExpressionInterface $expression, PlatformIn
// initialize variables
$parts = $expression->getExpressionData();
- $expressionParamIndex = 1;
+
+ if(!isset($this->instanceParameterIndex[$namedParameterPrefix])) {
+ $this->instanceParameterIndex[$namedParameterPrefix] = 1;
+ }
+
+ $expressionParamIndex = &$this->instanceParameterIndex[$namedParameterPrefix];
foreach ($parts as $part) {
diff --git a/library/Zend/Filter/FilterPluginManager.php b/library/Zend/Filter/FilterPluginManager.php
index d7ea9b55078..0f58a4e3a4d 100644
--- a/library/Zend/Filter/FilterPluginManager.php
+++ b/library/Zend/Filter/FilterPluginManager.php
@@ -68,6 +68,7 @@ class FilterPluginManager extends AbstractPluginManager
'stringtrim' => 'Zend\Filter\StringTrim',
'stripnewlines' => 'Zend\Filter\StripNewlines',
'striptags' => 'Zend\Filter\StripTags',
+ 'urinormalize' => 'Zend\Filter\UriNormalize',
'wordcamelcasetodash' => 'Zend\Filter\Word\CamelCaseToDash',
'wordcamelcasetoseparator' => 'Zend\Filter\Word\CamelCaseToSeparator',
'wordcamelcasetounderscore' => 'Zend\Filter\Word\CamelCaseToUnderscore',
diff --git a/library/Zend/Filter/UriNormalize.php b/library/Zend/Filter/UriNormalize.php
new file mode 100644
index 00000000000..082c37a89cb
--- /dev/null
+++ b/library/Zend/Filter/UriNormalize.php
@@ -0,0 +1,150 @@
+setOptions($options);
+ }
+ }
+
+ /**
+ * Set the default scheme to use when parsing scheme-less URIs
+ *
+ * The scheme used when parsing URIs may affect the specific object used to
+ * normalize the URI and thus may affect the resulting normalize URI.
+ *
+ * @param string $defaultScheme
+ * @return \Zend\Filter\UriNormalize
+ */
+ public function setDefaultScheme($defaultScheme)
+ {
+ $this->defaultScheme = $defaultScheme;
+ return $this;
+ }
+
+ /**
+ * Set a URI scheme to enforce on schemeless URIs
+ *
+ * This allows forcing input values such as 'www.example.com/foo' into
+ * 'http://www.example.com/foo'.
+ *
+ * This should be used with caution, as a standard-compliant URI parser
+ * would regard 'www.example.com' in the above input URI to be the path and
+ * not host part of the URI. While this option can assist in solving
+ * real-world user mishaps, it may yield unexpected results at times.
+ *
+ * @param string $enforcedScheme
+ * @return \Zend\Filter\UriNormalize
+ */
+ public function setEnforcedScheme($enforcedScheme)
+ {
+ $this->enforcedScheme = $enforcedScheme;
+ return $this;
+ }
+
+ /**
+ * Filter the URL by normalizing it and applying a default scheme if set
+ *
+ * @param string $value
+ * @return string
+ */
+ public function filter($value)
+ {
+ $defaultScheme = $this->defaultScheme ?: $this->enforcedScheme;
+
+ // Reset default scheme if it is not a known scheme
+ if (!UriFactory::getRegisteredSchemeClass($defaultScheme)) {
+ $defaultScheme = null;
+ }
+
+ try {
+ $uri = UriFactory::factory($value, $defaultScheme);
+ if ($this->enforcedScheme && (!$uri->getScheme())) {
+ $this->enforceScheme($uri);
+ }
+
+ } catch (UriException $ex) {
+ // We are unable to parse / enfore scheme with the given config and input
+ return $value;
+ }
+
+ $uri->normalize();
+
+ if (!$uri->isValid()) {
+ return $value;
+ }
+
+ return $uri->toString();
+ }
+
+ /**
+ * Enforce the defined scheme on the URI
+ *
+ * This will also adjust the host and path parts of the URI as expected in
+ * the case of scheme-less network URIs
+ *
+ * @param Uri $uri
+ */
+ protected function enforceScheme(Uri $uri)
+ {
+ $path = $uri->getPath();
+ if (strpos($path, '/') !== false) {
+ list($host, $path) = explode('/', $path, 2);
+ $path = '/' . $path;
+ } else {
+ $host = $path;
+ $path = '';
+ }
+
+ // We have nothing to do if we have no host
+ if (!$host) {
+ return;
+ }
+
+ $uri->setScheme($this->enforcedScheme)
+ ->setHost($host)
+ ->setPath($path);
+ }
+}
diff --git a/library/Zend/Filter/composer.json b/library/Zend/Filter/composer.json
index 254059717bd..4dd43285865 100644
--- a/library/Zend/Filter/composer.json
+++ b/library/Zend/Filter/composer.json
@@ -20,7 +20,8 @@
},
"suggest": {
"zendframework/zend-i18n": "Zend\\I18n component",
+ "zendframework/zend-uri": "Zend\\Uri component for UriNormalize filter",
"zendframework/zend-validator": "Zend\\Validator component",
"zendframework/zend-crypt": "Zend\\Crypt component"
}
-}
\ No newline at end of file
+}
diff --git a/library/Zend/Form/Annotation/AbstractArrayOrStringAnnotation.php b/library/Zend/Form/Annotation/AbstractArrayOrStringAnnotation.php
new file mode 100644
index 00000000000..a9bf814c32e
--- /dev/null
+++ b/library/Zend/Form/Annotation/AbstractArrayOrStringAnnotation.php
@@ -0,0 +1,43 @@
+value = $data['value'];
+ }
+}
diff --git a/library/Zend/Form/Annotation/Hydrator.php b/library/Zend/Form/Annotation/Hydrator.php
index d4fb9554957..ec88828b45a 100644
--- a/library/Zend/Form/Annotation/Hydrator.php
+++ b/library/Zend/Form/Annotation/Hydrator.php
@@ -21,12 +21,12 @@
* @package Zend_Form
* @subpackage Annotation
*/
-class Hydrator extends AbstractStringAnnotation
+class Hydrator extends AbstractArrayOrStringAnnotation
{
/**
* Retrieve the hydrator class
*
- * @return null|string
+ * @return null|string|array
*/
public function getHydrator()
{
diff --git a/library/Zend/Form/Element/DateSelect.php b/library/Zend/Form/Element/DateSelect.php
new file mode 100644
index 00000000000..4d3f5396947
--- /dev/null
+++ b/library/Zend/Form/Element/DateSelect.php
@@ -0,0 +1,176 @@
+dayElement = new Select('day');
+ }
+
+ /**
+ * Accepted options for DateSelect (plus the ones from MonthSelect) :
+ * - day_attributes: HTML attributes to be rendered with the day element
+ *
+ * @param array|\Traversable $options
+ * @return DateSelect
+ */
+ public function setOptions($options)
+ {
+ parent::setOptions($options);
+
+ if (isset($options['day_attributes'])) {
+ $this->setDayAttributes($options['day_attributes']);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return Select
+ */
+ public function getDayElement()
+ {
+ return $this->dayElement;
+ }
+
+ /**
+ * Set the day attributes
+ *
+ * @param array $dayAttributes
+ * @return DateSelect
+ */
+ public function setDayAttributes(array $dayAttributes)
+ {
+ $this->dayElement->setAttributes($dayAttributes);
+ return $this;
+ }
+
+ /**
+ * Get the day attributes
+ *
+ * @return array
+ */
+ public function getDayAttributes()
+ {
+ return $this->dayElement->getAttributes();
+ }
+
+ /**
+ * @param mixed $value
+ * @return void|\Zend\Form\Element
+ */
+ public function setValue($value)
+ {
+ if ($value instanceof DateTime) {
+ $value = array(
+ 'year' => $value->format('Y'),
+ 'month' => $value->format('m'),
+ 'day' => $value->format('d')
+ );
+ }
+
+ $this->yearElement->setValue($value['year']);
+ $this->monthElement->setValue($value['month']);
+ $this->dayElement->setValue($value['day']);
+ }
+
+ /**
+ * Prepare the form element (mostly used for rendering purposes)
+ *
+ * @param Form $form
+ * @return mixed
+ */
+ public function prepareElement(Form $form)
+ {
+ parent::prepareElement($form);
+
+ $name = $this->getName();
+ $this->dayElement->setName($name . '[day]');
+ }
+
+ /**
+ * Get validator
+ *
+ * @return ValidatorInterface
+ */
+ protected function getValidator()
+ {
+ if (null === $this->validator) {
+ $this->validator = new DateValidator(array('format' => 'Y-m-d'));
+ }
+
+ return $this->validator;
+ }
+
+ /**
+ * Should return an array specification compatible with
+ * {@link Zend\InputFilter\Factory::createInput()}.
+ *
+ * @return array
+ */
+ public function getInputSpecification()
+ {
+ return array(
+ 'name' => $this->getName(),
+ 'required' => false,
+ 'filters' => array(
+ array(
+ 'name' => 'Callback',
+ 'options' => array(
+ 'callback' => function($date) {
+ // Convert the date to a specific format
+ if (is_array($date)) {
+ $date = $date['year'] . '-' . $date['month'] . '-' . $date['day'];
+ }
+
+ return $date;
+ }
+ )
+ )
+ ),
+ 'validators' => array(
+ $this->getValidator(),
+ )
+ );
+ }
+
+ /**
+ * Clone the element (this is needed by Collection element, as it needs different copies of the elements)
+ */
+ public function __clone()
+ {
+ $this->dayElement = clone $this->dayElement;
+ $this->monthElement = clone $this->monthElement;
+ $this->yearElement = clone $this->yearElement;
+ }
+}
diff --git a/library/Zend/Form/Element/MonthSelect.php b/library/Zend/Form/Element/MonthSelect.php
new file mode 100644
index 00000000000..574cd4c5d32
--- /dev/null
+++ b/library/Zend/Form/Element/MonthSelect.php
@@ -0,0 +1,313 @@
+minYear = date('Y') - 100;
+ $this->maxYear = date('Y');
+
+ $this->monthElement = new Select('month');
+ $this->yearElement = new Select('year');
+
+ parent::__construct($name, $options);
+ }
+
+ /**
+ * Accepted options for DateSelect:
+ * - month_attributes: HTML attributes to be rendered with the month element
+ * - year_attributes: HTML attributes to be rendered with the month element
+ * - min_year: min year to use in the year select
+ * - max_year: max year to use in the year select
+ *
+ * @param array|\Traversable $options
+ * @return MonthSelect
+ */
+ public function setOptions($options)
+ {
+ parent::setOptions($options);
+
+ if (isset($options['month_attributes'])) {
+ $this->setMonthAttributes($options['month_attributes']);
+ }
+
+ if (isset($options['year_attributes'])) {
+ $this->setYearAttributes($options['year_attributes']);
+ }
+
+ if (isset($options['min_year'])) {
+ $this->setMinYear($options['min_year']);
+ }
+
+ if (isset($options['max_year'])) {
+ $this->setMaxYear($options['max_year']);
+ }
+
+ if (isset($options['create_empty_option'])) {
+ $this->setShouldCreateEmptyOption($options['create_empty_option']);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return Select
+ */
+ public function getMonthElement()
+ {
+ return $this->monthElement;
+ }
+
+ /**
+ * @return Select
+ */
+ public function getYearElement()
+ {
+ return $this->yearElement;
+ }
+
+ /**
+ * Set the month attributes
+ *
+ * @param array $monthAttributes
+ * @return MonthSelect
+ */
+ public function setMonthAttributes(array $monthAttributes)
+ {
+ $this->monthElement->setAttributes($monthAttributes);
+ return $this;
+ }
+
+ /**
+ * Get the month attributes
+ *
+ * @return array
+ */
+ public function getMonthAttributes()
+ {
+ return $this->monthElement->getAttributes();
+ }
+
+ /**
+ * Set the year attributes
+ *
+ * @param array $yearAttributes
+ * @return MonthSelect
+ */
+ public function setYearAttributes(array $yearAttributes)
+ {
+ $this->yearElement->setAttributes($yearAttributes);
+ return $this;
+ }
+
+ /**
+ * Get the year attributes
+ *
+ * @return array
+ */
+ public function getYearAttributes()
+ {
+ return $this->yearElement->getAttributes();
+ }
+
+ /**
+ * @param int $minYear
+ * @return MonthSelect
+ */
+ public function setMinYear($minYear)
+ {
+ $this->minYear = $minYear;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMinYear()
+ {
+ return $this->minYear;
+ }
+
+ /**
+ * @param int $maxYear
+ * @return MonthSelect
+ */
+ public function setMaxYear($maxYear)
+ {
+ $this->maxYear = $maxYear;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxYear()
+ {
+ return $this->maxYear;
+ }
+
+ /**
+ * @param bool $createEmptyOption
+ * @return MonthSelect
+ */
+ public function setShouldCreateEmptyOption($createEmptyOption)
+ {
+ $this->createEmptyOption = (bool) $createEmptyOption;
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function shouldCreateEmptyOption()
+ {
+ return $this->createEmptyOption;
+ }
+
+ /**
+ * @param mixed $value
+ * @return void|\Zend\Form\Element
+ */
+ public function setValue($value)
+ {
+ if ($value instanceof DateTime) {
+ $value = array(
+ 'year' => $value->format('Y'),
+ 'month' => $value->format('m')
+ );
+ }
+
+ $this->yearElement->setValue($value['year']);
+ $this->monthElement->setValue($value['month']);
+ }
+
+ /**
+ * Prepare the form element (mostly used for rendering purposes)
+ *
+ * @param Form $form
+ * @return mixed
+ */
+ public function prepareElement(Form $form)
+ {
+ $name = $this->getName();
+ $this->monthElement->setName($name . '[month]');
+ $this->yearElement->setName($name . '[year]');
+ }
+
+ /**
+ * Get validator
+ *
+ * @return ValidatorInterface
+ */
+ protected function getValidator()
+ {
+ return new RegexValidator('/^[0-9]{4}\-(0?[1-9]|1[012])$/');
+ }
+
+ /**
+ * Should return an array specification compatible with
+ * {@link Zend\InputFilter\Factory::createInput()}.
+ *
+ * @return array
+ */
+ public function getInputSpecification()
+ {
+ return array(
+ 'name' => $this->getName(),
+ 'required' => false,
+ 'filters' => array(
+ array(
+ 'name' => 'Callback',
+ 'options' => array(
+ 'callback' => function($date) {
+ // Convert the date to a specific format
+ if (is_array($date)) {
+ $date = $date['year'] . '-' . $date['month'];
+ }
+
+ return $date;
+ }
+ )
+ )
+ ),
+ 'validators' => array(
+ $this->getValidator(),
+ )
+ );
+ }
+
+ /**
+ * Clone the element (this is needed by Collection element, as it needs different copies of the elements)
+ */
+ public function __clone()
+ {
+ $this->monthElement = clone $this->monthElement;
+ $this->yearElement = clone $this->yearElement;
+ }
+}
diff --git a/library/Zend/Form/Factory.php b/library/Zend/Form/Factory.php
index 24d4eb37dbb..68e45b75a92 100644
--- a/library/Zend/Form/Factory.php
+++ b/library/Zend/Form/Factory.php
@@ -351,9 +351,9 @@ protected function prepareAndInjectObject($objectName, FieldsetInterface $fields
* Takes a string indicating a hydrator class name (or a concrete instance), instantiates the class
* by that name, and injects the hydrator instance into the form.
*
- * @param string $hydratorOrName
- * @param FieldsetInterface $fieldset
- * @param string $method
+ * @param string|array|Hydrator\HydratorInterface $hydratorOrName
+ * @param FieldsetInterface $fieldset
+ * @param string $method
* @return void
* @throws Exception\DomainException If $hydratorOrName is not a string, does not resolve to a known class, or
* the class does not implement Hydrator\HydratorInterface
@@ -365,14 +365,27 @@ protected function prepareAndInjectHydrator($hydratorOrName, FieldsetInterface $
return;
}
- if (!is_string($hydratorOrName)) {
+ if (!is_string($hydratorOrName) && !is_array($hydratorOrName)) {
throw new Exception\DomainException(sprintf(
- '%s expects string hydrator class name; received "%s"',
+ '%s expects string hydrator class name or an array specification; received "%s"',
$method,
(is_object($hydratorOrName) ? get_class($hydratorOrName) : gettype($hydratorOrName))
));
}
+ if (is_array($hydratorOrName)) {
+ if (!isset($hydratorOrName['type'])) {
+ throw new Exception\DomainException(sprintf(
+ '%s expects array specification to have a type value',
+ $method
+ ));
+ }
+ $hydratorOptions = (isset($hydratorOrName['options'])) ? $hydratorOrName['options'] : array();
+ $hydratorOrName = $hydratorOrName['type'];
+ } else {
+ $hydratorOptions = array();
+ }
+
if (!class_exists($hydratorOrName)) {
throw new Exception\DomainException(sprintf(
'%s expects string hydrator name to be a valid class name; received "%s"',
@@ -389,6 +402,9 @@ protected function prepareAndInjectHydrator($hydratorOrName, FieldsetInterface $
$hydratorOrName
));
}
+ if (!empty($hydratorOptions) && $hydrator instanceof Hydrator\HydratorOptionsInterface) {
+ $hydrator->setOptions($hydratorOptions);
+ }
$fieldset->setHydrator($hydrator);
}
diff --git a/library/Zend/Form/View/Helper/FormCollection.php b/library/Zend/Form/View/Helper/FormCollection.php
index f193c291aee..eab2caa9b81 100644
--- a/library/Zend/Form/View/Helper/FormCollection.php
+++ b/library/Zend/Form/View/Helper/FormCollection.php
@@ -65,13 +65,7 @@ public function render(ElementInterface $element)
$elementHelper = $this->getElementHelper();
if ($element instanceof CollectionElement && $element->shouldCreateTemplate()) {
- $elementOrFieldset = $element->getTemplateElement();
-
- if ($elementOrFieldset instanceof FieldsetInterface) {
- $templateMarkup .= $this->render($elementOrFieldset);
- } elseif ($elementOrFieldset instanceof ElementInterface) {
- $templateMarkup .= $elementHelper($elementOrFieldset);
- }
+ $templateMarkup = $this->renderTemplate($element);
}
foreach ($element->getIterator() as $elementOrFieldset) {
@@ -84,12 +78,7 @@ public function render(ElementInterface $element)
// If $templateMarkup is not empty, use it for simplify adding new element in JavaScript
if (!empty($templateMarkup)) {
- $escapeHtmlAttribHelper = $this->getEscapeHtmlAttrHelper();
-
- $markup .= sprintf(
- '',
- $escapeHtmlAttribHelper($templateMarkup)
- );
+ $markup .= $templateMarkup;
}
// Every collection is wrapped by a fieldset if needed
@@ -110,6 +99,32 @@ public function render(ElementInterface $element)
return $markup;
}
+ /**
+ * Only render a template
+ *
+ * @param CollectionElement $collection
+ * @return string
+ */
+ public function renderTemplate(CollectionElement $collection)
+ {
+ $elementHelper = $this->getElementHelper();
+ $escapeHtmlAttribHelper = $this->getEscapeHtmlAttrHelper();
+ $templateMarkup = '';
+
+ $elementOrFieldset = $collection->getTemplateElement();
+
+ if ($elementOrFieldset instanceof FieldsetInterface) {
+ $templateMarkup .= $this->render($elementOrFieldset);
+ } elseif ($elementOrFieldset instanceof ElementInterface) {
+ $templateMarkup .= $elementHelper($elementOrFieldset);
+ }
+
+ return sprintf(
+ '',
+ $escapeHtmlAttribHelper($templateMarkup)
+ );
+ }
+
/**
* Invoke helper as function
*
diff --git a/library/Zend/Form/View/Helper/FormDateSelect.php b/library/Zend/Form/View/Helper/FormDateSelect.php
new file mode 100644
index 00000000000..55a05c52cd6
--- /dev/null
+++ b/library/Zend/Form/View/Helper/FormDateSelect.php
@@ -0,0 +1,109 @@
+getName();
+ if ($name === null || $name === '') {
+ throw new Exception\DomainException(sprintf(
+ '%s requires that the element has an assigned name; none discovered',
+ __METHOD__
+ ));
+ }
+
+ $selectHelper = $this->getSelectElementHelper();
+ $pattern = $this->parsePattern();
+
+ $daysOptions = $this->getDaysOptions($pattern['day']);
+ $monthsOptions = $this->getMonthsOptions($pattern['month']);
+ $yearOptions = $this->getYearsOptions($element->getMinYear(), $element->getMaxYear());
+
+ $dayElement = $element->getDayElement()->setValueOptions($daysOptions);
+ $monthElement = $element->getMonthElement()->setValueOptions($monthsOptions);
+ $yearElement = $element->getYearElement()->setValueOptions($yearOptions);
+
+ if ($element->shouldCreateEmptyOption()) {
+ $dayElement->setEmptyOption('');
+ $yearElement->setEmptyOption('');
+ $monthElement->setEmptyOption('');
+ }
+
+ $markup = array();
+ $markup[$pattern['day']] = $selectHelper->render($dayElement);
+ $markup[$pattern['month']] = $selectHelper->render($monthElement);
+ $markup[$pattern['year']] = $selectHelper->render($yearElement);
+
+ $markup = sprintf(
+ '%s %s %s %s %s',
+ $markup[array_shift($pattern)],
+ array_shift($pattern), // Delimiter
+ $markup[array_shift($pattern)],
+ array_shift($pattern), // Delimiter
+ $markup[array_shift($pattern)]
+ );
+
+ return $markup;
+ }
+
+ /**
+ * Create a key => value options for days
+ *
+ * @param string $pattern Pattern to use for days
+ * @return array
+ */
+ protected function getDaysOptions($pattern)
+ {
+ $keyFormatter = new IntlDateFormatter($this->getLocale(), null, null, null, null, 'dd');
+ $valueFormatter = new IntlDateFormatter($this->getLocale(), null, null, null, null, $pattern);
+ $date = new DateTime('1970-01-01');
+
+ $result = array();
+ for ($day = 1; $day <= 31; $day++) {
+ $key = $keyFormatter->format($date);
+ $value = $valueFormatter->format($date);
+ $result[$key] = $value;
+
+ $date->modify('+1 day');
+ }
+
+ return $result;
+ }
+}
diff --git a/library/Zend/Form/View/Helper/FormElement.php b/library/Zend/Form/View/Helper/FormElement.php
index ab1d46c1aa3..7c4fb13638f 100644
--- a/library/Zend/Form/View/Helper/FormElement.php
+++ b/library/Zend/Form/View/Helper/FormElement.php
@@ -58,6 +58,16 @@ public function render(ElementInterface $element)
return $helper($element);
}
+ if ($element instanceof Element\DateSelect) {
+ $helper = $renderer->plugin('form_date_select');
+ return $helper($element);
+ }
+
+ if ($element instanceof Element\MonthSelect) {
+ $helper = $renderer->plugin('form_month_select');
+ return $helper($element);
+ }
+
$type = $element->getAttribute('type');
if ('checkbox' == $type) {
diff --git a/library/Zend/Form/View/Helper/FormMonthSelect.php b/library/Zend/Form/View/Helper/FormMonthSelect.php
new file mode 100644
index 00000000000..6f47247eac6
--- /dev/null
+++ b/library/Zend/Form/View/Helper/FormMonthSelect.php
@@ -0,0 +1,283 @@
+getName();
+ if ($name === null || $name === '') {
+ throw new Exception\DomainException(sprintf(
+ '%s requires that the element has an assigned name; none discovered',
+ __METHOD__
+ ));
+ }
+
+ $selectHelper = $this->getSelectElementHelper();
+ $pattern = $this->parsePattern();
+
+ // The pattern always contains "day" part and the first separator, so we have to remove it
+ unset($pattern['day']);
+ unset($pattern[0]);
+
+ $monthsOptions = $this->getMonthsOptions($pattern['month']);
+ $yearOptions = $this->getYearsOptions($element->getMinYear(), $element->getMaxYear());
+
+ $monthElement = $element->getMonthElement()->setValueOptions($monthsOptions);
+ $yearElement = $element->getYearElement()->setValueOptions($yearOptions);
+
+ if ($element->shouldCreateEmptyOption()) {
+ $monthElement->setEmptyOption('');
+ $yearElement->setEmptyOption('');
+ }
+
+ $markup = array();
+ $markup[$pattern['month']] = $selectHelper->render($monthElement);
+ $markup[$pattern['year']] = $selectHelper->render($yearElement);
+
+ $markup = sprintf(
+ '%s %s %s',
+ $markup[array_shift($pattern)],
+ array_shift($pattern), // Delimiter
+ $markup[array_shift($pattern)]
+ );
+
+ return $markup;
+ }
+
+ /**
+ * Invoke helper as function
+ *
+ * Proxies to {@link render()}.
+ *
+ * @param \Zend\Form\ElementInterface $element
+ * @param int $dateType
+ * @param null|string $locale
+ * @return FormDateSelect
+ */
+ public function __invoke(ElementInterface $element = null, $dateType = IntlDateFormatter::LONG, $locale = null)
+ {
+ if (!$element) {
+ return $this;
+ }
+
+ $this->setDateType($dateType);
+
+ if ($locale !== null) {
+ $this->setLocale($locale);
+ }
+
+ return $this->render($element);
+ }
+
+ /**
+ * @return string
+ */
+ public function getPattern()
+ {
+ if ($this->pattern === null) {
+ $intl = new IntlDateFormatter($this->getLocale(), $this->dateType, IntlDateFormatter::NONE);
+ $this->pattern = $intl->getPattern();
+ }
+
+ return $this->pattern;
+ }
+
+ /**
+ * Parse the pattern
+ *
+ * @return array
+ */
+ protected function parsePattern()
+ {
+ $pattern = $this->getPattern();
+ $pregResult = preg_split('/([ -,.\/]+)/', $pattern, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+
+ $result = array();
+ foreach ($pregResult as $value) {
+ if (stripos($value, 'd') !== false) {
+ $result['day'] = $value;
+ } elseif (stripos($value, 'm') !== false) {
+ $result['month'] = $value;
+ } elseif (stripos($value, 'y') !== false) {
+ $result['year'] = $value;
+ } else {
+ $result[] = $value;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param int $dateType
+ * @return FormDateSelect
+ */
+ public function setDateType($dateType)
+ {
+ // The FULL format uses values that are not used
+ if ($dateType === IntlDateFormatter::FULL) {
+ $dateType = IntlDateFormatter::LONG;
+ }
+
+ $this->dateType = $dateType;
+
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getDateType()
+ {
+ return $this->dateType;
+ }
+
+ /**
+ * @param string $locale
+ * @return FormDateSelect
+ */
+ public function setLocale($locale)
+ {
+ $this->locale = $locale;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLocale()
+ {
+ if ($this->locale === null) {
+ $this->locale = Locale::getDefault();
+ }
+
+ return $this->locale;
+ }
+
+ /**
+ * Create a key => value options for months
+ *
+ * @param string $pattern Pattern to use for months
+ * @return array
+ */
+ protected function getMonthsOptions($pattern)
+ {
+ $keyFormatter = new IntlDateFormatter($this->getLocale(), null, null, null, null, 'MM');
+ $valueFormatter = new IntlDateFormatter($this->getLocale(), null, null, null, null, $pattern);
+ $date = new DateTime('1970-01-01');
+
+ $result = array();
+ for ($month = 1; $month <= 12; $month++) {
+ $key = $keyFormatter->format($date);
+ $value = $valueFormatter->format($date);
+ $result[$key] = $value;
+
+ $date->modify('+1 month');
+ }
+
+ return $result;
+ }
+
+ /**
+ * Create a key => value options for years
+ * NOTE: we don't use a pattern for years, as years written as two digits can lead to hard to
+ * read date for users, so we only use four digits years
+ *
+ * @param int $minYear
+ * @param int $maxYear
+ * @return array
+ */
+ protected function getYearsOptions($minYear, $maxYear)
+ {
+ $result = array();
+ for ($i = $maxYear; $i >= $minYear; --$i) {
+ $result[$i] = $i;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Retrieve the FormSelect helper
+ *
+ * @return FormRow
+ */
+ protected function getSelectElementHelper()
+ {
+ if ($this->selectHelper) {
+ return $this->selectHelper;
+ }
+
+ if (method_exists($this->view, 'plugin')) {
+ $this->selectHelper = $this->view->plugin('formselect');
+ }
+
+ return $this->selectHelper;
+ }
+}
diff --git a/library/Zend/Form/View/HelperConfig.php b/library/Zend/Form/View/HelperConfig.php
index fe6590d65ba..aeada7947d2 100644
--- a/library/Zend/Form/View/HelperConfig.php
+++ b/library/Zend/Form/View/HelperConfig.php
@@ -43,6 +43,7 @@ class HelperConfig implements ConfigInterface
'formdate' => 'Zend\Form\View\Helper\FormDate',
'formdatetime' => 'Zend\Form\View\Helper\FormDateTime',
'formdatetimelocal' => 'Zend\Form\View\Helper\FormDateTimeLocal',
+ 'formdateselect' => 'Zend\Form\View\Helper\FormDateSelect',
'formelement' => 'Zend\Form\View\Helper\FormElement',
'formelementerrors' => 'Zend\Form\View\Helper\FormElementErrors',
'formemail' => 'Zend\Form\View\Helper\FormEmail',
@@ -52,6 +53,7 @@ class HelperConfig implements ConfigInterface
'forminput' => 'Zend\Form\View\Helper\FormInput',
'formlabel' => 'Zend\Form\View\Helper\FormLabel',
'formmonth' => 'Zend\Form\View\Helper\FormMonth',
+ 'formmonthselect' => 'Zend\Form\View\Helper\FormMonthSelect',
'formmulticheckbox' => 'Zend\Form\View\Helper\FormMultiCheckbox',
'formnumber' => 'Zend\Form\View\Helper\FormNumber',
'formpassword' => 'Zend\Form\View\Helper\FormPassword',
diff --git a/library/Zend/I18n/View/Helper/DateFormat.php b/library/Zend/I18n/View/Helper/DateFormat.php
index 279f0b5c6f0..da40cddd8aa 100644
--- a/library/Zend/I18n/View/Helper/DateFormat.php
+++ b/library/Zend/I18n/View/Helper/DateFormat.php
@@ -105,18 +105,19 @@ public function getlocale()
/**
* Format a date.
*
- * @param DateTime|integer|array $date
- * @param integer $dateType
- * @param integer $timeType
- * @param string $locale
+ * @param DateTime|integer|array $date
+ * @param int $dateType
+ * @param int $timeType
+ * @param string $locale
+ * @param string|null $pattern
* @return string
- * @throws Exception\RuntimeException
*/
public function __invoke(
$date,
$dateType = IntlDateFormatter::NONE,
$timeType = IntlDateFormatter::NONE,
- $locale = null
+ $locale = null,
+ $pattern = null
) {
if ($locale === null) {
$locale = $this->getlocale();
@@ -130,7 +131,9 @@ public function __invoke(
$locale,
$dateType,
$timeType,
- $timezone
+ $timezone,
+ IntlDateFormatter::GREGORIAN,
+ $pattern
);
}
diff --git a/library/Zend/I18n/View/Helper/Plural.php b/library/Zend/I18n/View/Helper/Plural.php
new file mode 100644
index 00000000000..10faf2a0080
--- /dev/null
+++ b/library/Zend/I18n/View/Helper/Plural.php
@@ -0,0 +1,84 @@
+rule = $pluralRule;
+
+ return $this;
+ }
+
+ /**
+ * Given an array of strings, a number and, if wanted, an optional locale (the default one is used
+ * otherwise), this picks the right string according to plural rules of the locale
+ *
+ * @param array|string $strings
+ * @param int $number
+ * @throws Exception\InvalidArgumentException
+ * @return string
+ */
+ public function __invoke($strings, $number)
+ {
+ if ($this->rule === null) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'No plural rule was set'
+ ));
+ }
+
+ if (!is_array($strings)) {
+ $strings = (array) $strings;
+ }
+
+ $pluralIndex = $this->rule->evaluate($number);
+
+ return $strings[$pluralIndex];
+ }
+}
diff --git a/library/Zend/I18n/View/HelperConfig.php b/library/Zend/I18n/View/HelperConfig.php
index 3dfe2782411..2034f194f3f 100644
--- a/library/Zend/I18n/View/HelperConfig.php
+++ b/library/Zend/I18n/View/HelperConfig.php
@@ -29,6 +29,7 @@ class HelperConfig implements ConfigInterface
'currencyformat' => 'Zend\I18n\View\Helper\CurrencyFormat',
'dateformat' => 'Zend\I18n\View\Helper\DateFormat',
'numberformat' => 'Zend\I18n\View\Helper\NumberFormat',
+ 'plural' => 'Zend\I18n\View\Helper\Plural',
'translate' => 'Zend\I18n\View\Helper\Translate',
'translateplural' => 'Zend\I18n\View\Helper\TranslatePlural',
);
diff --git a/library/Zend/Loader/ModuleAutoloader.php b/library/Zend/Loader/ModuleAutoloader.php
index c068c3592c8..05bc4ec077d 100644
--- a/library/Zend/Loader/ModuleAutoloader.php
+++ b/library/Zend/Loader/ModuleAutoloader.php
@@ -98,6 +98,29 @@ public function setOptions($options)
return $this;
}
+ /**
+ * Retrieves the class map for all loaded modules.
+ *
+ * @return array
+ */
+ public function getModuleClassMap()
+ {
+ return $this->moduleClassMap;
+ }
+
+ /**
+ * Sets the class map used to speed up the module autoloading.
+ *
+ * @param array $classmap
+ * @return ModuleLoader
+ */
+ public function setModuleClassMap(array $classmap)
+ {
+ $this->moduleClassMap = $classmap;
+
+ return $this;
+ }
+
/**
* Autoload a class
*
@@ -113,6 +136,11 @@ public function autoload($class)
return false;
}
+ if (isset($this->moduleClassMap[$class])) {
+ require_once $this->moduleClassMap[$class];
+ return $class;
+ }
+
$moduleName = substr($class, 0, -7);
if (isset($this->explicitPaths[$moduleName])) {
$classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class);
@@ -295,7 +323,8 @@ public function unregister()
public function registerPaths($paths)
{
if (!is_array($paths) && !$paths instanceof Traversable) {
- throw new \InvalidArgumentException(
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php';
+ throw new Exception\InvalidArgumentException(
'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s '
. 'registerPaths method must be an array or '
. 'implement the \\Traversable interface'
@@ -324,7 +353,8 @@ public function registerPaths($paths)
public function registerPath($path, $moduleName = false)
{
if (!is_string($path)) {
- throw new \InvalidArgumentException(sprintf(
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php';
+ throw new Exception\InvalidArgumentException(sprintf(
'Invalid path provided; must be a string, received %s',
gettype($path)
));
diff --git a/library/Zend/Log/Formatter/ChromePhp.php b/library/Zend/Log/Formatter/ChromePhp.php
new file mode 100644
index 00000000000..158f5b09fa8
--- /dev/null
+++ b/library/Zend/Log/Formatter/ChromePhp.php
@@ -0,0 +1,51 @@
+chromephp = $instance === null ? $this->getChromePhp() : $instance;
+ $this->formatter = new ChromePhpFormatter();
+ }
+
+ /**
+ * Write a message to the log.
+ *
+ * @param array $event event data
+ * @return void
+ */
+ protected function doWrite(array $event)
+ {
+ $line = $this->formatter->format($event);
+
+ switch ($event['priority']) {
+ case Logger::EMERG:
+ case Logger::ALERT:
+ case Logger::CRIT:
+ case Logger::ERR:
+ $this->chromephp->error($line);
+ break;
+ case Logger::WARN:
+ $this->chromephp->warn($line);
+ break;
+ case Logger::NOTICE:
+ case Logger::INFO:
+ $this->chromephp->info($line);
+ break;
+ case Logger::DEBUG:
+ $this->chromephp->trace($line);
+ break;
+ default:
+ $this->chromephp->log($line);
+ break;
+ }
+ }
+
+ /**
+ * Gets the ChromePhpInterface instance that is used for logging.
+ *
+ * @return ChromePhpInterface
+ */
+ public function getChromePhp()
+ {
+ // Remember: class names in strings are absolute; thus the class_exists
+ // here references the canonical name for the ChromePhp class
+ if (!$this->chromephp instanceof ChromePhpInterface
+ && class_exists('ChromePhp')
+ ) {
+ $this->setChromePhp(new ChromePhpBridge());
+ }
+ return $this->chromephp;
+ }
+
+ /**
+ * Sets the ChromePhpInterface instance that is used for logging.
+ *
+ * @param ChromePhpInterface $instance The instance to set.
+ * @return ChromePhp
+ */
+ public function setChromePhp(ChromePhpInterface $instance)
+ {
+ $this->chromephp = $instance;
+ return $this;
+ }
+}
diff --git a/library/Zend/Log/Writer/ChromePhp/ChromePhpBridge.php b/library/Zend/Log/Writer/ChromePhp/ChromePhpBridge.php
new file mode 100644
index 00000000000..d6a97655d64
--- /dev/null
+++ b/library/Zend/Log/Writer/ChromePhp/ChromePhpBridge.php
@@ -0,0 +1,71 @@
+writer = $writer;
+
+ if (null === $filterOrPriority) {
+ $filterOrPriority = new PriorityFilter(Logger::WARN);
+ } elseif (!$filterOrPriority instanceof FilterInterface) {
+ $filterOrPriority = new PriorityFilter($filterOrPriority);
+ }
+
+ $this->addFilter($filterOrPriority);
+ $this->bufferSize = $bufferSize;
+ }
+
+ /**
+ * Log a message to this writer.
+ *
+ * @param array $event log data event
+ * @return void
+ */
+ public function write(array $event)
+ {
+ $this->doWrite($event);
+ }
+
+ /**
+ * Check if buffered data should be flushed
+ *
+ * @param array $event event data
+ * @return boolean true if buffered data should be flushed
+ */
+ protected function isActivated(array $event)
+ {
+ foreach ($this->filters as $filter) {
+ if (!$filter->filter($event)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Write message to buffer or delegate event data to the wrapped writer
+ *
+ * @param array $event event data
+ * @return void
+ */
+ protected function doWrite(array $event)
+ {
+ if (!$this->buffering) {
+ $this->writer->write($event);
+ return;
+ }
+
+ $this->buffer[] = $event;
+
+ if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
+ array_shift($this->buffer);
+ }
+
+ if (!$this->isActivated($event)) {
+ return;
+ }
+
+ $this->buffering = false;
+
+ foreach ($this->buffer as $bufferedEvent) {
+ $this->writer->write($bufferedEvent);
+ }
+ }
+
+ /**
+ * Resets the state of the handler.
+ * Stops forwarding records to the wrapped writer
+ */
+ public function reset()
+ {
+ $this->buffering = true;
+ }
+
+ /**
+ * Stub in accordance to parent method signature.
+ * Fomatters must be set on the wrapped writer.
+ *
+ * @param Formatter $formatter
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ return $this->writer;
+ }
+
+ /**
+ * Record shutdown
+ *
+ * @return void
+ */
+ public function shutdown()
+ {
+ $this->writer->shutdown();
+ $this->buffer = null;
+ }
+}
diff --git a/library/Zend/Log/WriterPluginManager.php b/library/Zend/Log/WriterPluginManager.php
index 68ee6281fca..7e306ce507d 100644
--- a/library/Zend/Log/WriterPluginManager.php
+++ b/library/Zend/Log/WriterPluginManager.php
@@ -24,14 +24,15 @@ class WriterPluginManager extends AbstractPluginManager
* @var array
*/
protected $invokableClasses = array(
- 'db' => 'Zend\Log\Writer\Db',
- 'firephp' => 'Zend\Log\Writer\FirePhp',
- 'mail' => 'Zend\Log\Writer\Mail',
- 'mock' => 'Zend\Log\Writer\Mock',
- 'null' => 'Zend\Log\Writer\Null',
- 'stream' => 'Zend\Log\Writer\Stream',
- 'syslog' => 'Zend\Log\Writer\Syslog',
- 'zendmonitor' => 'Zend\Log\Writer\ZendMonitor',
+ 'db' => 'Zend\Log\Writer\Db',
+ 'fingerscrossed' => 'Zend\Log\Writer\FingersCrossed',
+ 'firephp' => 'Zend\Log\Writer\FirePhp',
+ 'mail' => 'Zend\Log\Writer\Mail',
+ 'mock' => 'Zend\Log\Writer\Mock',
+ 'null' => 'Zend\Log\Writer\Null',
+ 'stream' => 'Zend\Log\Writer\Stream',
+ 'syslog' => 'Zend\Log\Writer\Syslog',
+ 'zendmonitor' => 'Zend\Log\Writer\ZendMonitor',
);
/**
diff --git a/library/Zend/Mail/Message.php b/library/Zend/Mail/Message.php
index f70597afe30..014867d5b50 100644
--- a/library/Zend/Mail/Message.php
+++ b/library/Zend/Mail/Message.php
@@ -535,4 +535,25 @@ public function toString()
. Headers::EOL
. $this->getBodyText();
}
+
+ /**
+ * Instantiate from raw message string
+ *
+ * @todo Restore body to Mime\Message
+ * @param string $rawMessage
+ * @return Message
+ */
+ public static function fromString($rawMessage)
+ {
+ $message = new static();
+ $headers = null;
+ $content = null;
+ Mime\Decode::splitMessage($rawMessage, $headers, $content);
+ if ($headers->has('mime-version')) {
+ // todo - restore body to mime\message
+ }
+ $message->setHeaders($headers);
+ $message->setBody($content);
+ return $message;
+ }
}
diff --git a/library/Zend/Math/BigInteger/BigInteger.php b/library/Zend/Math/BigInteger/BigInteger.php
index ff7ab4cdd2b..052ed1252ab 100644
--- a/library/Zend/Math/BigInteger/BigInteger.php
+++ b/library/Zend/Math/BigInteger/BigInteger.php
@@ -15,7 +15,7 @@
* @package Zend_Math
* @subpackage BigInteger
*/
-class BigInteger
+abstract class BigInteger
{
/**
* Plugin manager for loading adapters
diff --git a/library/Zend/ModuleManager/Feature/FilterProviderInterface.php b/library/Zend/ModuleManager/Feature/FilterProviderInterface.php
new file mode 100644
index 00000000000..0599f92d6b8
--- /dev/null
+++ b/library/Zend/ModuleManager/Feature/FilterProviderInterface.php
@@ -0,0 +1,27 @@
+getOptions()->getConfigCacheEnabled()) {
- $this->updateCache();
+ if (
+ $this->getOptions()->getConfigCacheEnabled()
+ && false === $this->skipConfig
+ ) {
+ $configFile = $this->getOptions()->getConfigCacheFile();
+ $this->writeArrayToFile($configFile, $this->getMergedConfig(false));
}
return $this;
@@ -392,18 +396,4 @@ protected function getCachedConfig()
{
return include $this->getOptions()->getConfigCacheFile();
}
-
- /**
- * @return ConfigListener
- */
- protected function updateCache()
- {
- if (($this->getOptions()->getConfigCacheEnabled())
- && (false === $this->skipConfig)
- ) {
- $configFile = $this->getOptions()->getConfigCacheFile();
- $this->writeArrayToFile($configFile, $this->getMergedConfig(false));
- }
- return $this;
- }
}
diff --git a/library/Zend/ModuleManager/Listener/DefaultListenerAggregate.php b/library/Zend/ModuleManager/Listener/DefaultListenerAggregate.php
index 0404c3e34d3..f63a2bd78ee 100644
--- a/library/Zend/ModuleManager/Listener/DefaultListenerAggregate.php
+++ b/library/Zend/ModuleManager/Listener/DefaultListenerAggregate.php
@@ -12,7 +12,6 @@
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
-use Zend\Loader\ModuleAutoloader;
use Zend\ModuleManager\ModuleEvent;
use Zend\Stdlib\CallbackHandler;
@@ -47,10 +46,9 @@ public function attach(EventManagerInterface $events)
$options = $this->getOptions();
$configListener = $this->getConfigListener();
$locatorRegistrationListener = new LocatorRegistrationListener($options);
- $moduleAutoloader = new ModuleAutoloader($options->getModulePaths());
// High priority, we assume module autoloading (for FooNamespace\Module classes) should be available before anything else
- $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($moduleAutoloader, 'register'), 9000);
+ $this->listeners[] = $events->attach(new ModuleLoaderListener($options));
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE_RESOLVE, new ModuleResolverListener);
// High priority, because most other loadModule listeners will assume the module's classes are available via autoloading
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new AutoloaderListener($options), 9000);
diff --git a/library/Zend/ModuleManager/Listener/ListenerOptions.php b/library/Zend/ModuleManager/Listener/ListenerOptions.php
index c3f01fa0f1a..7bbf73edc66 100644
--- a/library/Zend/ModuleManager/Listener/ListenerOptions.php
+++ b/library/Zend/ModuleManager/Listener/ListenerOptions.php
@@ -57,6 +57,16 @@ class ListenerOptions extends AbstractOptions
*/
protected $cacheDir;
+ /**
+ * @var string
+ */
+ protected $moduleMapCacheEnabled = false;
+
+ /**
+ * @var string
+ */
+ protected $moduleMapCacheKey;
+
/**
* Get an array of paths where modules reside
*
@@ -72,7 +82,7 @@ public function getModulePaths()
*
* @param array|Traversable $modulePaths
* @throws Exception\InvalidArgumentException
- * @return ListenerOptions
+ * @return ListenerOptions Provides fluent interface
*/
public function setModulePaths($modulePaths)
{
@@ -84,6 +94,7 @@ public function setModulePaths($modulePaths)
__CLASS__, __METHOD__, gettype($modulePaths))
);
}
+
$this->modulePaths = $modulePaths;
return $this;
}
@@ -113,7 +124,7 @@ public function getConfigStaticPaths()
*
* @param array|Traversable $configGlobPaths
* @throws Exception\InvalidArgumentException
- * @return ListenerOptions
+ * @return ListenerOptions Provides fluent interface
*/
public function setConfigGlobPaths($configGlobPaths)
{
@@ -125,6 +136,7 @@ public function setConfigGlobPaths($configGlobPaths)
__CLASS__, __METHOD__, gettype($configGlobPaths))
);
}
+
$this->configGlobPaths = $configGlobPaths;
return $this;
}
@@ -134,7 +146,7 @@ public function setConfigGlobPaths($configGlobPaths)
*
* @param array|Traversable $configStaticPaths
* @throws Exception\InvalidArgumentException
- * @return ListenerOptions
+ * @return ListenerOptions Provides fluent interface
*/
public function setConfigStaticPaths($configStaticPaths)
{
@@ -146,6 +158,7 @@ public function setConfigStaticPaths($configStaticPaths)
__CLASS__, __METHOD__, gettype($configStaticPaths))
);
}
+
$this->configStaticPaths = $configStaticPaths;
return $this;
}
@@ -166,7 +179,7 @@ public function getExtraConfig()
*
* @param array|Traversable $extraConfig
* @throws Exception\InvalidArgumentException
- * @return ListenerOptions
+ * @return ListenerOptions Provides fluent interface
*/
public function setExtraConfig($extraConfig)
{
@@ -178,6 +191,7 @@ public function setExtraConfig($extraConfig)
__CLASS__, __METHOD__, gettype($extraConfig))
);
}
+
$this->extraConfig = $extraConfig;
return $this;
}
@@ -265,6 +279,60 @@ public function setCacheDir($cacheDir)
return $this;
}
+ /**
+ * Check if the module class map cache is enabled
+ *
+ * @return bool
+ */
+ public function getModuleMapCacheEnabled()
+ {
+ return $this->moduleMapCacheEnabled;
+ }
+
+ /**
+ * Set if the module class map cache should be enabled or not
+ *
+ * @param bool $enabled
+ * @return ListenerOptions
+ */
+ public function setModuleMapCacheEnabled($enabled)
+ {
+ $this->moduleMapCacheEnabled = (bool) $enabled;
+ return $this;
+ }
+
+ /**
+ * Get key used to create the cache file name
+ *
+ * @return string
+ */
+ public function getModuleMapCacheKey()
+ {
+ return (string) $this->moduleMapCacheKey;
+ }
+
+ /**
+ * Set key used to create the cache file name
+ *
+ * @param string $moduleMapCacheKey the value to be set
+ * @return ListenerOptions
+ */
+ public function setModuleMapCacheKey($moduleMapCacheKey)
+ {
+ $this->moduleMapCacheKey = $moduleMapCacheKey;
+ return $this;
+ }
+
+ /**
+ * Get the path to the module class map cache
+ *
+ * @return string
+ */
+ public function getModuleMapCacheFile()
+ {
+ return $this->getCacheDir() . '/module-classmap-cache.'.$this->getModuleMapCacheKey().'.php';
+ }
+
/**
* Normalize a path for insertion in the stack
*
diff --git a/library/Zend/ModuleManager/Listener/LocatorRegistrationListener.php b/library/Zend/ModuleManager/Listener/LocatorRegistrationListener.php
index 42e19c272e2..bec4ddab5ba 100644
--- a/library/Zend/ModuleManager/Listener/LocatorRegistrationListener.php
+++ b/library/Zend/ModuleManager/Listener/LocatorRegistrationListener.php
@@ -55,14 +55,14 @@ public function onLoadModule(ModuleEvent $e)
}
/**
- * loadModulesPost
+ * loadModules
*
* Once all the modules are loaded, loop
*
* @param Event $e
* @return void
*/
- public function onLoadModulesPost(Event $e)
+ public function onLoadModules(Event $e)
{
$moduleManager = $e->getTarget();
$events = $moduleManager->getEventManager()->getSharedManager();
@@ -122,7 +122,7 @@ public function onBootstrap(Event $e)
public function attach(EventManagerInterface $events)
{
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, array($this, 'onLoadModule'));
- $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModulesPost'), -1000);
+ $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModules'), -1000);
return $this;
}
diff --git a/library/Zend/ModuleManager/Listener/ModuleLoaderListener.php b/library/Zend/ModuleManager/Listener/ModuleLoaderListener.php
new file mode 100644
index 00000000000..15bbdbf0e4d
--- /dev/null
+++ b/library/Zend/ModuleManager/Listener/ModuleLoaderListener.php
@@ -0,0 +1,140 @@
+generateCache = $this->options->getModuleMapCacheEnabled();
+ $this->moduleLoader = new ModuleAutoloader($this->options->getModulePaths());
+
+ if ($this->hasCachedClassMap()) {
+ $this->generateCache = false;
+ $this->moduleLoader->setModuleClassMap($this->getCachedConfig());
+ }
+ }
+
+ /**
+ * Attach one or more listeners
+ *
+ * @param EventManagerInterface $events
+ * @return LocatorRegistrationListener
+ */
+ public function attach(EventManagerInterface $events)
+ {
+ $this->listeners[] = $events->attach(
+ ModuleEvent::EVENT_LOAD_MODULES,
+ array($this->moduleLoader, 'register'),
+ 9000
+ );
+
+ if ($this->generateCache) {
+ $this->listeners[] = $events->attach(
+ ModuleEvent::EVENT_LOAD_MODULES_POST,
+ array($this, 'onLoadModulesPost')
+ );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Detach all previously attached listeners
+ *
+ * @param EventManagerInterface $events
+ * @return void
+ */
+ public function detach(EventManagerInterface $events)
+ {
+ foreach ($this->listeners as $key => $listener) {
+ if ($events->detach($listener)) {
+ unset($this->listeners[$key]);
+ }
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ protected function hasCachedClassMap()
+ {
+ if (
+ $this->options->getModuleMapCacheEnabled()
+ && file_exists($this->options->getModuleMapCacheFile())
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ protected function getCachedConfig()
+ {
+ return include $this->options->getModuleMapCacheFile();
+ }
+
+ /**
+ * loadModulesPost
+ *
+ * Unregisters the ModuleLoader and generates the module class map cache.
+ *
+ * @param ModuleEvent $e
+ */
+ public function onLoadModulesPost(ModuleEvent $event)
+ {
+ $this->moduleLoader->unregister();
+ $this->writeArrayToFile(
+ $this->options->getModuleMapCacheFile(),
+ $this->moduleLoader->getModuleClassMap()
+ );
+ }
+}
diff --git a/library/Zend/ModuleManager/Listener/ModuleResolverListener.php b/library/Zend/ModuleManager/Listener/ModuleResolverListener.php
index 3a18625c3f6..8868790a745 100644
--- a/library/Zend/ModuleManager/Listener/ModuleResolverListener.php
+++ b/library/Zend/ModuleManager/Listener/ModuleResolverListener.php
@@ -10,6 +10,8 @@
namespace Zend\ModuleManager\Listener;
+use Zend\ModuleManager\ModuleEvent;
+
/**
* Module resolver listener
*
@@ -20,10 +22,10 @@
class ModuleResolverListener extends AbstractListener
{
/**
- * @param \Zend\EventManager\EventInterface $e
- * @return object
+ * @param ModuleEvent $e
+ * @return object|false False if module class does not exist
*/
- public function __invoke($e)
+ public function __invoke(ModuleEvent $e)
{
$moduleName = $e->getModuleName();
$class = $moduleName . '\Module';
diff --git a/library/Zend/Mvc/Controller/Plugin/Identity.php b/library/Zend/Mvc/Controller/Plugin/Identity.php
new file mode 100644
index 00000000000..9e30d89436e
--- /dev/null
+++ b/library/Zend/Mvc/Controller/Plugin/Identity.php
@@ -0,0 +1,64 @@
+authenticationService;
+ }
+
+ /**
+ * @param AuthenticationService $authenticationService
+ */
+ public function setAuthenticationService(AuthenticationService $authenticationService)
+ {
+ $this->authenticationService = $authenticationService;
+ }
+
+ /**
+ * Retrieve the current identity, if any.
+ *
+ * If none is present, returns null.
+ *
+ * @return mixed|null
+ * @throws Exception\RuntimeException
+ */
+ public function __invoke()
+ {
+ if (!$this->authenticationService instanceof AuthenticationService){
+ throw new Exception\RuntimeException('No AuthenticationService instance provided');
+ }
+ if (!$this->authenticationService->hasIdentity()) {
+ return null;
+ }
+ return $this->authenticationService->getIdentity();
+ }
+}
diff --git a/library/Zend/Mvc/Controller/Plugin/Redirect.php b/library/Zend/Mvc/Controller/Plugin/Redirect.php
index dfaf8db1ad6..c3fa8ffddbc 100644
--- a/library/Zend/Mvc/Controller/Plugin/Redirect.php
+++ b/library/Zend/Mvc/Controller/Plugin/Redirect.php
@@ -25,7 +25,6 @@ class Redirect extends AbstractPlugin
{
protected $event;
protected $response;
- protected $router;
/**
* Generates a URL based on a route
@@ -73,6 +72,16 @@ public function toUrl($url)
return $response;
}
+ /**
+ * Refresh to current route
+ *
+ * @return string
+ */
+ public function refresh()
+ {
+ return $this->toRoute(null, array(), array(), true);
+ }
+
/**
* Get the response
*
diff --git a/library/Zend/Mvc/Controller/PluginManager.php b/library/Zend/Mvc/Controller/PluginManager.php
index 5ef7cb0131a..4466dbb32fc 100644
--- a/library/Zend/Mvc/Controller/PluginManager.php
+++ b/library/Zend/Mvc/Controller/PluginManager.php
@@ -67,6 +67,17 @@ class PluginManager extends AbstractPluginManager
public function __construct(ConfigInterface $configuration = null)
{
parent::__construct($configuration);
+
+ $this->setFactory('identity', function ($plugins) {
+ $services = $plugins->getServiceLocator();
+ $plugin = new Plugin\Identity();
+ if (!$services->has('Zend\Authentication\AuthenticationService')) {
+ return $plugin;
+ }
+ $plugin->setAuthenticationService($services->get('Zend\Authentication\AuthenticationService'));
+ return $plugin;
+ });
+
$this->addInitializer(array($this, 'injectController'));
}
diff --git a/library/Zend/Mvc/Service/AbstractPluginManagerFactory.php b/library/Zend/Mvc/Service/AbstractPluginManagerFactory.php
index 90972d09886..049089520ad 100644
--- a/library/Zend/Mvc/Service/AbstractPluginManagerFactory.php
+++ b/library/Zend/Mvc/Service/AbstractPluginManagerFactory.php
@@ -12,7 +12,6 @@
use Zend\ServiceManager\AbstractPluginManager;
use Zend\ServiceManager\Di\DiAbstractServiceFactory;
-use Zend\ServiceManager\Di\DiServiceInitializer;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
@@ -31,23 +30,21 @@ abstract class AbstractPluginManagerFactory implements FactoryInterface
* the PLUGIN_MANGER_CLASS constant.
*
* @param ServiceLocatorInterface $serviceLocator
- * @return AbstractPluginManager
+ * @return \Zend\ServiceManager\AbstractPluginManager
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$pluginManagerClass = static::PLUGIN_MANAGER_CLASS;
+ /* @var $plugins \Zend\ServiceManager\AbstractPluginManager */
$plugins = new $pluginManagerClass;
$plugins->setServiceLocator($serviceLocator);
- $configuration = $serviceLocator->get('Config');
+ $configuration = $serviceLocator->get('Config');
+
if (isset($configuration['di']) && $serviceLocator->has('Di')) {
- $di = $serviceLocator->get('Di');
- $plugins->addAbstractFactory(
- new DiAbstractServiceFactory($di, DiAbstractServiceFactory::USE_SL_BEFORE_DI)
- );
- $plugins->addInitializer(
- new DiServiceInitializer($di, $serviceLocator)
- );
+ $plugins->addAbstractFactory($serviceLocator->get('DiAbstractServiceFactory'));
+ $plugins->addInitializer($serviceLocator->get('DiServiceInitializer'));
}
+
return $plugins;
}
}
diff --git a/library/Zend/Mvc/Service/ControllerLoaderFactory.php b/library/Zend/Mvc/Service/ControllerLoaderFactory.php
index be64bda0ad5..434271389fd 100644
--- a/library/Zend/Mvc/Service/ControllerLoaderFactory.php
+++ b/library/Zend/Mvc/Service/ControllerLoaderFactory.php
@@ -47,13 +47,7 @@ public function createService(ServiceLocatorInterface $serviceLocator)
$config = $serviceLocator->get('Config');
if (isset($config['di']) && isset($config['di']['allowed_controllers']) && $serviceLocator->has('Di')) {
- $diAbstractFactory = new DiStrictAbstractServiceFactory(
- $serviceLocator->get('Di'),
- DiStrictAbstractServiceFactory::USE_SL_BEFORE_DI
- );
- $diAbstractFactory->setAllowedServiceNames($config['di']['allowed_controllers']);
-
- $controllerLoader->addAbstractFactory($diAbstractFactory);
+ $controllerLoader->addAbstractFactory($serviceLocator->get('DiStrictAbstractServiceFactory'));
}
return $controllerLoader;
diff --git a/library/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php b/library/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php
new file mode 100644
index 00000000000..d54062ba12b
--- /dev/null
+++ b/library/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php
@@ -0,0 +1,42 @@
+get('Di'), DiAbstractServiceFactory::USE_SL_BEFORE_DI);
+
+ if ($serviceLocator instanceof ServiceManager) {
+ /* @var $serviceLocator ServiceManager */
+ $serviceLocator->addAbstractFactory($factory);
+ }
+
+ return $factory;
+ }
+}
diff --git a/library/Zend/Mvc/Service/DiFactory.php b/library/Zend/Mvc/Service/DiFactory.php
index 8c801713120..f208bfd4487 100644
--- a/library/Zend/Mvc/Service/DiFactory.php
+++ b/library/Zend/Mvc/Service/DiFactory.php
@@ -10,12 +10,10 @@
namespace Zend\Mvc\Service;
-use Zend\Di\Config as DiConfig;
+use Zend\Di\Config;
use Zend\Di\Di;
-use Zend\ServiceManager\Di\DiAbstractServiceFactory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
-use Zend\ServiceManager\ServiceManager;
/**
* @category Zend
@@ -43,14 +41,8 @@ public function createService(ServiceLocatorInterface $serviceLocator)
$config = $serviceLocator->get('Config');
if (isset($config['di'])) {
- $di->configure(new DiConfig($config['di']));
- }
-
- if ($serviceLocator instanceof ServiceManager) {
- /* @var $serviceLocator ServiceManager */
- $serviceLocator->addAbstractFactory(
- new DiAbstractServiceFactory($di, DiAbstractServiceFactory::USE_SL_BEFORE_DI)
- );
+ $config = new Config($config['di']);
+ $config->configure($di);
}
return $di;
diff --git a/library/Zend/Mvc/Service/DiServiceInitializerFactory.php b/library/Zend/Mvc/Service/DiServiceInitializerFactory.php
new file mode 100644
index 00000000000..60b337db3ff
--- /dev/null
+++ b/library/Zend/Mvc/Service/DiServiceInitializerFactory.php
@@ -0,0 +1,42 @@
+get('Di'), $serviceLocator);
+
+ if ($serviceLocator instanceof ServiceManager) {
+ /* @var $serviceLocator ServiceManager */
+ $serviceLocator->addInitializer($initializer);
+ }
+
+ return $initializer;
+ }
+}
diff --git a/library/Zend/Mvc/Service/DiStrictAbstractServiceFactoryFactory.php b/library/Zend/Mvc/Service/DiStrictAbstractServiceFactoryFactory.php
new file mode 100644
index 00000000000..6c1fd47e590
--- /dev/null
+++ b/library/Zend/Mvc/Service/DiStrictAbstractServiceFactoryFactory.php
@@ -0,0 +1,44 @@
+get('Di'),
+ DiStrictAbstractServiceFactory::USE_SL_BEFORE_DI
+ );
+ $config = $serviceLocator->get('Config');
+
+ if (isset($config['di']['allowed_controllers'])) {
+ $diAbstractFactory->setAllowedServiceNames($config['di']['allowed_controllers']);
+ }
+
+ return $diAbstractFactory;
+ }
+}
diff --git a/library/Zend/Mvc/Service/FilterManagerFactory.php b/library/Zend/Mvc/Service/FilterManagerFactory.php
new file mode 100644
index 00000000000..5685c91799a
--- /dev/null
+++ b/library/Zend/Mvc/Service/FilterManagerFactory.php
@@ -0,0 +1,36 @@
+addServiceManager(
+ 'ValidatorManager',
+ 'validators',
+ 'Zend\ModuleManager\Feature\ValidatorProviderInterface',
+ 'getValidatorConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'FilterManager',
+ 'filters',
+ 'Zend\ModuleManager\Feature\FilterProviderInterface',
+ 'getFilterConfig'
+ );
$events = $serviceLocator->get('EventManager');
$events->attach($defaultListeners);
diff --git a/library/Zend/Mvc/Service/ServiceListenerFactory.php b/library/Zend/Mvc/Service/ServiceListenerFactory.php
index c9fddf8db6d..15932da4ad5 100644
--- a/library/Zend/Mvc/Service/ServiceListenerFactory.php
+++ b/library/Zend/Mvc/Service/ServiceListenerFactory.php
@@ -45,26 +45,31 @@ class ServiceListenerFactory implements FactoryInterface
'RouteListener' => 'Zend\Mvc\RouteListener',
),
'factories' => array(
- 'Application' => 'Zend\Mvc\Service\ApplicationFactory',
- 'Config' => 'Zend\Mvc\Service\ConfigFactory',
- 'ControllerLoader' => 'Zend\Mvc\Service\ControllerLoaderFactory',
- 'ControllerPluginManager' => 'Zend\Mvc\Service\ControllerPluginManagerFactory',
- 'ConsoleAdapter' => 'Zend\Mvc\Service\ConsoleAdapterFactory',
- 'ConsoleRouter' => 'Zend\Mvc\Service\RouterFactory',
- 'DependencyInjector' => 'Zend\Mvc\Service\DiFactory',
- 'HttpRouter' => 'Zend\Mvc\Service\RouterFactory',
- 'Request' => 'Zend\Mvc\Service\RequestFactory',
- 'Response' => 'Zend\Mvc\Service\ResponseFactory',
- 'Router' => 'Zend\Mvc\Service\RouterFactory',
- 'ViewHelperManager' => 'Zend\Mvc\Service\ViewHelperManagerFactory',
- 'ViewFeedRenderer' => 'Zend\Mvc\Service\ViewFeedRendererFactory',
- 'ViewFeedStrategy' => 'Zend\Mvc\Service\ViewFeedStrategyFactory',
- 'ViewJsonRenderer' => 'Zend\Mvc\Service\ViewJsonRendererFactory',
- 'ViewJsonStrategy' => 'Zend\Mvc\Service\ViewJsonStrategyFactory',
- 'ViewManager' => 'Zend\Mvc\Service\ViewManagerFactory',
- 'ViewResolver' => 'Zend\Mvc\Service\ViewResolverFactory',
- 'ViewTemplateMapResolver' => 'Zend\Mvc\Service\ViewTemplateMapResolverFactory',
- 'ViewTemplatePathStack' => 'Zend\Mvc\Service\ViewTemplatePathStackFactory',
+ 'Application' => 'Zend\Mvc\Service\ApplicationFactory',
+ 'Config' => 'Zend\Mvc\Service\ConfigFactory',
+ 'ControllerLoader' => 'Zend\Mvc\Service\ControllerLoaderFactory',
+ 'ControllerPluginManager' => 'Zend\Mvc\Service\ControllerPluginManagerFactory',
+ 'ConsoleAdapter' => 'Zend\Mvc\Service\ConsoleAdapterFactory',
+ 'ConsoleRouter' => 'Zend\Mvc\Service\RouterFactory',
+ 'DependencyInjector' => 'Zend\Mvc\Service\DiFactory',
+ 'DiStrictAbstractServiceFactory' => 'Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory',
+ 'DiAbstractServiceFactory' => 'Zend\Mvc\Service\DiAbstractServiceFactoryFactory',
+ 'DiServiceInitializer' => 'Zend\Mvc\Service\DiServiceInitializerFactory',
+ 'FilterManager' => 'Zend\Mvc\Service\FilterManagerFactory',
+ 'HttpRouter' => 'Zend\Mvc\Service\RouterFactory',
+ 'Request' => 'Zend\Mvc\Service\RequestFactory',
+ 'Response' => 'Zend\Mvc\Service\ResponseFactory',
+ 'Router' => 'Zend\Mvc\Service\RouterFactory',
+ 'ValidatorManager' => 'Zend\Mvc\Service\ValidatorManagerFactory',
+ 'ViewHelperManager' => 'Zend\Mvc\Service\ViewHelperManagerFactory',
+ 'ViewFeedRenderer' => 'Zend\Mvc\Service\ViewFeedRendererFactory',
+ 'ViewFeedStrategy' => 'Zend\Mvc\Service\ViewFeedStrategyFactory',
+ 'ViewJsonRenderer' => 'Zend\Mvc\Service\ViewJsonRendererFactory',
+ 'ViewJsonStrategy' => 'Zend\Mvc\Service\ViewJsonStrategyFactory',
+ 'ViewManager' => 'Zend\Mvc\Service\ViewManagerFactory',
+ 'ViewResolver' => 'Zend\Mvc\Service\ViewResolverFactory',
+ 'ViewTemplateMapResolver' => 'Zend\Mvc\Service\ViewTemplateMapResolverFactory',
+ 'ViewTemplatePathStack' => 'Zend\Mvc\Service\ViewTemplatePathStackFactory',
),
'aliases' => array(
'Configuration' => 'Config',
diff --git a/library/Zend/Mvc/Service/ValidatorManagerFactory.php b/library/Zend/Mvc/Service/ValidatorManagerFactory.php
new file mode 100644
index 00000000000..da41f71712a
--- /dev/null
+++ b/library/Zend/Mvc/Service/ValidatorManagerFactory.php
@@ -0,0 +1,36 @@
+allow()).
+ *
+ * If a $privilege is not provided, then this method returns false if and only if the
+ * Role is denied access to at least one privilege upon the Resource. In other words, this
+ * method returns true if and only if the Role is allowed all privileges on the Resource.
+ *
+ * This method checks Role inheritance using a depth-first traversal of the Role registry.
+ * The highest priority parent (i.e., the parent most recently added) is checked first,
+ * and its respective parents are checked similarly before the lower-priority parents of
+ * the Role are checked.
+ *
+ * @param Role\RoleInterface|string $role
+ * @param Resource\ResourceInterface|string $resource
+ * @param string $privilege
+ * @return boolean
+ */
+ public function isAllowed($role = null, $resource = null, $privilege = null);
+}
diff --git a/library/Zend/Permissions/Rbac/AbstractIterator.php b/library/Zend/Permissions/Rbac/AbstractIterator.php
new file mode 100644
index 00000000000..be9fd93cf47
--- /dev/null
+++ b/library/Zend/Permissions/Rbac/AbstractIterator.php
@@ -0,0 +1,102 @@
+
+ * Return the current element
+ * @link http://php.net/manual/en/iterator.current.php
+ * @return mixed Can return any type.
+ */
+ public function current()
+ {
+ return $this->children[$this->index];
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Move forward to next element
+ * @link http://php.net/manual/en/iterator.next.php
+ * @return void Any returned value is ignored.
+ */
+ public function next()
+ {
+ $this->index++;
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Return the key of the current element
+ * @link http://php.net/manual/en/iterator.key.php
+ * @return scalar scalar on success, or null on failure.
+ */
+ public function key()
+ {
+ return $this->index;
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Checks if current position is valid
+ * @link http://php.net/manual/en/iterator.valid.php
+ * @return boolean The return value will be casted to boolean and then evaluated.
+ * Returns true on success or false on failure.
+ */
+ public function valid()
+ {
+ return isset($this->children[$this->index]);
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Rewind the Iterator to the first element
+ * @link http://php.net/manual/en/iterator.rewind.php
+ * @return void Any returned value is ignored.
+ */
+ public function rewind()
+ {
+ $this->index = 0;
+ }
+
+ /**
+ * (PHP 5 >= 5.1.0)
+ * Returns if an iterator can be created fot the current entry.
+ * @link http://php.net/manual/en/recursiveiterator.haschildren.php
+ * @return bool true if the current entry can be iterated over, otherwise returns false.
+ */
+ public function hasChildren()
+ {
+ return count($this->children) > 0;
+ }
+
+ /**
+ * (PHP 5 >= 5.1.0)
+ * Returns an iterator for the current entry.
+ * @link http://php.net/manual/en/recursiveiterator.getRoles.php
+ * @return RecursiveIterator An iterator for the current entry.
+ */
+ public function getChildren()
+ {
+ return $this->children[$this->index];
+ }
+}
diff --git a/library/Zend/Permissions/Rbac/AbstractRole.php b/library/Zend/Permissions/Rbac/AbstractRole.php
new file mode 100644
index 00000000000..85de86a11a6
--- /dev/null
+++ b/library/Zend/Permissions/Rbac/AbstractRole.php
@@ -0,0 +1,124 @@
+name;
+ }
+
+ /**
+ * Add permission to the role.
+ *
+ * @param $name
+ * @return AbstractRole
+ */
+ public function addPermission($name)
+ {
+ $this->permissions[$name] = true;
+
+ return $this;
+ }
+
+ /**
+ * Checks if a permission exists for this role or any child roles.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function hasPermission($name)
+ {
+ if (isset($this->permissions[$name])) {
+ return true;
+ }
+
+ $it = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::CHILD_FIRST);
+ foreach ($it as $leaf) {
+ /** @var AbstractRole $leaf */
+ if ($leaf->hasPermission($name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Add a child.
+ *
+ * @param AbstractRole|string $child
+ * @return Role
+ */
+ public function addChild($child)
+ {
+ if (is_string($child)) {
+ $child = new Role($child);
+ }
+ if (!$child instanceof AbstractRole) {
+ throw new Exception\InvalidArgumentException(
+ 'Child must be a string or instance of Zend\Permissions\Rbac\AbstractRole'
+ );
+ }
+
+ $child->setParent($this);
+ $this->children[] = $child;
+
+ return $this;
+ }
+
+ /**
+ * @param AbstractRole $parent
+ * @return AbstractRole
+ */
+ public function setParent($parent)
+ {
+ $this->parent = $parent;
+
+ return $this;
+ }
+
+ /**
+ * @return null|AbstractRole
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+}
diff --git a/library/Zend/Permissions/Rbac/AssertionInterface.php b/library/Zend/Permissions/Rbac/AssertionInterface.php
new file mode 100644
index 00000000000..868ed7fd616
--- /dev/null
+++ b/library/Zend/Permissions/Rbac/AssertionInterface.php
@@ -0,0 +1,27 @@
+createMissingRoles = $createMissingRoles;
+
+ return $this;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function getCreateMissingRoles()
+ {
+ return $this->createMissingRoles;
+ }
+
+ /**
+ * Add a child.
+ *
+ * @param string|AbstractRole $child
+ * @return AbstractRole
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addRole($child, $parents = null)
+ {
+ if (is_string($child)) {
+ $child = new Role($child);
+ }
+ if (!$child instanceof AbstractRole) {
+ throw new Exception\InvalidArgumentException(
+ 'Child must be a string or instance of Zend\Permissions\Rbac\AbstractRole'
+ );
+ }
+
+ if ($parents) {
+ if (!is_array($parents)) {
+ $parents = array($parents);
+ }
+ foreach ($parents as $parent) {
+ if ($this->createMissingRoles && !$this->hasRole($parent)) {
+ $this->addRole($parent);
+ }
+ $this->getRole($parent)->addChild($child);
+ }
+ }
+
+ $this->children[] = $child;
+
+ return $this;
+ }
+
+ /**
+ * Is a child with $name registered?
+ *
+ * @param \Zend\Permissions\Rbac\AbstractRole|string $objectOrName
+ * @return bool
+ */
+ public function hasRole($objectOrName)
+ {
+ try {
+ $this->getRole($objectOrName);
+
+ return true;
+ } catch (Exception\InvalidArgumentException $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Get a child.
+ *
+ * @param \Zend\Permissions\Rbac\AbstractRole|string $objectOrName
+ * @return AbstractRole
+ * @throws Exception\InvalidArgumentException
+ */
+ public function getRole($objectOrName)
+ {
+ if (!is_string($objectOrName) && !$objectOrName instanceof AbstractRole) {
+ throw new Exception\InvalidArgumentException(
+ 'Expected string or instance of \Zend\Permissions\Rbac\AbstractRole'
+ );
+ }
+
+ $it = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::CHILD_FIRST);
+ foreach ($it as $leaf) {
+ if ((is_string($objectOrName) && $leaf->getName() == $objectOrName) || $leaf == $objectOrName) {
+ return $leaf;
+ }
+ }
+
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'No child with name "%s" could be found',
+ is_object($objectOrName) ? $objectOrName->getName() : $objectOrName
+ ));
+ }
+
+ /**
+ * Determines if access is granted by checking the role and child roles for permission.
+ *
+ * @param string $permission
+ * @param \Zend\Permissions\Rbac\AssertionInterface|Callable|null $assert
+ */
+ public function isGranted($role, $permission, $assert = null)
+ {
+ if ($assert) {
+ if ($assert instanceof AssertionInterface) {
+ if (!$assert->assert($this)) {
+ return false;
+ }
+ } elseif (is_callable($assert)) {
+ if (!$assert($this)) {
+ return false;
+ }
+ } else {
+ throw new Exception\InvalidArgumentException(
+ 'Assertions must be a Callable or an instance of Zend\Permissions\Rbac\AssertionInterface'
+ );
+ }
+ }
+
+ if ($this->getRole($role)->hasPermission($permission)) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/library/Zend/Permissions/Rbac/Role.php b/library/Zend/Permissions/Rbac/Role.php
new file mode 100644
index 00000000000..b83e2c818d9
--- /dev/null
+++ b/library/Zend/Permissions/Rbac/Role.php
@@ -0,0 +1,27 @@
+name = $name;
+ }
+}
diff --git a/library/Zend/Serializer/Adapter/MsgPack.php b/library/Zend/Serializer/Adapter/MsgPack.php
new file mode 100644
index 00000000000..ee81d4df136
--- /dev/null
+++ b/library/Zend/Serializer/Adapter/MsgPack.php
@@ -0,0 +1,91 @@
+ 'Zend\Serializer\Adapter\IgBinary',
'json' => 'Zend\Serializer\Adapter\Json',
+ 'msgpack' => 'Zend\Serializer\Adapter\MsgPack',
'phpcode' => 'Zend\Serializer\Adapter\PhpCode',
'phpserialize' => 'Zend\Serializer\Adapter\PhpSerialize',
'pythonpickle' => 'Zend\Serializer\Adapter\PythonPickle',
diff --git a/library/Zend/Serializer/Serializer.php b/library/Zend/Serializer/Serializer.php
index af49627296c..7d7013894e3 100644
--- a/library/Zend/Serializer/Serializer.php
+++ b/library/Zend/Serializer/Serializer.php
@@ -16,7 +16,7 @@
* @category Zend
* @package Zend_Serializer
*/
-class Serializer
+abstract class Serializer
{
/**
* Plugin manager for loading adapters
diff --git a/library/Zend/ServiceManager/AbstractPluginManager.php b/library/Zend/ServiceManager/AbstractPluginManager.php
index 61704d45189..72e0fe0c821 100644
--- a/library/Zend/ServiceManager/AbstractPluginManager.php
+++ b/library/Zend/ServiceManager/AbstractPluginManager.php
@@ -69,9 +69,6 @@ public function __construct(ConfigInterface $configuration = null)
if ($instance instanceof ServiceLocatorAwareInterface) {
$instance->setServiceLocator($self);
}
- if ($instance instanceof ServiceManagerAwareInterface) {
- $instance->setServiceManager($self);
- }
});
}
diff --git a/library/Zend/Session/SaveHandler/MongoDB.php b/library/Zend/Session/SaveHandler/MongoDB.php
new file mode 100644
index 00000000000..578e06da1fd
--- /dev/null
+++ b/library/Zend/Session/SaveHandler/MongoDB.php
@@ -0,0 +1,201 @@
+getDatabase())) {
+ throw new InvalidArgumentException('The database option cannot be emtpy');
+ }
+
+ if (null === ($collection = $options->getCollection())) {
+ throw new InvalidArgumentException('The collection option cannot be emtpy');
+ }
+
+ $this->mongoCollection = $mongo->selectCollection($database, $collection);
+ $this->options = $options;
+ }
+
+ /**
+ * Open session
+ *
+ * @param string $savePath
+ * @param string $name
+ * @return boolean
+ */
+ public function open($savePath, $name)
+ {
+ // Note: session save path is not used
+ $this->sessionName = $name;
+ $this->lifetime = ini_get('session.gc_maxlifetime');
+
+ return true;
+ }
+
+ /**
+ * Close session
+ *
+ * @return boolean
+ */
+ public function close()
+ {
+ return true;
+ }
+
+ /**
+ * Read session data
+ *
+ * @param string $id
+ * @return string
+ */
+ public function read($id)
+ {
+ $session = $this->mongoCollection->findOne(array(
+ '_id' => $id,
+ $this->options->getNameField() => $this->sessionName,
+ ));
+
+ if (null !== $session) {
+ if ($session[$this->options->getModifiedField()] instanceof MongoDate &&
+ $session[$this->options->getModifiedField()]->sec +
+ $session[$this->options->getLifetimeField()] > time()) {
+ return $session[$this->options->getDataField()];
+ }
+ $this->destroy($id);
+ }
+
+ return '';
+ }
+
+ /**
+ * Write session data
+ *
+ * @param string $id
+ * @param string $data
+ * @return boolean
+ */
+ public function write($id, $data)
+ {
+ $saveOptions = array_replace(
+ $this->options->getSaveOptions(),
+ array('upsert' => true, 'multiple' => false)
+ );
+
+ $criteria = array(
+ '_id' => $id,
+ $this->options->getNameField() => $this->sessionName,
+ );
+
+ $newObj = array('$set' => array(
+ $this->options->getDataField() => (string) $data,
+ $this->options->getLifetimeField() => $this->lifetime,
+ $this->options->getModifiedField() => new MongoDate(),
+ ));
+
+ /* Note: a MongoCursorException will be thrown if a record with this ID
+ * already exists with a different session name, since the upsert query
+ * cannot insert a new document with the same ID and new session name.
+ * This should only happen if ID's are not unique or if the session name
+ * is altered mid-process.
+ */
+ $result = $this->mongoCollection->update($criteria, $newObj, $saveOptions);
+
+ return (bool) (isset($result['ok']) ? $result['ok'] : $result);
+ }
+
+ /**
+ * Destroy session
+ *
+ * @param string $id
+ * @return boolean
+ */
+ public function destroy($id)
+ {
+ $result = $this->mongoCollection->remove(array(
+ '_id' => $id,
+ $this->options->getNameField() => $this->sessionName,
+ ), $this->options->getSaveOptions());
+
+ return (bool) (isset($result['ok']) ? $result['ok'] : $result);
+ }
+
+ /**
+ * Garbage collection
+ *
+ * Note: MongoDB 2.2+ supports TTL collections, which may be used in place
+ * of this method by indexing with "modified" field with an
+ * "expireAfterSeconds" option.
+ *
+ * @see http://docs.mongodb.org/manual/tutorial/expire-data/
+ * @param int $maxlifetime
+ * @return boolean
+ */
+ public function gc($maxlifetime)
+ {
+ /* Note: unlike DbTableGateway, we do not use the lifetime field in
+ * each document. Doing so would require a $where query to work with the
+ * computed value (modified + lifetime) and be very inefficient.
+ */
+ $result = $this->mongoCollection->remove(array(
+ $this->options->getModifiedField() => array('$lt' => new MongoDate(time() - $maxlifetime)),
+ ), $this->options->getSaveOptions());
+
+ return (bool) (isset($result['ok']) ? $result['ok'] : $result);
+ }
+}
diff --git a/library/Zend/Session/SaveHandler/MongoDBOptions.php b/library/Zend/Session/SaveHandler/MongoDBOptions.php
new file mode 100644
index 00000000000..fccd89d4b8b
--- /dev/null
+++ b/library/Zend/Session/SaveHandler/MongoDBOptions.php
@@ -0,0 +1,260 @@
+ true);
+
+ /**
+ * Name field
+ *
+ * @var string
+ */
+ protected $nameField = 'name';
+
+ /**
+ * Data field
+ *
+ * @var string
+ */
+ protected $dataField = 'data';
+
+ /**
+ * Lifetime field
+ *
+ * @var string
+ */
+ protected $lifetimeField = 'lifetime';
+
+ /**
+ * Modified field
+ *
+ * @var string
+ */
+ protected $modifiedField = 'modified';
+
+ /**
+ * Set database name
+ *
+ * @param string $database
+ * @return MongoDBOptions
+ * @throws Zend\Session\Exception\InvalidArgumentException
+ */
+ public function setDatabase($database)
+ {
+ $database = (string) $database;
+ if (strlen($database) === 0) {
+ throw new InvalidArgumentException('$database must be a non-empty string');
+ }
+ $this->database = $database;
+ return $this;
+ }
+
+ /**
+ * Get database name
+ *
+ * @return string
+ */
+ public function getDatabase()
+ {
+ return $this->database;
+ }
+
+ /**
+ * Set collection name
+ *
+ * @param string $collection
+ * @return MongoDBOptions
+ * @throws Zend\Session\Exception\InvalidArgumentException
+ */
+ public function setCollection($collection)
+ {
+ $collection = (string) $collection;
+ if (strlen($collection) === 0) {
+ throw new InvalidArgumentException('$collection must be a non-empty string');
+ }
+ $this->collection = $collection;
+ return $this;
+ }
+
+ /**
+ * Get collection name
+ *
+ * @return string
+ */
+ public function getCollection()
+ {
+ return $this->collection;
+ }
+
+ /**
+ * Set save options
+ *
+ * @see http://php.net/manual/en/mongocollection.save.php
+ * @param array $saveOptions
+ * @return MongoDBOptions
+ */
+ public function setSaveOptions(array $saveOptions)
+ {
+ $this->saveOptions = $saveOptions;
+ return $this;
+ }
+
+ /**
+ * Get save options
+ *
+ * @return string
+ */
+ public function getSaveOptions()
+ {
+ return $this->saveOptions;
+ }
+
+ /**
+ * Set name field
+ *
+ * @param string $nameField
+ * @return MongoDBOptions
+ * @throws Zend\Session\Exception\InvalidArgumentException
+ */
+ public function setNameField($nameField)
+ {
+ $nameField = (string) $nameField;
+ if (strlen($nameField) === 0) {
+ throw new InvalidArgumentException('$nameField must be a non-empty string');
+ }
+ $this->nameField = $nameField;
+ return $this;
+ }
+
+ /**
+ * Get name field
+ *
+ * @return string
+ */
+ public function getNameField()
+ {
+ return $this->nameField;
+ }
+
+ /**
+ * Set data field
+ *
+ * @param string $dataField
+ * @return MongoDBOptions
+ * @throws Zend\Session\Exception\InvalidArgumentException
+ */
+ public function setDataField($dataField)
+ {
+ $dataField = (string) $dataField;
+ if (strlen($dataField) === 0) {
+ throw new InvalidArgumentException('$dataField must be a non-empty string');
+ }
+ $this->dataField = $dataField;
+ return $this;
+ }
+
+ /**
+ * Get data field
+ *
+ * @return string
+ */
+ public function getDataField()
+ {
+ return $this->dataField;
+ }
+
+ /**
+ * Set lifetime field
+ *
+ * @param string $lifetimeField
+ * @return MongoDBOptions
+ * @throws Zend\Session\Exception\InvalidArgumentException
+ */
+ public function setLifetimeField($lifetimeField)
+ {
+ $lifetimeField = (string) $lifetimeField;
+ if (strlen($lifetimeField) === 0) {
+ throw new InvalidArgumentException('$lifetimeField must be a non-empty string');
+ }
+ $this->lifetimeField = $lifetimeField;
+ return $this;
+ }
+
+ /**
+ * Get lifetime Field
+ *
+ * @return string
+ */
+ public function getLifetimeField()
+ {
+ return $this->lifetimeField;
+ }
+
+ /**
+ * Set Modified Field
+ *
+ * @param string $modifiedField
+ * @return MongoDBOptions
+ * @throws Zend\Session\Exception\InvalidArgumentException
+ */
+ public function setModifiedField($modifiedField)
+ {
+ $modifiedField = (string) $modifiedField;
+ if (strlen($modifiedField) === 0) {
+ throw new InvalidArgumentException('$modifiedField must be a non-empty string');
+ }
+ $this->modifiedField = $modifiedField;
+ return $this;
+ }
+
+ /**
+ * Get modified Field
+ *
+ * @return string
+ */
+ public function getModifiedField()
+ {
+ return $this->modifiedField;
+ }
+}
diff --git a/library/Zend/Stdlib/AbstractOptions.php b/library/Zend/Stdlib/AbstractOptions.php
index 86e69c3d51c..f9365e8112b 100644
--- a/library/Zend/Stdlib/AbstractOptions.php
+++ b/library/Zend/Stdlib/AbstractOptions.php
@@ -28,8 +28,6 @@ abstract class AbstractOptions implements ParameterObjectInterface
/**
* @param array|Traversable|null $options
- * @return AbstractOptions
- * @throws Exception\InvalidArgumentException
*/
public function __construct($options = null)
{
@@ -41,7 +39,7 @@ public function __construct($options = null)
/**
* @param array|Traversable $options
* @throws Exception\InvalidArgumentException
- * @return void
+ * @return AbstractOptions Provides fluent interface
*/
public function setFromArray($options)
{
@@ -55,6 +53,7 @@ public function setFromArray($options)
foreach ($options as $key => $value) {
$this->__set($key, $value);
}
+ return $this;
}
/**
@@ -115,6 +114,7 @@ public function __get($key)
. 'which must be defined'
);
}
+
return $this->{$getter}();
}
@@ -131,14 +131,14 @@ public function __isset($key)
/**
* @see ParameterObject::__unset()
* @param string $key
- * @return void
* @throws Exception\InvalidArgumentException
+ * @return void
*/
public function __unset($key)
{
try {
$this->__set($key, null);
- } catch (\InvalidArgumentException $e) {
+ } catch (Exception\BadMethodCallException $e) {
throw new Exception\InvalidArgumentException(
'The class property $' . $key . ' cannot be unset as'
. ' NULL is an invalid value for it',
diff --git a/library/Zend/Stdlib/Hydrator/AbstractHydrator.php b/library/Zend/Stdlib/Hydrator/AbstractHydrator.php
index 4b320f18f18..964dc95618e 100644
--- a/library/Zend/Stdlib/Hydrator/AbstractHydrator.php
+++ b/library/Zend/Stdlib/Hydrator/AbstractHydrator.php
@@ -11,6 +11,7 @@
namespace Zend\Stdlib\Hydrator;
use ArrayObject;
+use Zend\Stdlib\Exception;
use Zend\Stdlib\Hydrator\StrategyEnabledInterface;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;
@@ -44,7 +45,19 @@ public function __construct()
*/
public function getStrategy($name)
{
- return $this->strategies[$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['*'];
}
/**
@@ -55,7 +68,8 @@ public function getStrategy($name)
*/
public function hasStrategy($name)
{
- return array_key_exists($name, $this->strategies);
+ return array_key_exists($name, $this->strategies)
+ || array_key_exists('*', $this->strategies);
}
/**
diff --git a/library/Zend/Stdlib/Hydrator/ClassMethods.php b/library/Zend/Stdlib/Hydrator/ClassMethods.php
index ad565f88de5..73781adaa68 100644
--- a/library/Zend/Stdlib/Hydrator/ClassMethods.php
+++ b/library/Zend/Stdlib/Hydrator/ClassMethods.php
@@ -17,22 +17,61 @@
* @package Zend_Stdlib
* @subpackage Hydrator
*/
-class ClassMethods extends AbstractHydrator
+class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface
{
/**
* Flag defining whether array keys are underscore-separated (true) or camel case (false)
* @var boolean
*/
- protected $underscoreSeparatedKeys;
+ protected $underscoreSeparatedKeys = true;
/**
* Define if extract values will use camel case or name with underscore
- * @param boolean $underscoreSeparatedKeys
+ * @param boolean|array $underscoreSeparatedKeys
*/
public function __construct($underscoreSeparatedKeys = true)
{
parent::__construct();
+ $this->setUnderscoreSeparatedKeys($underscoreSeparatedKeys);
+ }
+
+ /**
+ * @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 boolean $underscoreSeparatedKeys
+ * @return ClassMethods
+ */
+ public function setUnderscoreSeparatedKeys($underscoreSeparatedKeys)
+ {
$this->underscoreSeparatedKeys = $underscoreSeparatedKeys;
+ return $this;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function getUnderscoreSeparatedKeys()
+ {
+ return $this->underscoreSeparatedKeys;
}
/**
diff --git a/library/Zend/Stdlib/Hydrator/HydratorOptionsInterface.php b/library/Zend/Stdlib/Hydrator/HydratorOptionsInterface.php
new file mode 100644
index 00000000000..056aca97e35
--- /dev/null
+++ b/library/Zend/Stdlib/Hydrator/HydratorOptionsInterface.php
@@ -0,0 +1,25 @@
+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 Serializer
+ */
+ 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;
+ }
+}
diff --git a/library/Zend/Tag/Cloud/DecoratorPluginManager.php b/library/Zend/Tag/Cloud/DecoratorPluginManager.php
index d885f53659e..316153c21c7 100644
--- a/library/Zend/Tag/Cloud/DecoratorPluginManager.php
+++ b/library/Zend/Tag/Cloud/DecoratorPluginManager.php
@@ -34,7 +34,7 @@ class DecoratorPluginManager extends AbstractPluginManager
protected $invokableClasses = array(
'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
'htmltag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
- 'tag' => 'Zend\Tag\Cloud\Decorator\Tag',
+ 'tag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
);
/**
diff --git a/library/Zend/Uri/UriFactory.php b/library/Zend/Uri/UriFactory.php
index 6871e3e1527..5e8490374e6 100644
--- a/library/Zend/Uri/UriFactory.php
+++ b/library/Zend/Uri/UriFactory.php
@@ -66,6 +66,23 @@ public static function unregisterScheme($scheme)
}
}
+ /**
+ * Get the class name for a registered scheme
+ *
+ * If provided scheme is not registered, will return NULL
+ *
+ * @param string $scheme
+ * @return string|null
+ */
+ public static function getRegisteredSchemeClass($scheme)
+ {
+ if (isset(static::$schemeClasses[$scheme])) {
+ return static::$schemeClasses[$scheme];
+ } else {
+ return null;
+ }
+ }
+
/**
* Create a URI from a string
*
diff --git a/library/Zend/Validator/IsInstanceOf.php b/library/Zend/Validator/IsInstanceOf.php
new file mode 100644
index 00000000000..52ce9d42384
--- /dev/null
+++ b/library/Zend/Validator/IsInstanceOf.php
@@ -0,0 +1,112 @@
+ "The input is not an instance of '%className%'",
+ );
+
+ /**
+ * Additional variables available for validation failure messages
+ *
+ * @var array
+ */
+ protected $messageVariables = array(
+ 'className' => 'className'
+ );
+
+ /**
+ * Class name
+ *
+ * @var string
+ */
+ protected $className;
+
+ /**
+ * Sets validator options
+ *
+ * @param array|Traversable $options
+ * @throws Exception\InvalidArgumentException
+ */
+ public function __construct($options = null)
+ {
+ if ($options instanceof Traversable) {
+ $options = iterator_to_array($options);
+ }
+
+ // If argument is not an array, consider first argument as class name
+ if (!is_array($options)) {
+ $options = func_get_args();
+
+ $tmpOptions = array();
+ $tmpOptions['className'] = array_shift($options);
+
+ $options = $tmpOptions;
+ }
+
+ if (!array_key_exists('className', $options)) {
+ throw new Exception\InvalidArgumentException('Missing option "className"');
+ }
+
+ parent::__construct($options);
+ }
+
+ /**
+ * Get class name
+ *
+ * @return string
+ */
+ public function getClassName()
+ {
+ return $this->className;
+ }
+
+ /**
+ * Set class name
+ *
+ * @param string $className
+ * @return self
+ */
+ public function setClassName($className)
+ {
+ $this->className = $className;
+ return $this;
+ }
+
+ /**
+ * Returns true if $value is instance of $this->className
+ *
+ * @param mixed $value
+ * @return boolean
+ */
+ public function isValid($value)
+ {
+ if ($value instanceof $this->className) {
+ return true;
+ }
+ $this->error(self::NOT_INSTANCE_OF);
+ return false;
+ }
+}
diff --git a/library/Zend/Validator/ValidatorPluginManager.php b/library/Zend/Validator/ValidatorPluginManager.php
index cbed58bd5ab..aef360a4131 100644
--- a/library/Zend/Validator/ValidatorPluginManager.php
+++ b/library/Zend/Validator/ValidatorPluginManager.php
@@ -95,6 +95,7 @@ class ValidatorPluginManager extends AbstractPluginManager
'int' => 'Zend\I18n\Validator\Int',
'ip' => 'Zend\Validator\Ip',
'isbn' => 'Zend\Validator\Isbn',
+ 'isinstanceof' => 'Zend\Validator\IsInstanceOf',
'lessthan' => 'Zend\Validator\LessThan',
'notempty' => 'Zend\Validator\NotEmpty',
'postcode' => 'Zend\I18n\Validator\PostCode',
diff --git a/library/Zend/Version/Version.php b/library/Zend/Version/Version.php
index f8ae2f55489..d1c6f57ebba 100644
--- a/library/Zend/Version/Version.php
+++ b/library/Zend/Version/Version.php
@@ -23,7 +23,7 @@ final class Version
/**
* Zend Framework version identification - see compareVersion()
*/
- const VERSION = '2.0.4dev';
+ const VERSION = '2.1.0dev';
/**
* Github Service Identifier for version information is retreived from
diff --git a/library/Zend/View/Helper/HeadLink.php b/library/Zend/View/Helper/HeadLink.php
index 280011f955c..63c381b3002 100644
--- a/library/Zend/View/Helper/HeadLink.php
+++ b/library/Zend/View/Helper/HeadLink.php
@@ -115,7 +115,7 @@ public function __invoke(array $attributes = null, $placement = Placeholder\Cont
*/
public function __call($method, $args)
{
- if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(?PStylesheet|Alternate)$/', $method, $matches)) {
+ if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(?PStylesheet|Alternate|Prev|Next)$/', $method, $matches)) {
$argc = count($args);
$action = $matches['action'];
$type = $matches['type'];
@@ -425,4 +425,34 @@ public function createDataAlternate(array $args)
$attributes = compact('rel', 'href', 'type', 'title', 'extras');
return $this->createData($attributes);
}
+
+ /**
+ * Create item for a prev relationship (mainly used for pagination)
+ *
+ * @param array $args
+ * @return stdClass
+ */
+ public function createDataPrev(array $args)
+ {
+ $rel = 'prev';
+ $href = (string) array_shift($args);
+
+ $attributes = compact('rel', 'href');
+ return $this->createData($attributes);
+ }
+
+ /**
+ * Create item for a prev relationship (mainly used for pagination)
+ *
+ * @param array $args
+ * @return stdClass
+ */
+ public function createDataNext(array $args)
+ {
+ $rel = 'next';
+ $href = (string) array_shift($args);
+
+ $attributes = compact('rel', 'href');
+ return $this->createData($attributes);
+ }
}
diff --git a/library/Zend/View/Helper/Identity.php b/library/Zend/View/Helper/Identity.php
new file mode 100644
index 00000000000..34dc8a234a3
--- /dev/null
+++ b/library/Zend/View/Helper/Identity.php
@@ -0,0 +1,65 @@
+authenticationService;
+ }
+
+ /**
+ * @param AuthenticationService $authenticationService
+ */
+ public function setAuthenticationService(AuthenticationService $authenticationService)
+ {
+ $this->authenticationService = $authenticationService;
+ }
+
+ /**
+ * Retrieve the current identity, if any.
+ *
+ * If none available, returns null.
+ *
+ * @return mixed|null
+ * @throws Exception\RuntimeException
+ */
+ public function __invoke()
+ {
+ if (!$this->authenticationService instanceof AuthenticationService){
+ throw new Exception\RuntimeException('No AuthenticationService instance provided');
+ }
+
+ if (!$this->authenticationService->hasIdentity()) {
+ return null;
+ }
+ return $this->authenticationService->getIdentity();
+ }
+}
diff --git a/library/Zend/View/Helper/Navigation/AbstractHelper.php b/library/Zend/View/Helper/Navigation/AbstractHelper.php
index 65203d96124..8c97074d3e1 100644
--- a/library/Zend/View/Helper/Navigation/AbstractHelper.php
+++ b/library/Zend/View/Helper/Navigation/AbstractHelper.php
@@ -69,7 +69,7 @@ abstract class AbstractHelper extends View\Helper\AbstractHtmlElement implements
/**
* ACL to use when iterating pages
*
- * @var Acl\Acl
+ * @var Acl\AclInterface
*/
protected $acl;
@@ -119,7 +119,7 @@ abstract class AbstractHelper extends View\Helper\AbstractHtmlElement implements
* Default ACL to use when iterating pages if not explicitly set in the
* instance by calling {@link setAcl()}
*
- * @var Acl\Acl
+ * @var Acl\AclInterface
*/
protected static $defaultAcl;
@@ -316,10 +316,10 @@ public function getIndent()
*
* Implements {@link HelperInterface::setAcl()}.
*
- * @param Acl\Acl $acl [optional] ACL object. Default is null.
+ * @param Acl\AclInterface $acl [optional] ACL object. Default is null.
* @return AbstractHelper fluent interface, returns self
*/
- public function setAcl(Acl\Acl $acl = null)
+ public function setAcl(Acl\AclInterface $acl = null)
{
$this->acl = $acl;
return $this;
@@ -331,7 +331,7 @@ public function setAcl(Acl\Acl $acl = null)
*
* Implements {@link HelperInterface::getAcl()}.
*
- * @return Acl\Acl|null ACL object or null
+ * @return Acl\AclInterface|null ACL object or null
*/
public function getAcl()
{
@@ -844,11 +844,11 @@ protected function normalizeId($value)
/**
* Sets default ACL to use if another ACL is not explicitly set
*
- * @param Acl\Acl $acl [optional] ACL object. Default is null, which
+ * @param Acl\AclInterface $acl [optional] ACL object. Default is null, which
* sets no ACL object.
* @return void
*/
- public static function setDefaultAcl(Acl\Acl $acl = null)
+ public static function setDefaultAcl(Acl\AclInterface $acl = null)
{
self::$defaultAcl = $acl;
}
diff --git a/library/Zend/View/Helper/Navigation/HelperInterface.php b/library/Zend/View/Helper/Navigation/HelperInterface.php
index 0870962d103..f954f405466 100644
--- a/library/Zend/View/Helper/Navigation/HelperInterface.php
+++ b/library/Zend/View/Helper/Navigation/HelperInterface.php
@@ -44,16 +44,16 @@ public function getContainer();
/**
* Sets ACL to use when iterating pages
*
- * @param Acl\Acl $acl [optional] ACL instance
+ * @param Acl\AclInterface $acl [optional] ACL instance
* @return HelperInterface fluent interface, returns self
*/
- public function setAcl(Acl\Acl $acl = null);
+ public function setAcl(Acl\AclInterface $acl = null);
/**
* Returns ACL or null if it isn't set using {@link setAcl()} or
* {@link setDefaultAcl()}
*
- * @return Acl\Acl|null ACL object or null
+ * @return Acl\AclInterface|null ACL object or null
*/
public function getAcl();
diff --git a/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php b/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php
index 37d52e701dd..d116fbea70e 100644
--- a/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php
+++ b/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php
@@ -98,6 +98,7 @@ public function __construct()
public function set($value)
{
$this->exchangeArray(array($value));
+ return $this;
}
/**
@@ -111,6 +112,7 @@ public function prepend($value)
$values = $this->getArrayCopy();
array_unshift($values, $value);
$this->exchangeArray($values);
+ return $this;
}
/**
diff --git a/library/Zend/View/HelperPluginManager.php b/library/Zend/View/HelperPluginManager.php
index 517c07a3dc9..aee4f6ef670 100644
--- a/library/Zend/View/HelperPluginManager.php
+++ b/library/Zend/View/HelperPluginManager.php
@@ -86,6 +86,17 @@ class HelperPluginManager extends AbstractPluginManager
public function __construct(ConfigInterface $configuration = null)
{
parent::__construct($configuration);
+
+ $this->setFactory('identity', function ($helpers) {
+ $services = $helpers->getServiceLocator();
+ $helper = new Helper\Identity();
+ if (!$services->has('Zend\Authentication\AuthenticationService')) {
+ return $helper;
+ }
+ $helper->setAuthenticationService($services->get('Zend\Authentication\AuthenticationService'));
+ return $helper;
+ });
+
$this->addInitializer(array($this, 'injectRenderer'))
->addInitializer(array($this, 'injectTranslator'));
}
diff --git a/tests/ZendTest/Code/Annotation/TestAsset/EntityWithAnnotations.php b/tests/ZendTest/Code/Annotation/TestAsset/EntityWithAnnotations.php
index 4ed63fd024a..7e59b7db381 100644
--- a/tests/ZendTest/Code/Annotation/TestAsset/EntityWithAnnotations.php
+++ b/tests/ZendTest/Code/Annotation/TestAsset/EntityWithAnnotations.php
@@ -10,6 +10,12 @@
namespace ZendTest\Code\Annotation\TestAsset;
+/**
+ * @Foo(first)
+ * @Bar(second)
+ * @Bar(third)
+ * @Bogus(does not exist)
+ */
class EntityWithAnnotations
{
/**
diff --git a/tests/ZendTest/Code/Generator/ClassGeneratorTest.php b/tests/ZendTest/Code/Generator/ClassGeneratorTest.php
index d813f23d693..e88330ad9e4 100644
--- a/tests/ZendTest/Code/Generator/ClassGeneratorTest.php
+++ b/tests/ZendTest/Code/Generator/ClassGeneratorTest.php
@@ -362,4 +362,19 @@ public function testPassingANamespacedClassnameShouldGenerateAClassnameWithoutIt
$received = $classGeneratorClass->generate();
$this->assertContains('class FunClass', $received, $received);
}
+
+ /**
+ * @group ZF2-151
+ */
+ public function testAddUses()
+ {
+ $classGenerator = new ClassGenerator();
+ $classGenerator->setName('My\Class');
+ $classGenerator->addUse('My\First\Use\Class');
+ $classGenerator->addUse('My\Second\Use\Class', 'MyAlias');
+ $generated = $classGenerator->generate();
+
+ $this->assertContains('use My\First\Use\Class;', $generated);
+ $this->assertContains('use My\Second\Use\Class as MyAlias;', $generated);
+ }
}
diff --git a/tests/ZendTest/Code/Scanner/ClassScannerTest.php b/tests/ZendTest/Code/Scanner/ClassScannerTest.php
index 3d7b6364900..fb415f1d842 100644
--- a/tests/ZendTest/Code/Scanner/ClassScannerTest.php
+++ b/tests/ZendTest/Code/Scanner/ClassScannerTest.php
@@ -11,10 +11,24 @@
namespace ZendTest\Code\Scanner;
use Zend\Code\Scanner\FileScanner;
+use Zend\Code\Annotation;
use PHPUnit_Framework_TestCase as TestCase;
class ClassScannerTest extends TestCase
{
+ protected $manager;
+
+ public function setUp()
+ {
+ $this->manager = new Annotation\AnnotationManager();
+
+ $genericParser = new Annotation\Parser\GenericAnnotationParser();
+ $genericParser->registerAnnotation('ZendTest\Code\Annotation\TestAsset\Foo');
+ $genericParser->registerAnnotation('ZendTest\Code\Annotation\TestAsset\Bar');
+
+ $this->manager->attach($genericParser);
+ }
+
public function testClassScannerHasClassInformation()
{
$file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php');
@@ -44,7 +58,6 @@ public function testClassScannerHasProperties()
{
$file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php');
$class = $file->getClass('ZendTest\Code\TestAsset\FooClass');
- $this->assertInternalType('array', $class->getPropertyNames());
$this->assertContains('bar', $class->getPropertyNames());
}
@@ -59,12 +72,22 @@ public function testClassScannerReturnsMethodsWithMethodScanners()
{
$file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php');
$class = $file->getClass('ZendTest\Code\TestAsset\FooClass');
- $methods = $class->getMethods(true);
+ $methods = $class->getMethods();
foreach ($methods as $method) {
$this->assertInstanceOf('Zend\Code\Scanner\MethodScanner', $method);
}
}
+ public function testClassScannerReturnsPropertiesWithPropertyScanners()
+ {
+ $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php');
+ $class = $file->getClass('ZendTest\Code\TestAsset\FooClass');
+ $properties = $class->getProperties();
+ foreach ($properties as $property) {
+ $this->assertInstanceOf('Zend\Code\Scanner\PropertyScanner', $property);
+ }
+ }
+
public function testClassScannerCanScanInterface()
{
$file = new FileScanner(__DIR__ . '/../TestAsset/FooInterface.php');
@@ -77,7 +100,7 @@ public function testClassScannerCanReturnLineNumbers()
$file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php');
$class = $file->getClass('ZendTest\Code\TestAsset\FooClass');
$this->assertEquals(11, $class->getLineStart());
- $this->assertEquals(23, $class->getLineEnd());
+ $this->assertEquals(31, $class->getLineEnd());
$file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php');
$class = $file->getClass('ZendTest\Code\TestAsset\BarClass');
@@ -85,4 +108,17 @@ public function testClassScannerCanReturnLineNumbers()
$this->assertEquals(33, $class->getLineEnd());
}
+ public function testClassScannerCanScanAnnotations()
+ {
+ $file = new FileScanner(__DIR__ . '/../Annotation/TestAsset/EntityWithAnnotations.php');
+ $class = $file->getClass('ZendTest\Code\Annotation\TestAsset\EntityWithAnnotations');
+ $annotations = $class->getAnnotations($this->manager);
+
+ $this->assertTrue($annotations->hasAnnotation('ZendTest\Code\Annotation\TestAsset\Foo'));
+ $this->assertTrue($annotations->hasAnnotation('ZendTest\Code\Annotation\TestAsset\Bar'));
+
+ $this->assertEquals('first', $annotations[0]->content);
+ $this->assertEquals('second', $annotations[1]->content);
+ $this->assertEquals('third', $annotations[2]->content);
+ }
}
diff --git a/tests/ZendTest/Code/Scanner/PropertyScannerTest.php b/tests/ZendTest/Code/Scanner/PropertyScannerTest.php
new file mode 100644
index 00000000000..fc9754ad384
--- /dev/null
+++ b/tests/ZendTest/Code/Scanner/PropertyScannerTest.php
@@ -0,0 +1,47 @@
+getClass('ZendTest\Code\TestAsset\FooClass');
+
+ $property = $class->getProperty('bar');
+ $this->assertEquals('bar', $property->getName());
+ $this->assertEquals('value', $property->getValue());
+ $this->assertFalse($property->isPublic());
+ $this->assertTrue($property->isProtected());
+ $this->assertFalse($property->isPrivate());
+ $this->assertTrue($property->isStatic());
+
+ $property = $class->getProperty('foo');
+ $this->assertEquals('foo', $property->getName());
+ $this->assertEquals('value2', $property->getValue());
+ $this->assertTrue($property->isPublic());
+ $this->assertFalse($property->isProtected());
+ $this->assertFalse($property->isPrivate());
+ $this->assertFalse($property->isStatic());
+
+ $property = $class->getProperty('baz');
+ $this->assertEquals('baz', $property->getName());
+ $this->assertEquals(3, $property->getValue());
+ $this->assertFalse($property->isPublic());
+ $this->assertFalse($property->isProtected());
+ $this->assertTrue($property->isPrivate());
+ $this->assertFalse($property->isStatic());
+ }
+}
diff --git a/tests/ZendTest/Code/TestAsset/FooClass.php b/tests/ZendTest/Code/TestAsset/FooClass.php
index b2e55de23cd..54b0cc70937 100644
--- a/tests/ZendTest/Code/TestAsset/FooClass.php
+++ b/tests/ZendTest/Code/TestAsset/FooClass.php
@@ -14,6 +14,14 @@ abstract class FooClass implements \ArrayAccess, E\Blarg, Local\SubClass
const FOO = self::BAR;
protected static $bar = 'value';
+ public $foo = 'value2';
+
+ /**
+ * Test comment
+ *
+ * @var int
+ */
+ private $baz = 3;
final public function fooBarBaz()
{
diff --git a/tests/ZendTest/Config/FactoryTest.php b/tests/ZendTest/Config/FactoryTest.php
index 3f5d724f520..3f72b74f3cd 100644
--- a/tests/ZendTest/Config/FactoryTest.php
+++ b/tests/ZendTest/Config/FactoryTest.php
@@ -20,6 +20,28 @@
*/
class FactoryTest extends \PHPUnit_Framework_TestCase
{
+ protected $tmpFiles = array();
+
+ protected function getTestAssetFileName($ext)
+ {
+ if (empty($this->tmpfiles[$ext])) {
+ $this->tmpfiles[$ext] = tempnam(sys_get_temp_dir(), 'zend-config-writer').'.'.$ext;
+ }
+ return $this->tmpfiles[$ext];
+ }
+
+ public function tearDown()
+ {
+ foreach($this->tmpFiles as $file) {
+ if (file_exists($file)) {
+ if (!is_writable($file)) {
+ chmod($file, 0777);
+ }
+ @unlink($file);
+ }
+ }
+ }
+
public function testFromIni()
{
$config = Factory::fromFile(__DIR__ . '/TestAssets/Ini/include-base.ini');
@@ -125,7 +147,7 @@ public function testFactoryCanRegisterCustomReaderInstance()
$this->assertEquals($configObject['one'], 1);
}
- public function testFactoryCanRegisterCustomReaderPlugn()
+ public function testFactoryCanRegisterCustomReaderPlugin()
{
$dummyReader = new Reader\TestAssets\DummyReader();
Factory::getReaderPluginManager()->setService('DummyReader', $dummyReader);
@@ -138,5 +160,73 @@ public function testFactoryCanRegisterCustomReaderPlugn()
$this->assertEquals($configObject['one'], 1);
}
+ public function testFactoryToFileInvalidFileExtension()
+ {
+ $this->setExpectedException('RuntimeException');
+ $result = Factory::toFile(__DIR__.'/TestAssets/bad.ext', array());
+ }
+
+ public function testFactoryToFileNoDirInHere()
+ {
+ $this->setExpectedException('RuntimeException');
+ $result = Factory::toFile(__DIR__.'/TestAssets/NoDirInHere/nonExisiting/dummy.php', array());
+ }
+
+ public function testFactoryWriteToFile()
+ {
+ $config = array('test' => 'foo', 'bar' => array(0 => 'baz', 1 => 'foo'));
+
+ $file = $this->getTestAssetFileName('php');
+ $result = Factory::toFile($file, $config);
+
+ // build string line by line as we are trailing-whitespace sensitive.
+ $expected = " 'foo',\n";
+ $expected .= " 'bar' => \n";
+ $expected .= " array (\n";
+ $expected .= " 0 => 'baz',\n";
+ $expected .= " 1 => 'foo',\n";
+ $expected .= " ),\n";
+ $expected .= ");\n";
+
+ $this->assertEquals(true, $result);
+ $this->assertEquals($expected, file_get_contents($file));
+ }
+
+ public function testFactoryToFileWrongConfig()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ $result = Factory::toFile('test.ini', 'Im wrong');
+ }
+
+ public function testFactoryRegisterInvalidWriter()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+ Factory::registerWriter('dum', new Reader\TestAssets\DummyReader());
+ }
+
+ public function testFactoryCanRegisterCustomWriterInstance()
+ {
+ Factory::registerWriter('dum', new Writer\TestAssets\DummyWriter());
+
+ $file = $this->getTestAssetFileName('dum');
+ $res = Factory::toFile($file, array('one' => 1));
+
+ $this->assertEquals($res, true);
+ }
+
+ public function testFactoryCanRegisterCustomWriterPlugin()
+ {
+ $dummyWriter = new Writer\TestAssets\DummyWriter();
+ Factory::getWriterPluginManager()->setService('DummyWriter', $dummyWriter);
+
+ Factory::registerWriter('dum', 'DummyWriter');
+
+ $file = $this->getTestAssetFileName('dum');
+
+ $res = Factory::toFile($file, array('one' => 1));
+ $this->assertEquals($res, true);
+ }
}
diff --git a/tests/ZendTest/Config/Writer/TestAssets/DummyWriter.php b/tests/ZendTest/Config/Writer/TestAssets/DummyWriter.php
new file mode 100755
index 00000000000..d5a989ccc15
--- /dev/null
+++ b/tests/ZendTest/Config/Writer/TestAssets/DummyWriter.php
@@ -0,0 +1,22 @@
+assertEquals('69ea60798d71616cce5fd0871e23754cd75d5a0a', $hmac);
}
- public function testEmptyKey()
- {
- $this->setExpectedException('Zend\Crypt\Exception\InvalidArgumentException',
- 'Provided key is null or empty');
- $hash = HMAC::compute(null, 'md5', 'test');
- }
-
public function testWrongHashAlgorithm()
{
$this->setExpectedException('Zend\Crypt\Exception\InvalidArgumentException',
diff --git a/tests/ZendTest/Crypt/Key/Derivation/ScryptTest.php b/tests/ZendTest/Crypt/Key/Derivation/ScryptTest.php
new file mode 100644
index 00000000000..0a8498c1b07
--- /dev/null
+++ b/tests/ZendTest/Crypt/Key/Derivation/ScryptTest.php
@@ -0,0 +1,196 @@
+getMethod($name);
+ $method->setAccessible(true);
+ return $method;
+ }
+
+ /**
+ * Test vector of Salsa 20/8 core
+ *
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-7
+ */
+ public function testVectorSalsa208Core()
+ {
+ $hexInput = '7e 87 9a 21 4f 3e c9 86 7c a9 40 e6 41 71 8f 26
+ ba ee 55 5b 8c 61 c1 b5 0d f8 46 11 6d cd 3b 1d
+ ee 24 f3 19 df 9b 3d 85 14 12 1e 4b 5a c5 aa 32
+ 76 02 1d 29 09 c7 48 29 ed eb c6 8d b8 b8 c2 5e';
+
+ $hexOutput = 'a4 1f 85 9c 66 08 cc 99 3b 81 ca cb 02 0c ef 05
+ 04 4b 21 81 a2 fd 33 7d fd 7b 1c 63 96 68 2f 29
+ b4 39 31 68 e3 c9 e6 bc fe 6b c5 b7 a0 6d 96 ba
+ e4 24 cc 10 2c 91 74 5c 24 ad 67 3d c7 61 8f 81';
+
+
+ $salsaAlg = 'salsa208Core32';
+ if (PHP_INT_SIZE === 8) {
+ $salsaAlg = 'salsa208Core64';
+ }
+ $salsa20 = self::getMethod($salsaAlg);
+ $obj = $this->getMockForAbstractClass('Zend\Crypt\Key\Derivation\Scrypt');
+ $input = self::hex2bin(str_replace(array(' ',"\n"),'',$hexInput));
+ $result = $salsa20->invokeArgs($obj, array($input));
+
+ $this->assertEquals(64, strlen($input), 'Input must be a string of 64 bytes');
+ $this->assertEquals(64, strlen($result), 'Output must be a string of 64 bytes');
+ $this->assertEquals(str_replace(array(' ',"\n"),'',$hexOutput), bin2hex($result));
+ }
+ /**
+ * Test vector of Scrypt BlockMix
+ *
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-8
+ */
+ public function testVectorScryptBlockMix()
+ {
+ $hexInput = 'f7 ce 0b 65 3d 2d 72 a4 10 8c f5 ab e9 12 ff dd
+ 77 76 16 db bb 27 a7 0e 82 04 f3 ae 2d 0f 6f ad
+ 89 f6 8f 48 11 d1 e8 7b cc 3b d7 40 0a 9f fd 29
+ 09 4f 01 84 63 95 74 f3 9a e5 a1 31 52 17 bc d7
+
+ 89 49 91 44 72 13 bb 22 6c 25 b5 4d a8 63 70 fb
+ cd 98 43 80 37 46 66 bb 8f fc b5 bf 40 c2 54 b0
+ 67 d2 7c 51 ce 4a d5 fe d8 29 c9 0b 50 5a 57 1b
+ 7f 4d 1c ad 6a 52 3c da 77 0e 67 bc ea af 7e 89';
+
+ $hexOutput = 'a4 1f 85 9c 66 08 cc 99 3b 81 ca cb 02 0c ef 05
+ 04 4b 21 81 a2 fd 33 7d fd 7b 1c 63 96 68 2f 29
+ b4 39 31 68 e3 c9 e6 bc fe 6b c5 b7 a0 6d 96 ba
+ e4 24 cc 10 2c 91 74 5c 24 ad 67 3d c7 61 8f 81
+
+ 20 ed c9 75 32 38 81 a8 05 40 f6 4c 16 2d cd 3c
+ 21 07 7c fe 5f 8d 5f e2 b1 a4 16 8f 95 36 78 b7
+ 7d 3b 3d 80 3b 60 e4 ab 92 09 96 e5 9b 4d 53 b6
+ 5d 2a 22 58 77 d5 ed f5 84 2c b9 f1 4e ef e4 25';
+
+ $blockMix = self::getMethod('scryptBlockMix');
+ $obj = $this->getMockForAbstractClass('Zend\Crypt\Key\Derivation\Scrypt');
+ $input = self::hex2bin(str_replace(array(' ',"\n"), '', $hexInput));
+ $result = $blockMix->invokeArgs($obj, array($input, 1));
+
+ $this->assertEquals(str_replace(array(' ',"\n"),'',$hexOutput), bin2hex($result));
+ }
+
+ /**
+ * Test vector of Scrypt ROMix
+ *
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-9
+ */
+ public function testVectorScryptROMix()
+ {
+ $hexInput = 'f7 ce 0b 65 3d 2d 72 a4 10 8c f5 ab e9 12 ff dd
+ 77 76 16 db bb 27 a7 0e 82 04 f3 ae 2d 0f 6f ad
+ 89 f6 8f 48 11 d1 e8 7b cc 3b d7 40 0a 9f fd 29
+ 09 4f 01 84 63 95 74 f3 9a e5 a1 31 52 17 bc d7
+ 89 49 91 44 72 13 bb 22 6c 25 b5 4d a8 63 70 fb
+ cd 98 43 80 37 46 66 bb 8f fc b5 bf 40 c2 54 b0
+ 67 d2 7c 51 ce 4a d5 fe d8 29 c9 0b 50 5a 57 1b
+ 7f 4d 1c ad 6a 52 3c da 77 0e 67 bc ea af 7e 89';
+
+ $hexOutput = '79 cc c1 93 62 9d eb ca 04 7f 0b 70 60 4b f6 b6
+ 2c e3 dd 4a 96 26 e3 55 fa fc 61 98 e6 ea 2b 46
+ d5 84 13 67 3b 99 b0 29 d6 65 c3 57 60 1f b4 26
+ a0 b2 f4 bb a2 00 ee 9f 0a 43 d1 9b 57 1a 9c 71
+ ef 11 42 e6 5d 5a 26 6f dd ca 83 2c e5 9f aa 7c
+ ac 0b 9c f1 be 2b ff ca 30 0d 01 ee 38 76 19 c4
+ ae 12 fd 44 38 f2 03 a0 e4 e1 c4 7e c3 14 86 1f
+ 4e 90 87 cb 33 39 6a 68 73 e8 f9 d2 53 9a 4b 8e';
+
+
+ $roMix = self::getMethod('scryptROMix');
+ $obj = $this->getMockForAbstractClass('Zend\Crypt\Key\Derivation\Scrypt');
+ $input = self::hex2bin(str_replace(array(' ',"\n"), '', $hexInput));
+ $result = $roMix->invokeArgs($obj, array($input, 16, 1));
+
+ $this->assertEquals(str_replace(array(' ',"\n"),'',$hexOutput), bin2hex($result));
+ }
+
+
+ /**
+ * Test Vector Scrypt
+ *
+ * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-11
+ */
+ public function testVectorScrypt()
+ {
+ $hexOutput = '77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97
+ f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42
+ fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17
+ e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06';
+
+ $result = Scrypt::calc('', '', 16, 1, 1, 64);
+ $this->assertEquals(64, strlen($result));
+ $this->assertEquals(str_replace(array(' ',"\n"),'',$hexOutput), bin2hex($result));
+ }
+
+ /**
+ * @expectedException Zend\Crypt\Key\Derivation\Exception\InvalidArgumentException
+ */
+ public function testScryptWrongN()
+ {
+ $result = Scrypt::calc('test', 'salt', 17, 1, 1, 64);
+ $result = Scrypt::calc('test', 'salt', PHP_INT_MAX, 1, 1, 64);
+ }
+
+ /**
+ * @expectedException Zend\Crypt\Key\Derivation\Exception\InvalidArgumentException
+ */
+ public function testScryptWrongR()
+ {
+ $result = Scrypt::calc('test', 'salt', PHP_INT_MAX / 128, 4, 1, 64);
+ }
+
+ /**
+ * Test scrypt correct size output
+ */
+ public function testScryptSize()
+ {
+ for ($size = 0; $size < 64; $size++) {
+ if (extension_loaded('Scrypt') && ($size < 16)) {
+ $this->setExpectedException('Zend\Crypt\Key\Derivation\Exception\InvalidArgumentException');
+ }
+ $result = Scrypt::calc('test', 'salt', 16, 1, 1, $size);
+ $this->assertEquals($size, strlen($result));
+ }
+ }
+
+ /**
+ * Convert a string with hex values in binary string
+ *
+ * @param string $hex
+ * @return string
+ */
+ protected static function hex2bin($hex)
+ {
+ $len = strlen($hex);
+ $result = '';
+ for ($i = 0; $i < $len; $i += 2) {
+ $result .= chr(hexdec($hex[$i] . $hex[$i+1]));
+ }
+ return $result;
+ }
+}
diff --git a/tests/ZendTest/Crypt/Password/BcryptTest.php b/tests/ZendTest/Crypt/Password/BcryptTest.php
index 7b37dd70fa1..6207428ca28 100644
--- a/tests/ZendTest/Crypt/Password/BcryptTest.php
+++ b/tests/ZendTest/Crypt/Password/BcryptTest.php
@@ -139,4 +139,20 @@ public function testPasswordWith8bitCharacter()
$output = $this->bcrypt->create($password);
}
}
+
+ public function testSetBackwardCompatibility()
+ {
+ $result = $this->bcrypt->setBackwardCompatibility(true);
+ $this->assertTrue($result instanceof Bcrypt);
+ $this->assertTrue($this->bcrypt->getBackwardCompatibility());
+ }
+
+ public function testBackwardCompatibility()
+ {
+ $this->bcrypt->setSalt($this->salt);
+ $this->bcrypt->setBackwardCompatibility(true);
+ $password = $this->bcrypt->create($this->password);
+ $this->assertEquals('$2a$', substr($password, 0, 4));
+ $this->assertEquals(substr($password, 4), substr($this->bcryptPassword, 4));
+ }
}
diff --git a/tests/ZendTest/Filter/FilterPluginManagerTest.php b/tests/ZendTest/Filter/FilterPluginManagerTest.php
new file mode 100644
index 00000000000..0a3b512b764
--- /dev/null
+++ b/tests/ZendTest/Filter/FilterPluginManagerTest.php
@@ -0,0 +1,46 @@
+filters = new FilterPluginManager();
+ }
+
+ public function testFilterSuccessfullyRetrieved()
+ {
+ $filter = $this->filters->get('int');
+ $this->assertInstanceOf('Zend\Filter\Int', $filter);
+ }
+
+ public function testRegisteringInvalidFilterRaisesException()
+ {
+ $this->setExpectedException('Zend\Filter\Exception\RuntimeException');
+ $this->filters->setService('test', $this);
+ }
+
+ public function testLoadingInvalidFilterRaisesException()
+ {
+ $this->filters->setInvokableClass('test', get_class($this));
+ $this->setExpectedException('Zend\Filter\Exception\RuntimeException');
+ $this->filters->get('test');
+ }
+}
diff --git a/tests/ZendTest/Filter/UriNormalizeTest.php b/tests/ZendTest/Filter/UriNormalizeTest.php
new file mode 100644
index 00000000000..f0d42e36c28
--- /dev/null
+++ b/tests/ZendTest/Filter/UriNormalizeTest.php
@@ -0,0 +1,70 @@
+filter($url);
+ $this->assertEquals($expected, $result);
+ }
+
+ public function testDefaultSchemeAffectsNormalization()
+ {
+ $this->markTestIncomplete();
+ }
+
+ /**
+ * @dataProvider enforcedSchemeTestcaseProvider
+ */
+ public function testEnforcedScheme($scheme, $input, $expected)
+ {
+ $filter = new UriNormalize(array('enforcedScheme' => $scheme));
+ $result = $filter->filter($input);
+ $this->assertEquals($expected, $result);
+ }
+
+ public static function abnormalUriProvider()
+ {
+ return array(
+ array('http://www.example.com', 'http://www.example.com/'),
+ array('hTTp://www.example.com/ space', 'http://www.example.com/%20space'),
+ array('file:///www.example.com/foo/bar', 'file:///www.example.com/foo/bar'), // this should not be affected
+ array('file:///home/shahar/secret/../../otherguy/secret', 'file:///home/otherguy/secret'),
+ array('https://www.example.com:443/hasport', 'https://www.example.com/hasport'),
+ array('/foo/bar?q=%711', '/foo/bar?q=q1'), // no scheme enforced
+ );
+ }
+
+ public static function enforcedSchemeTestcaseProvider()
+ {
+ return array(
+ array('ftp', 'http://www.example.com', 'http://www.example.com/'), // no effect - this one has a scheme
+ array('mailto', 'mailto:shahar@example.com', 'mailto:shahar@example.com'),
+ array('http', 'www.example.com/foo/bar?q=q', 'http://www.example.com/foo/bar?q=q'),
+ array('ftp', 'www.example.com/path/to/file.ext', 'ftp://www.example.com/path/to/file.ext'),
+ array('http', '/just/a/path', '/just/a/path') // cannot be enforced, no host
+ );
+ }
+}
diff --git a/tests/ZendTest/Form/Annotation/AnnotationBuilderTest.php b/tests/ZendTest/Form/Annotation/AnnotationBuilderTest.php
index 2359a3fcc0c..0a07923d5d0 100644
--- a/tests/ZendTest/Form/Annotation/AnnotationBuilderTest.php
+++ b/tests/ZendTest/Form/Annotation/AnnotationBuilderTest.php
@@ -187,6 +187,17 @@ public function testCanHandleOptionsAnnotation()
$this->assertEquals(array('class' => 'label'), $username->getLabelAttributes());
}
+ public function testCanHandleHydratorArrayAnnotation()
+ {
+ $entity = new TestAsset\Annotation\EntityWithHydratorArray();
+ $builder = new Annotation\AnnotationBuilder();
+ $form = $builder->createForm($entity);
+
+ $hydrator = $form->getHydrator();
+ $this->assertInstanceOf('Zend\Stdlib\Hydrator\ClassMethods', $hydrator);
+ $this->assertFalse($hydrator->getUnderscoreSeparatedKeys());
+ }
+
public function testAllowTypeAsElementNameInInputFilter()
{
$entity = new TestAsset\Annotation\EntityWithTypeAsElementName();
diff --git a/tests/ZendTest/Form/Element/DateSelectTest.php b/tests/ZendTest/Form/Element/DateSelectTest.php
new file mode 100644
index 00000000000..420c9d9736a
--- /dev/null
+++ b/tests/ZendTest/Form/Element/DateSelectTest.php
@@ -0,0 +1,53 @@
+getInputSpecification();
+ $this->assertArrayHasKey('validators', $inputSpec);
+ $this->assertInternalType('array', $inputSpec['validators']);
+
+ $expectedClasses = array(
+ 'Zend\Validator\Date'
+ );
+ foreach ($inputSpec['validators'] as $validator) {
+ $class = get_class($validator);
+ $this->assertTrue(in_array($class, $expectedClasses), $class);
+ switch ($class) {
+ case 'Zend\Validator\Date':
+ $this->assertEquals('Y-m-d', $validator->getFormat());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ public function testCanSetDateFromDateTime()
+ {
+ $element = new DateSelectElement();
+ $element->setValue(new DateTime('2012-09-24'));
+
+ $this->assertEquals('2012', $element->getYearElement()->getValue());
+ $this->assertEquals('09', $element->getMonthElement()->getValue());
+ $this->assertEquals('24', $element->getDayElement()->getValue());
+ }
+}
diff --git a/tests/ZendTest/Form/Element/MonthSelectTest.php b/tests/ZendTest/Form/Element/MonthSelectTest.php
new file mode 100644
index 00000000000..7bffab54f19
--- /dev/null
+++ b/tests/ZendTest/Form/Element/MonthSelectTest.php
@@ -0,0 +1,84 @@
+getInputSpecification();
+ $this->assertArrayHasKey('validators', $inputSpec);
+ $this->assertInternalType('array', $inputSpec['validators']);
+
+ $expectedClasses = array(
+ 'Zend\Validator\Regex'
+ );
+ foreach ($inputSpec['validators'] as $validator) {
+ $class = get_class($validator);
+ $this->assertTrue(in_array($class, $expectedClasses), $class);
+ switch ($class) {
+ case 'Zend\Validator\Regex':
+ $this->assertEquals('/^[0-9]{4}\-(0?[1-9]|1[012])$/', $validator->getPattern());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Note about those tests: 2012-1 is not valid in HTML5 validation, but here we use selects, and in some
+ * locales, the month may be expressed using only 1 digit, so this is valid here
+ *
+ * @return array
+ */
+ public function monthValuesDataProvider()
+ {
+ return array(
+ // value expected
+ array('2012-01', true),
+ array('2012-12', true),
+ array('2012-13', false),
+ array('2012-12-01', false),
+ array('12-2012', false),
+ array('2012-1', true),
+ array('12-01', false),
+ );
+ }
+
+ /**
+ * @dataProvider monthValuesDataProvider
+ */
+ public function testMonthValidation($value, $expected)
+ {
+ $element = new MonthSelectElement('foo');
+ $inputSpec = $element->getInputSpecification();
+ $this->assertArrayHasKey('validators', $inputSpec);
+ $monthValidator = $inputSpec['validators'][0];
+ $this->assertEquals($expected, $monthValidator->isValid($value));
+ }
+
+ public function testCanSetMonthFromDateTime()
+ {
+ $element = new MonthSelectElement();
+ $element->setValue(new DateTime('2012-09'));
+
+ $this->assertEquals('2012', $element->getYearElement()->getValue());
+ $this->assertEquals('09', $element->getMonthElement()->getValue());
+ }
+}
diff --git a/tests/ZendTest/Form/FactoryTest.php b/tests/ZendTest/Form/FactoryTest.php
index c0b659739d2..61320bd44f2 100644
--- a/tests/ZendTest/Form/FactoryTest.php
+++ b/tests/ZendTest/Form/FactoryTest.php
@@ -316,6 +316,22 @@ public function testCanCreateFormsAndSpecifyHydrator()
$this->assertInstanceOf('Zend\Stdlib\Hydrator\ObjectProperty', $hydrator);
}
+ public function testCanCreateHydratorFromArray()
+ {
+ $form = $this->factory->createForm(array(
+ 'name' => 'foo',
+ 'hydrator' => array(
+ 'type' => 'Zend\Stdlib\Hydrator\ClassMethods',
+ 'options' => array('underscoreSeparatedKeys' => false),
+ ),
+ ));
+
+ $this->assertInstanceOf('Zend\Form\FormInterface', $form);
+ $hydrator = $form->getHydrator();
+ $this->assertInstanceOf('Zend\Stdlib\Hydrator\ClassMethods', $hydrator);
+ $this->assertFalse($hydrator->getUnderscoreSeparatedKeys());
+ }
+
public function testCanCreateHydratorFromConcreteClass()
{
$form = $this->factory->createForm(array(
diff --git a/tests/ZendTest/Form/TestAsset/Annotation/EntityWithHydratorArray.php b/tests/ZendTest/Form/TestAsset/Annotation/EntityWithHydratorArray.php
new file mode 100644
index 00000000000..dd91b0456d8
--- /dev/null
+++ b/tests/ZendTest/Form/TestAsset/Annotation/EntityWithHydratorArray.php
@@ -0,0 +1,26 @@
+assertSame('foo', $defaultElement);
}
+ public function testCanRenderTemplateAlone()
+ {
+ $form = $this->getForm();
+ $collection = $form->get('colors');
+ $collection->setShouldCreateTemplate(true);
+ $markup = $this->helper->renderTemplate($collection);
+ $this->assertContains('assertContains($collection->getTemplatePlaceholder(), $markup);
+ }
}
diff --git a/tests/ZendTest/Form/View/Helper/FormDateSelectTest.php b/tests/ZendTest/Form/View/Helper/FormDateSelectTest.php
new file mode 100644
index 00000000000..de26a7ac288
--- /dev/null
+++ b/tests/ZendTest/Form/View/Helper/FormDateSelectTest.php
@@ -0,0 +1,69 @@
+helper = new FormDateSelectHelper();
+ parent::setUp();
+ }
+
+ public function testRaisesExceptionWhenNameIsNotPresentInElement()
+ {
+ $element = new DateSelect();
+ $this->setExpectedException('Zend\Form\Exception\DomainException', 'name');
+ $this->helper->render($element);
+ }
+
+ public function testGeneratesThreeSelectsWithElement()
+ {
+ $element = new DateSelect('foo');
+ $markup = $this->helper->render($element);
+ $this->assertContains('