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('assertContains('assertContains('assertContains('', $markup); + } + + public function testInvokeProxiesToRender() + { + $element = new DateSelect('foo'); + $markup = $this->helper->__invoke($element); + $this->assertContains('assertContains('assertContains('setShouldCreateEmptyOption(true); + $markup = $this->helper->render($element); + $this->assertNotContains('assertContains('assertContains('assertSame($this->helper, $this->helper->__invoke()); + } +} diff --git a/tests/ZendTest/I18n/Validator/FloatTest.php b/tests/ZendTest/I18n/Validator/FloatTest.php index c9f82e275d6..802e800bbc0 100644 --- a/tests/ZendTest/I18n/Validator/FloatTest.php +++ b/tests/ZendTest/I18n/Validator/FloatTest.php @@ -59,6 +59,7 @@ public function basicProvider() array(0.01, true), array(-0.1, true), array('10.1', true), + array('5.00', true), array('10.0', true), array('10.10', true), array(1, true), diff --git a/tests/ZendTest/I18n/View/Helper/DateFormatTest.php b/tests/ZendTest/I18n/View/Helper/DateFormatTest.php index 38873d57f4a..4ed864ec25c 100644 --- a/tests/ZendTest/I18n/View/Helper/DateFormatTest.php +++ b/tests/ZendTest/I18n/View/Helper/DateFormatTest.php @@ -53,7 +53,7 @@ public function tearDown() unset($this->helper); } - public function currencyTestsDataProvider() + public function dateTestsDataProvider() { $date = new DateTime('2012-07-02T22:44:03Z'); return array( @@ -160,19 +160,62 @@ public function currencyTestsDataProvider() ); } + public function dateTestsDataProviderWithPattern() + { + $date = new DateTime('2012-07-02T22:44:03Z'); + return array( + // FULL format varies based on OS + // array( + // 'de_DE', + // 'Europe/Berlin', + // IntlDateFormatter::FULL, + // IntlDateFormatter::FULL, + // $date, + // 'Dienstag, 3. Juli 2012 00:44:03 Deutschland', + // ), + array( + 'de_DE', + 'Europe/Berlin', + null, + null, + 'MMMM', + $date, + 'Juli', + ), + array( + 'de_DE', + 'Europe/Berlin', + null, + null, + 'MMMM.Y', + $date, + 'Juli.2012', + ), + array( + 'de_DE', + 'Europe/Berlin', + null, + null, + 'dd/Y', + $date, + '03/2012', + ), + ); + } + /** - * @dataProvider currencyTestsDataProvider + * @dataProvider dateTestsDataProvider */ public function testBasic($locale, $timezone, $timeType, $dateType, $date, $expected) { $this->helper->setTimezone($timezone); $this->assertMbStringEquals($expected, $this->helper->__invoke( - $date, $dateType, $timeType, $locale + $date, $dateType, $timeType, $locale, null )); } /** - * @dataProvider currencyTestsDataProvider + * @dataProvider dateTestsDataProvider */ public function testSettersProvideDefaults($locale, $timezone, $timeType, $dateType, $date, $expected) { @@ -185,6 +228,17 @@ public function testSettersProvideDefaults($locale, $timezone, $timeType, $dateT )); } + /** + * @dataProvider dateTestsDataProviderWithPattern + */ + public function testUseCustomPattern($locale, $timezone, $timeType, $dateType, $pattern, $date, $expected) + { + $this->helper->setTimezone($timezone); + $this->assertMbStringEquals($expected, $this->helper->__invoke( + $date, $dateType, $timeType, $locale, $pattern + )); + } + public function testDefaultLocale() { $this->assertEquals(Locale::getDefault(), $this->helper->getLocale()); diff --git a/tests/ZendTest/I18n/View/Helper/PluralTest.php b/tests/ZendTest/I18n/View/Helper/PluralTest.php new file mode 100644 index 00000000000..dbb0d37b5c9 --- /dev/null +++ b/tests/ZendTest/I18n/View/Helper/PluralTest.php @@ -0,0 +1,68 @@ +helper = new PluralHelper(); + } + + /** + * @return array + */ + public function pluralsTestProvider() + { + return array( + array('nplurals=1; plural=0', 'かさ', 0, 'かさ'), + array('nplurals=1; plural=0', 'かさ', 10, 'かさ'), + + array('nplurals=2; plural=(n==1 ? 0 : 1)', array('umbrella', 'umbrellas'), 0, 'umbrellas'), + array('nplurals=2; plural=(n==1 ? 0 : 1)', array('umbrella', 'umbrellas'), 1, 'umbrella'), + array('nplurals=2; plural=(n==1 ? 0 : 1)', array('umbrella', 'umbrellas'), 2, 'umbrellas'), + + array('nplurals=2; plural=(n==0 || n==1 ? 0 : 1)', array('parapluie', 'parapluies'), 0, 'parapluie'), + array('nplurals=2; plural=(n==0 || n==1 ? 0 : 1)', array('parapluie', 'parapluies'), 1, 'parapluie'), + array('nplurals=2; plural=(n==0 || n==1 ? 0 : 1)', array('parapluie', 'parapluies'), 2, 'parapluies'), + ); + } + + /** + * @dataProvider pluralsTestProvider + */ + public function testGetCorrectPlurals($pluralRule, $strings, $number, $expected) + { + $this->helper->setPluralRule($pluralRule); + $result = $this->helper->__invoke($strings, $number); + $this->assertEquals($expected, $result); + } +} diff --git a/tests/ZendTest/Loader/ModuleAutoloaderTest.php b/tests/ZendTest/Loader/ModuleAutoloaderTest.php index 2aec0d32ec8..fd388f99c56 100644 --- a/tests/ZendTest/Loader/ModuleAutoloaderTest.php +++ b/tests/ZendTest/Loader/ModuleAutoloaderTest.php @@ -197,6 +197,19 @@ public function testCanLoadModulesFromExplicitLocation() $this->assertTrue(class_exists('PharModuleExplicit\Module')); } + public function testCanLoadModulesFromClassMap() + { + $loader = new ModuleAutoloader(); + $loader->setModuleClassMap(array( + 'BarModule\Module' => __DIR__ . '/_files/BarModule/Module.php', + 'PharModuleMap\Module' => __DIR__ . '/_files/PharModuleMap.phar', + )); + $loader->register(); + + $this->assertTrue(class_exists('BarModule\Module')); + $this->assertTrue(class_exists('PharModuleMap\Module')); + } + public function testCanLoadModulesFromNamespace() { $loader = new ModuleAutoloader(array( @@ -208,5 +221,4 @@ public function testCanLoadModulesFromNamespace() $this->assertTrue(class_exists('FooModule\SubModule\Module')); $this->assertTrue(class_exists('FooModule\Module')); } - } diff --git a/tests/ZendTest/Loader/_files/BarModule/Module.php b/tests/ZendTest/Loader/_files/BarModule/Module.php new file mode 100644 index 00000000000..dfd18098c5f --- /dev/null +++ b/tests/ZendTest/Loader/_files/BarModule/Module.php @@ -0,0 +1,15 @@ +enabled = $enabled; + } + + public function getEnabled() + { + return $this->enabled; + } + + public function error($line) + { + $this->calls['error'][] = $line; + } + + public function warn($line) + { + $this->calls['warn'][] = $line; + } + + public function info($line) + { + $this->calls['info'][] = $line; + } + + public function trace($line) + { + $this->calls['trace'][] = $line; + } + + public function log($line) + { + $this->calls['log'][] = $line; + } +} diff --git a/tests/ZendTest/Log/Writer/ChromePhpTest.php b/tests/ZendTest/Log/Writer/ChromePhpTest.php new file mode 100644 index 00000000000..52784fb10c6 --- /dev/null +++ b/tests/ZendTest/Log/Writer/ChromePhpTest.php @@ -0,0 +1,83 @@ +chromephp = new MockChromePhp(); + + } + + public function testGetChromePhp() + { + $writer = new ChromePhp($this->chromephp); + $this->assertTrue($writer->getChromePhp() instanceof ChromePhpInterface); + } + + public function testSetChromePhp() + { + $writer = new ChromePhp($this->chromephp); + $chromephp2 = new MockChromePhp(); + + $writer->setChromePhp($chromephp2); + $this->assertTrue($writer->getChromePhp() instanceof ChromePhpInterface); + $this->assertEquals($chromephp2, $writer->getChromePhp()); + } + + public function testWrite() + { + $writer = new ChromePhp($this->chromephp); + $writer->write(array( + 'message' => 'my msg', + 'priority' => Logger::DEBUG + )); + $this->assertEquals('my msg', $this->chromephp->calls['trace'][0]); + } + + public function testWriteDisabled() + { + $chromephp = new MockChromePhp(false); + $writer = new ChromePhp($chromephp); + $writer->write(array( + 'message' => 'my msg', + 'priority' => Logger::DEBUG + )); + $this->assertTrue(empty($this->chromephp->calls)); + } +} diff --git a/tests/ZendTest/Log/Writer/FingersCrossedTest.php b/tests/ZendTest/Log/Writer/FingersCrossedTest.php new file mode 100644 index 00000000000..a87ce853d04 --- /dev/null +++ b/tests/ZendTest/Log/Writer/FingersCrossedTest.php @@ -0,0 +1,57 @@ +write(array('priority' => 3, 'message' => 'foo')); + + $this->assertSame(count($wrappedWriter->events), 0); + } + + public function testFlushing() + { + $wrappedWriter = new MockWriter(); + $writer = new FingersCrossedWriter($wrappedWriter, 2); + + $writer->write(array('priority' => 3, 'message' => 'foo')); + $writer->write(array('priority' => 1, 'message' => 'bar')); + + $this->assertSame(count($wrappedWriter->events), 2); + } + + public function testAfterFlushing() + { + $wrappedWriter = new MockWriter(); + $writer = new FingersCrossedWriter($wrappedWriter, 2); + + $writer->write(array('priority' => 3, 'message' => 'foo')); + $writer->write(array('priority' => 1, 'message' => 'bar')); + $writer->write(array('priority' => 3, 'message' => 'bar')); + + $this->assertSame(count($wrappedWriter->events), 3); + } +} diff --git a/tests/ZendTest/Mail/MessageTest.php b/tests/ZendTest/Mail/MessageTest.php index e198a6c974c..eaa649c76d1 100644 --- a/tests/ZendTest/Mail/MessageTest.php +++ b/tests/ZendTest/Mail/MessageTest.php @@ -56,7 +56,7 @@ public function testSetsOrigDateHeaderByDefault() public function testAddingFromAddressMarksAsValid() { - $this->message->addFrom('zf-devteam@zend.com'); + $this->message->addFrom('zf-devteam@example.com'); $this->assertTrue($this->message->isValid()); } @@ -68,14 +68,14 @@ public function testHeadersMethodReturnsHeadersObject() public function testToMethodReturnsAddressListObject() { - $this->message->addTo('zf-devteam@zend.com'); + $this->message->addTo('zf-devteam@example.com'); $to = $this->message->getTo(); $this->assertInstanceOf('Zend\Mail\AddressList', $to); } public function testToAddressListLivesInHeaders() { - $this->message->addTo('zf-devteam@zend.com'); + $this->message->addTo('zf-devteam@example.com'); $to = $this->message->getTo(); $headers = $this->message->getHeaders(); $this->assertInstanceOf('Zend\Mail\Headers', $headers); @@ -86,14 +86,14 @@ public function testToAddressListLivesInHeaders() public function testFromMethodReturnsAddressListObject() { - $this->message->addFrom('zf-devteam@zend.com'); + $this->message->addFrom('zf-devteam@example.com'); $from = $this->message->getFrom(); $this->assertInstanceOf('Zend\Mail\AddressList', $from); } public function testFromAddressListLivesInHeaders() { - $this->message->addFrom('zf-devteam@zend.com'); + $this->message->addFrom('zf-devteam@example.com'); $from = $this->message->getFrom(); $headers = $this->message->getHeaders(); $this->assertInstanceOf('Zend\Mail\Headers', $headers); @@ -104,14 +104,14 @@ public function testFromAddressListLivesInHeaders() public function testCcMethodReturnsAddressListObject() { - $this->message->addCc('zf-devteam@zend.com'); + $this->message->addCc('zf-devteam@example.com'); $cc = $this->message->getCc(); $this->assertInstanceOf('Zend\Mail\AddressList', $cc); } public function testCcAddressListLivesInHeaders() { - $this->message->addCc('zf-devteam@zend.com'); + $this->message->addCc('zf-devteam@example.com'); $cc = $this->message->getCc(); $headers = $this->message->getHeaders(); $this->assertInstanceOf('Zend\Mail\Headers', $headers); @@ -122,14 +122,14 @@ public function testCcAddressListLivesInHeaders() public function testBccMethodReturnsAddressListObject() { - $this->message->addBcc('zf-devteam@zend.com'); + $this->message->addBcc('zf-devteam@example.com'); $bcc = $this->message->getBcc(); $this->assertInstanceOf('Zend\Mail\AddressList', $bcc); } public function testBccAddressListLivesInHeaders() { - $this->message->addBcc('zf-devteam@zend.com'); + $this->message->addBcc('zf-devteam@example.com'); $bcc = $this->message->getBcc(); $headers = $this->message->getHeaders(); $this->assertInstanceOf('Zend\Mail\Headers', $headers); @@ -140,14 +140,14 @@ public function testBccAddressListLivesInHeaders() public function testReplyToMethodReturnsAddressListObject() { - $this->message->addReplyTo('zf-devteam@zend.com'); + $this->message->addReplyTo('zf-devteam@example.com'); $replyTo = $this->message->getReplyTo(); $this->assertInstanceOf('Zend\Mail\AddressList', $replyTo); } public function testReplyToAddressListLivesInHeaders() { - $this->message->addReplyTo('zf-devteam@zend.com'); + $this->message->addReplyTo('zf-devteam@example.com'); $replyTo = $this->message->getReplyTo(); $headers = $this->message->getHeaders(); $this->assertInstanceOf('Zend\Mail\Headers', $headers); @@ -163,14 +163,14 @@ public function testSenderIsNullByDefault() public function testSettingSenderCreatesAddressObject() { - $this->message->setSender('zf-devteam@zend.com'); + $this->message->setSender('zf-devteam@example.com'); $sender = $this->message->getSender(); $this->assertInstanceOf('Zend\Mail\Address', $sender); } public function testCanSpecifyNameWhenSettingSender() { - $this->message->setSender('zf-devteam@zend.com', 'ZF DevTeam'); + $this->message->setSender('zf-devteam@example.com', 'ZF DevTeam'); $sender = $this->message->getSender(); $this->assertInstanceOf('Zend\Mail\Address', $sender); $this->assertEquals('ZF DevTeam', $sender->getName()); @@ -178,7 +178,7 @@ public function testCanSpecifyNameWhenSettingSender() public function testCanProvideAddressObjectWhenSettingSender() { - $sender = new Address('zf-devteam@zend.com'); + $sender = new Address('zf-devteam@example.com'); $this->message->setSender($sender); $test = $this->message->getSender(); $this->assertSame($sender, $test); @@ -188,24 +188,24 @@ public function testSenderAccessorsProxyToSenderHeader() { $header = new Header\Sender(); $this->message->getHeaders()->addHeader($header); - $address = new Address('zf-devteam@zend.com', 'ZF DevTeam'); + $address = new Address('zf-devteam@example.com', 'ZF DevTeam'); $this->message->setSender($address); $this->assertSame($address, $header->getAddress()); } public function testCanAddFromAddressUsingName() { - $this->message->addFrom('zf-devteam@zend.com', 'ZF DevTeam'); + $this->message->addFrom('zf-devteam@example.com', 'ZF DevTeam'); $addresses = $this->message->getFrom(); $this->assertEquals(1, count($addresses)); $address = $addresses->current(); - $this->assertEquals('zf-devteam@zend.com', $address->getEmail()); + $this->assertEquals('zf-devteam@example.com', $address->getEmail()); $this->assertEquals('ZF DevTeam', $address->getName()); } public function testCanAddFromAddressUsingAddressObject() { - $address = new Address('zf-devteam@zend.com', 'ZF DevTeam'); + $address = new Address('zf-devteam@example.com', 'ZF DevTeam'); $this->message->addFrom($address); $addresses = $this->message->getFrom(); @@ -217,59 +217,59 @@ public function testCanAddFromAddressUsingAddressObject() public function testCanAddManyFromAddressesUsingArray() { $addresses = array( - 'zf-devteam@zend.com', - 'zf-contributors@lists.zend.com' => 'ZF Contributors List', - new Address('fw-announce@lists.zend.com', 'ZF Announce List'), + 'zf-devteam@example.com', + 'zf-contributors@example.com' => 'ZF Contributors List', + new Address('fw-announce@example.com', 'ZF Announce List'), ); $this->message->addFrom($addresses); $from = $this->message->getFrom(); $this->assertEquals(3, count($from)); - $this->assertTrue($from->has('zf-devteam@zend.com')); - $this->assertTrue($from->has('zf-contributors@lists.zend.com')); - $this->assertTrue($from->has('fw-announce@lists.zend.com')); + $this->assertTrue($from->has('zf-devteam@example.com')); + $this->assertTrue($from->has('zf-contributors@example.com')); + $this->assertTrue($from->has('fw-announce@example.com')); } public function testCanAddManyFromAddressesUsingAddressListObject() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addFrom('fw-announce@lists.zend.com'); + $this->message->addFrom('fw-announce@example.com'); $this->message->addFrom($list); $from = $this->message->getFrom(); $this->assertEquals(2, count($from)); - $this->assertTrue($from->has('fw-announce@lists.zend.com')); - $this->assertTrue($from->has('zf-devteam@zend.com')); + $this->assertTrue($from->has('fw-announce@example.com')); + $this->assertTrue($from->has('zf-devteam@example.com')); } public function testCanSetFromListFromAddressList() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addFrom('fw-announce@lists.zend.com'); + $this->message->addFrom('fw-announce@example.com'); $this->message->setFrom($list); $from = $this->message->getFrom(); $this->assertEquals(1, count($from)); - $this->assertFalse($from->has('fw-announce@lists.zend.com')); - $this->assertTrue($from->has('zf-devteam@zend.com')); + $this->assertFalse($from->has('fw-announce@example.com')); + $this->assertTrue($from->has('zf-devteam@example.com')); } public function testCanAddCcAddressUsingName() { - $this->message->addCc('zf-devteam@zend.com', 'ZF DevTeam'); + $this->message->addCc('zf-devteam@example.com', 'ZF DevTeam'); $addresses = $this->message->getCc(); $this->assertEquals(1, count($addresses)); $address = $addresses->current(); - $this->assertEquals('zf-devteam@zend.com', $address->getEmail()); + $this->assertEquals('zf-devteam@example.com', $address->getEmail()); $this->assertEquals('ZF DevTeam', $address->getName()); } public function testCanAddCcAddressUsingAddressObject() { - $address = new Address('zf-devteam@zend.com', 'ZF DevTeam'); + $address = new Address('zf-devteam@example.com', 'ZF DevTeam'); $this->message->addCc($address); $addresses = $this->message->getCc(); @@ -281,59 +281,59 @@ public function testCanAddCcAddressUsingAddressObject() public function testCanAddManyCcAddressesUsingArray() { $addresses = array( - 'zf-devteam@zend.com', - 'zf-contributors@lists.zend.com' => 'ZF Contributors List', - new Address('fw-announce@lists.zend.com', 'ZF Announce List'), + 'zf-devteam@example.com', + 'zf-contributors@example.com' => 'ZF Contributors List', + new Address('fw-announce@example.com', 'ZF Announce List'), ); $this->message->addCc($addresses); $cc = $this->message->getCc(); $this->assertEquals(3, count($cc)); - $this->assertTrue($cc->has('zf-devteam@zend.com')); - $this->assertTrue($cc->has('zf-contributors@lists.zend.com')); - $this->assertTrue($cc->has('fw-announce@lists.zend.com')); + $this->assertTrue($cc->has('zf-devteam@example.com')); + $this->assertTrue($cc->has('zf-contributors@example.com')); + $this->assertTrue($cc->has('fw-announce@example.com')); } public function testCanAddManyCcAddressesUsingAddressListObject() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addCc('fw-announce@lists.zend.com'); + $this->message->addCc('fw-announce@example.com'); $this->message->addCc($list); $cc = $this->message->getCc(); $this->assertEquals(2, count($cc)); - $this->assertTrue($cc->has('fw-announce@lists.zend.com')); - $this->assertTrue($cc->has('zf-devteam@zend.com')); + $this->assertTrue($cc->has('fw-announce@example.com')); + $this->assertTrue($cc->has('zf-devteam@example.com')); } public function testCanSetCcListFromAddressList() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addCc('fw-announce@lists.zend.com'); + $this->message->addCc('fw-announce@example.com'); $this->message->setCc($list); $cc = $this->message->getCc(); $this->assertEquals(1, count($cc)); - $this->assertFalse($cc->has('fw-announce@lists.zend.com')); - $this->assertTrue($cc->has('zf-devteam@zend.com')); + $this->assertFalse($cc->has('fw-announce@example.com')); + $this->assertTrue($cc->has('zf-devteam@example.com')); } public function testCanAddBccAddressUsingName() { - $this->message->addBcc('zf-devteam@zend.com', 'ZF DevTeam'); + $this->message->addBcc('zf-devteam@example.com', 'ZF DevTeam'); $addresses = $this->message->getBcc(); $this->assertEquals(1, count($addresses)); $address = $addresses->current(); - $this->assertEquals('zf-devteam@zend.com', $address->getEmail()); + $this->assertEquals('zf-devteam@example.com', $address->getEmail()); $this->assertEquals('ZF DevTeam', $address->getName()); } public function testCanAddBccAddressUsingAddressObject() { - $address = new Address('zf-devteam@zend.com', 'ZF DevTeam'); + $address = new Address('zf-devteam@example.com', 'ZF DevTeam'); $this->message->addBcc($address); $addresses = $this->message->getBcc(); @@ -345,59 +345,59 @@ public function testCanAddBccAddressUsingAddressObject() public function testCanAddManyBccAddressesUsingArray() { $addresses = array( - 'zf-devteam@zend.com', - 'zf-contributors@lists.zend.com' => 'ZF Contributors List', - new Address('fw-announce@lists.zend.com', 'ZF Announce List'), + 'zf-devteam@example.com', + 'zf-contributors@example.com' => 'ZF Contributors List', + new Address('fw-announce@example.com', 'ZF Announce List'), ); $this->message->addBcc($addresses); $bcc = $this->message->getBcc(); $this->assertEquals(3, count($bcc)); - $this->assertTrue($bcc->has('zf-devteam@zend.com')); - $this->assertTrue($bcc->has('zf-contributors@lists.zend.com')); - $this->assertTrue($bcc->has('fw-announce@lists.zend.com')); + $this->assertTrue($bcc->has('zf-devteam@example.com')); + $this->assertTrue($bcc->has('zf-contributors@example.com')); + $this->assertTrue($bcc->has('fw-announce@example.com')); } public function testCanAddManyBccAddressesUsingAddressListObject() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addBcc('fw-announce@lists.zend.com'); + $this->message->addBcc('fw-announce@example.com'); $this->message->addBcc($list); $bcc = $this->message->getBcc(); $this->assertEquals(2, count($bcc)); - $this->assertTrue($bcc->has('fw-announce@lists.zend.com')); - $this->assertTrue($bcc->has('zf-devteam@zend.com')); + $this->assertTrue($bcc->has('fw-announce@example.com')); + $this->assertTrue($bcc->has('zf-devteam@example.com')); } public function testCanSetBccListFromAddressList() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addBcc('fw-announce@lists.zend.com'); + $this->message->addBcc('fw-announce@example.com'); $this->message->setBcc($list); $bcc = $this->message->getBcc(); $this->assertEquals(1, count($bcc)); - $this->assertFalse($bcc->has('fw-announce@lists.zend.com')); - $this->assertTrue($bcc->has('zf-devteam@zend.com')); + $this->assertFalse($bcc->has('fw-announce@example.com')); + $this->assertTrue($bcc->has('zf-devteam@example.com')); } public function testCanAddReplyToAddressUsingName() { - $this->message->addReplyTo('zf-devteam@zend.com', 'ZF DevTeam'); + $this->message->addReplyTo('zf-devteam@example.com', 'ZF DevTeam'); $addresses = $this->message->getReplyTo(); $this->assertEquals(1, count($addresses)); $address = $addresses->current(); - $this->assertEquals('zf-devteam@zend.com', $address->getEmail()); + $this->assertEquals('zf-devteam@example.com', $address->getEmail()); $this->assertEquals('ZF DevTeam', $address->getName()); } public function testCanAddReplyToAddressUsingAddressObject() { - $address = new Address('zf-devteam@zend.com', 'ZF DevTeam'); + $address = new Address('zf-devteam@example.com', 'ZF DevTeam'); $this->message->addReplyTo($address); $addresses = $this->message->getReplyTo(); @@ -409,44 +409,44 @@ public function testCanAddReplyToAddressUsingAddressObject() public function testCanAddManyReplyToAddressesUsingArray() { $addresses = array( - 'zf-devteam@zend.com', - 'zf-contributors@lists.zend.com' => 'ZF Contributors List', - new Address('fw-announce@lists.zend.com', 'ZF Announce List'), + 'zf-devteam@example.com', + 'zf-contributors@example.com' => 'ZF Contributors List', + new Address('fw-announce@example.com', 'ZF Announce List'), ); $this->message->addReplyTo($addresses); $replyTo = $this->message->getReplyTo(); $this->assertEquals(3, count($replyTo)); - $this->assertTrue($replyTo->has('zf-devteam@zend.com')); - $this->assertTrue($replyTo->has('zf-contributors@lists.zend.com')); - $this->assertTrue($replyTo->has('fw-announce@lists.zend.com')); + $this->assertTrue($replyTo->has('zf-devteam@example.com')); + $this->assertTrue($replyTo->has('zf-contributors@example.com')); + $this->assertTrue($replyTo->has('fw-announce@example.com')); } public function testCanAddManyReplyToAddressesUsingAddressListObject() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addReplyTo('fw-announce@lists.zend.com'); + $this->message->addReplyTo('fw-announce@example.com'); $this->message->addReplyTo($list); $replyTo = $this->message->getReplyTo(); $this->assertEquals(2, count($replyTo)); - $this->assertTrue($replyTo->has('fw-announce@lists.zend.com')); - $this->assertTrue($replyTo->has('zf-devteam@zend.com')); + $this->assertTrue($replyTo->has('fw-announce@example.com')); + $this->assertTrue($replyTo->has('zf-devteam@example.com')); } public function testCanSetReplyToListFromAddressList() { $list = new AddressList(); - $list->add('zf-devteam@zend.com'); + $list->add('zf-devteam@example.com'); - $this->message->addReplyTo('fw-announce@lists.zend.com'); + $this->message->addReplyTo('fw-announce@example.com'); $this->message->setReplyTo($list); $replyTo = $this->message->getReplyTo(); $this->assertEquals(1, count($replyTo)); - $this->assertFalse($replyTo->has('fw-announce@lists.zend.com')); - $this->assertTrue($replyTo->has('zf-devteam@zend.com')); + $this->assertFalse($replyTo->has('fw-announce@example.com')); + $this->assertTrue($replyTo->has('zf-devteam@example.com')); } public function testSubjectIsEmptyByDefault() @@ -611,10 +611,10 @@ public function testMessageReturnsNonEncodedSubject() public function testSettingNonAsciiEncodingForcesMimeEncodingOfSomeHeaders() { - $this->message->addTo('zf-devteam@zend.com', 'ZF DevTeam'); - $this->message->addFrom('matthew@zend.com', "Matthew Weier O'Phinney"); - $this->message->addCc('zf-contributors@lists.zend.com', 'ZF Contributors List'); - $this->message->addBcc('zf-crteam@lists.zend.com', 'ZF CR Team'); + $this->message->addTo('zf-devteam@example.com', 'ZF DevTeam'); + $this->message->addFrom('matthew@example.com', "Matthew Weier O'Phinney"); + $this->message->addCc('zf-contributors@example.com', 'ZF Contributors List'); + $this->message->addBcc('zf-crteam@example.com', 'ZF CR Team'); $this->message->setSubject('This is a subject'); $this->message->setEncoding('UTF-8'); @@ -622,19 +622,19 @@ public function testSettingNonAsciiEncodingForcesMimeEncodingOfSomeHeaders() $expected = '=?UTF-8?Q?ZF=20DevTeam?='; $this->assertContains($expected, $test); - $this->assertContains('', $test); + $this->assertContains('', $test); $expected = "=?UTF-8?Q?Matthew=20Weier=20O'Phinney?="; $this->assertContains($expected, $test, $test); - $this->assertContains('', $test); + $this->assertContains('', $test); $expected = '=?UTF-8?Q?ZF=20Contributors=20List?='; $this->assertContains($expected, $test); - $this->assertContains('', $test); + $this->assertContains('', $test); $expected = '=?UTF-8?Q?ZF=20CR=20Team?='; $this->assertContains($expected, $test); - $this->assertContains('', $test); + $this->assertContains('', $test); $expected = 'Subject: =?UTF-8?Q?This=20is=20a=20subject?='; $this->assertContains($expected, $test); @@ -654,4 +654,16 @@ public function testDefaultDateHeaderEncodingIsAlwaysAscii() $test = substr($test, 0, 16); $this->assertEquals($date, $test); } + + public function testRestoreFromSerializedString() + { + $this->message->addTo('zf-devteam@example.com', 'ZF DevTeam'); + $this->message->addFrom('matthew@example.com', "Matthew Weier O'Phinney"); + $this->message->addCc('zf-contributors@example.com', 'ZF Contributors List'); + $this->message->setSubject('This is a subject'); + $this->message->setBody('foo'); + $serialized = $this->message->toString(); + $restoredMessage = Message::fromString($serialized); + $this->assertEquals($serialized, $restoredMessage->toString()); + } } diff --git a/tests/ZendTest/ModuleManager/Listener/ListenerOptionsTest.php b/tests/ZendTest/ModuleManager/Listener/ListenerOptionsTest.php index 51e92cea2c5..956e39bae6c 100644 --- a/tests/ZendTest/ModuleManager/Listener/ListenerOptionsTest.php +++ b/tests/ZendTest/ModuleManager/Listener/ListenerOptionsTest.php @@ -10,7 +10,6 @@ namespace ZendTest\ModuleManager\Listener; -use InvalidArgumentException; use PHPUnit_Framework_TestCase as TestCase; use Zend\Config\Config; use Zend\ModuleManager\Listener\ListenerOptions; @@ -92,4 +91,31 @@ public function testSetConfigGlobPathsThrowsInvalidArgumentException() $options = new ListenerOptions; $options->setConfigGlobPaths('asd'); } + + public function testSetConfigStaticPathsThrowsInvalidArgumentException() + { + $this->setExpectedException('InvalidArgumentException'); + $options = new ListenerOptions; + $options->setConfigStaticPaths('asd'); + } + + public function testSetExtraConfigAcceptsArrayOrTraverable() + { + $array = array(__DIR__); + $traversable = new Config($array); + $options = new ListenerOptions; + + $this->assertSame($options, $options->setExtraConfig($array)); + $this->assertSame($array, $options->getExtraConfig()); + + $this->assertSame($options, $options->setExtraConfig($traversable)); + $this->assertSame($traversable, $options->getExtraConfig()); + } + + public function testSetExtraConfigThrowsInvalidArgumentException() + { + $this->setExpectedException('InvalidArgumentException'); + $options = new ListenerOptions; + $options->setExtraConfig('asd'); + } } diff --git a/tests/ZendTest/ModuleManager/Listener/ModuleLoaderListenerTest.php b/tests/ZendTest/ModuleManager/Listener/ModuleLoaderListenerTest.php new file mode 100644 index 00000000000..cc654093d0e --- /dev/null +++ b/tests/ZendTest/ModuleManager/Listener/ModuleLoaderListenerTest.php @@ -0,0 +1,96 @@ +tmpdir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'zend_module_cache_dir'; + @mkdir($this->tmpdir); + + $this->moduleManager = new ModuleManager(array()); + $this->moduleManager->getEventManager()->attach('loadModule.resolve', new ModuleResolverListener, 1000); + } + + public function tearDown() + { + $file = glob($this->tmpdir . DIRECTORY_SEPARATOR . '*'); + @unlink($file[0]); // change this if there's ever > 1 file + @rmdir($this->tmpdir); + } + + public function testModuleLoaderListenerFunctionsAsAggregateListenerEnabledCache() + { + $options = new ListenerOptions(array( + 'cache_dir' => $this->tmpdir, + 'module_map_cache_enabled' => true, + 'module_map_cache_key' => 'foo', + )); + + $moduleLoaderListener = new ModuleLoaderListener($options); + + $moduleManager = $this->moduleManager; + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES))); + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST))); + + $moduleLoaderListener->attach($moduleManager->getEventManager()); + $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES))); + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST))); + } + + public function testModuleLoaderListenerFunctionsAsAggregateListenerDisabledCache() + { + $options = new ListenerOptions(array( + 'cache_dir' => $this->tmpdir, + )); + + $moduleLoaderListener = new ModuleLoaderListener($options); + + $moduleManager = $this->moduleManager; + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES))); + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST))); + + $moduleLoaderListener->attach($moduleManager->getEventManager()); + $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES))); + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST))); + } + + public function testModuleLoaderListenerFunctionsAsAggregateListenerHasCache() + { + $options = new ListenerOptions(array( + 'cache_dir' => $this->tmpdir, + 'module_map_cache_key' => 'foo', + 'module_map_cache_enabled' => true, + )); + + file_put_contents($options->getModuleMapCacheFile(), 'moduleManager; + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES))); + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST))); + + $moduleLoaderListener->attach($moduleManager->getEventManager()); + $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES))); + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST))); + } +} diff --git a/tests/ZendTest/Mvc/Controller/Plugin/IdentityTest.php b/tests/ZendTest/Mvc/Controller/Plugin/IdentityTest.php new file mode 100644 index 00000000000..730c86b4b6d --- /dev/null +++ b/tests/ZendTest/Mvc/Controller/Plugin/IdentityTest.php @@ -0,0 +1,47 @@ +setUsername('a username'); + $identity->setPassword('a password'); + + $authenticationService = new AuthenticationService(new NonPersistentStorage, new TestAsset\AuthenticationAdapter); + + $identityPlugin = new IdentityPlugin; + $identityPlugin->setAuthenticationService($authenticationService); + + $this->assertNull($identityPlugin()); + + $this->assertFalse($authenticationService->hasIdentity()); + + $authenticationService->getAdapter()->setIdentity($identity); + $result = $authenticationService->authenticate(); + $this->assertTrue($result->isValid()); + + $this->assertEquals($identity, $identityPlugin()); + } +} diff --git a/tests/ZendTest/Mvc/Controller/Plugin/RedirectTest.php b/tests/ZendTest/Mvc/Controller/Plugin/RedirectTest.php index 7e1d3612d5c..fc6c50fb063 100644 --- a/tests/ZendTest/Mvc/Controller/Plugin/RedirectTest.php +++ b/tests/ZendTest/Mvc/Controller/Plugin/RedirectTest.php @@ -12,6 +12,7 @@ use PHPUnit_Framework_TestCase as TestCase; use Zend\Http\Response; +use Zend\Route\Request; use Zend\Mvc\Controller\Plugin\Redirect as RedirectPlugin; use Zend\Mvc\MvcEvent; use Zend\Mvc\Router\Http\Literal as LiteralRoute; @@ -35,6 +36,10 @@ public function setUp() ))); $this->router = $router; + $routeMatch = new RouteMatch(array()); + $routeMatch->setMatchedRouteName('home'); + $this->routeMatch = $routeMatch; + $event = new MvcEvent(); $event->setRouter($router); $event->setResponse($this->response); @@ -162,4 +167,24 @@ public function testCanPassBooleanValueForThirdArgumentToAllowReusingRouteMatche $location = $headers->get('Location'); $this->assertEquals('/foo/bar', $location->getFieldValue()); } + + public function testPluginCanRefreshToRouteWhenProperlyConfigured() + { + $this->event->setRouteMatch($this->routeMatch); + $response = $this->plugin->refresh(); + $this->assertTrue($response->isRedirect()); + $headers = $response->getHeaders(); + $location = $headers->get('Location'); + $this->assertEquals('/', $location->getFieldValue()); + } + + public function testPluginCanRedirectToRouteWithNullWhenProperlyConfigured() + { + $this->event->setRouteMatch($this->routeMatch); + $response = $this->plugin->toRoute(); + $this->assertTrue($response->isRedirect()); + $headers = $response->getHeaders(); + $location = $headers->get('Location'); + $this->assertEquals('/', $location->getFieldValue()); + } } diff --git a/tests/ZendTest/Mvc/Controller/Plugin/TestAsset/AuthenticationAdapter.php b/tests/ZendTest/Mvc/Controller/Plugin/TestAsset/AuthenticationAdapter.php new file mode 100644 index 00000000000..4eedbe677b9 --- /dev/null +++ b/tests/ZendTest/Mvc/Controller/Plugin/TestAsset/AuthenticationAdapter.php @@ -0,0 +1,34 @@ +identity = $identity; + } + + public function authenticate() + { + return new Result(Result::SUCCESS, $this->identity); + } +} diff --git a/tests/ZendTest/Mvc/Controller/Plugin/TestAsset/IdentityObject.php b/tests/ZendTest/Mvc/Controller/Plugin/TestAsset/IdentityObject.php new file mode 100644 index 00000000000..c978326aaf7 --- /dev/null +++ b/tests/ZendTest/Mvc/Controller/Plugin/TestAsset/IdentityObject.php @@ -0,0 +1,61 @@ +password = (string) $password; + } + + /** + * @return string|null + */ + public function getPassword() + { + return $this->password; + } + + /** + * @param string $username + */ + public function setUsername($username) + { + $this->username = (string) $username; + } + + /** + * @return string|null + */ + public function getUsername() + { + return $this->username; + } +} diff --git a/tests/ZendTest/Mvc/Controller/PluginManagerTest.php b/tests/ZendTest/Mvc/Controller/PluginManagerTest.php index ff475fed12a..ce09f0ff681 100644 --- a/tests/ZendTest/Mvc/Controller/PluginManagerTest.php +++ b/tests/ZendTest/Mvc/Controller/PluginManagerTest.php @@ -15,6 +15,7 @@ use ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin; use ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginWithConstructor; use Zend\Mvc\Controller\PluginManager; +use Zend\ServiceManager\ServiceManager; class PluginManagerTest extends TestCase { @@ -72,6 +73,23 @@ public function testGetWithConstrutorAndOptions() $this->assertEquals($plugin->getBar(), 'foo'); } + public function testDefinesFactoryForIdentityPlugin() + { + $pluginManager = new PluginManager; + $this->assertTrue($pluginManager->has('identity')); + } + + public function testIdentityFactoryCanInjectAuthenticationServiceIfInParentServiceManager() + { + $services = new ServiceManager(); + $services->setInvokableClass('Zend\Authentication\AuthenticationService', 'Zend\Authentication\AuthenticationService'); + $pluginManager = new PluginManager; + $pluginManager->setServiceLocator($services); + $identity = $pluginManager->get('identity'); + $expected = $services->get('Zend\Authentication\AuthenticationService'); + $this->assertSame($expected, $identity->getAuthenticationService()); + } + public function testCanCreateByFactory() { $pluginManager = new PluginManager; @@ -88,5 +106,4 @@ public function testCanCreateByFactoryWithConstrutor() $this->assertInstanceOf('\ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginWithConstructor', $plugin); $this->assertEquals($plugin->getBar(), 'foo'); } - } diff --git a/tests/ZendTest/Mvc/Service/ControllerLoaderFactoryTest.php b/tests/ZendTest/Mvc/Service/ControllerLoaderFactoryTest.php index d47c3e976dc..59e6bfc12cb 100644 --- a/tests/ZendTest/Mvc/Service/ControllerLoaderFactoryTest.php +++ b/tests/ZendTest/Mvc/Service/ControllerLoaderFactoryTest.php @@ -15,6 +15,9 @@ use Zend\Mvc\Service\ControllerLoaderFactory; use Zend\Mvc\Service\ControllerPluginManagerFactory; use Zend\Mvc\Service\DiFactory; +use Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory; +use Zend\Mvc\Service\DiAbstractServiceFactoryFactory; +use Zend\Mvc\Service\DiServiceInitializerFactory; use Zend\Mvc\Service\EventManagerFactory; use Zend\ServiceManager\Config; use Zend\ServiceManager\ServiceManager; @@ -42,6 +45,9 @@ public function setUp() $this->services->setService('Config', $config); $this->services->setFactory('ControllerPluginManager', new ControllerPluginManagerFactory()); $this->services->setFactory('Di', new DiFactory()); + $this->services->setFactory('DiStrictAbstractServiceFactory', new DiStrictAbstractServiceFactoryFactory()); + $this->services->setFactory('DiAbstractServiceFactory', new DiAbstractServiceFactoryFactory()); + $this->services->setFactory('DiServiceInitializer', new DiServiceInitializerFactory()); $this->services->setFactory('EventManager', new EventManagerFactory()); $this->services->setInvokableClass('SharedEventManager', 'Zend\EventManager\SharedEventManager'); } diff --git a/tests/ZendTest/Mvc/Service/DiFactoryTest.php b/tests/ZendTest/Mvc/Service/DiFactoryTest.php new file mode 100644 index 00000000000..c93baede574 --- /dev/null +++ b/tests/ZendTest/Mvc/Service/DiFactoryTest.php @@ -0,0 +1,27 @@ +setService('Config', array('di' => array(''))); + $serviceManager->setFactory('Di', new DiFactory()); + + $di = $serviceManager->get('Di'); + $this->assertInstanceOf('Zend\Di\Di', $di); + } +} diff --git a/tests/ZendTest/Permissions/Rbac/RbacTest.php b/tests/ZendTest/Permissions/Rbac/RbacTest.php new file mode 100644 index 00000000000..51342bdb01c --- /dev/null +++ b/tests/ZendTest/Permissions/Rbac/RbacTest.php @@ -0,0 +1,144 @@ +rbac = new Rbac\Rbac(); + } + + public function testIsGrantedAssertion() + { + $foo = new Rbac\Role('foo'); + $bar = new Rbac\Role('bar'); + + $true = new TestAsset\SimpleTrueAssertion(); + $false = new TestAsset\SimpleFalseAssertion(); + + $roleNoMatch = new TestAsset\RoleMustMatchAssertion($bar); + $roleMatch = new TestAsset\RoleMustMatchAssertion($foo); + + $foo->addPermission('can.foo'); + $bar->addPermission('can.bar'); + + $this->rbac->addRole($foo); + $this->rbac->addRole($bar); + + $this->assertEquals(true, $this->rbac->isGranted($foo, 'can.foo', $true)); + $this->assertEquals(false, $this->rbac->isGranted($bar, 'can.bar', $false)); + + $this->assertEquals(false, $this->rbac->isGranted($bar, 'can.bar', $roleNoMatch)); + $this->assertEquals(false, $this->rbac->isGranted($bar, 'can.foo', $roleNoMatch)); + + $this->assertEquals(true, $this->rbac->isGranted($foo, 'can.foo', $roleMatch)); + } + + public function testIsGrantedSingleRole() + { + $foo = new Rbac\Role('foo'); + $foo->addPermission('can.bar'); + + $this->rbac->addRole($foo); + + $this->assertEquals(true, $this->rbac->isGranted('foo', 'can.bar')); + $this->assertEquals(false, $this->rbac->isGranted('foo', 'can.baz')); + } + + public function testIsGrantedChildRoles() + { + $foo = new Rbac\Role('foo'); + $bar = new Rbac\Role('bar'); + + $foo->addPermission('can.foo'); + $bar->addPermission('can.bar'); + + $this->rbac->addRole($foo); + $this->rbac->addRole($bar, $foo); + + $this->assertEquals(true, $this->rbac->isGranted('foo', 'can.bar')); + $this->assertEquals(true, $this->rbac->isGranted('foo', 'can.foo')); + $this->assertEquals(true, $this->rbac->isGranted('bar', 'can.bar')); + + $this->assertEquals(false, $this->rbac->isGranted('foo', 'can.baz')); + $this->assertEquals(false, $this->rbac->isGranted('bar', 'can.baz')); + } + + public function testHasRole() + { + $foo = new Rbac\Role('foo'); + + $this->rbac->addRole('bar'); + $this->rbac->addRole($foo); + + $this->assertEquals(true, $this->rbac->hasRole($foo)); + $this->assertEquals(true, $this->rbac->hasRole('bar')); + $this->assertEquals(false, $this->rbac->hasRole('baz')); + } + + public function testAddRoleFromString() + { + $this->rbac->addRole('foo'); + + $foo = $this->rbac->getRole('foo'); + $this->assertInstanceOf('Zend\Permissions\Rbac\Role', $foo); + } + + public function testAddRoleFromClass() + { + $foo = new Rbac\Role('foo'); + + $this->rbac->addRole('foo'); + $foo2 = $this->rbac->getRole('foo'); + + $this->assertEquals($foo, $foo2); + $this->assertInstanceOf('Zend\Permissions\Rbac\Role', $foo2); + } + + public function testAddRoleWithParentsUsingRbac() + { + $foo = new Rbac\Role('foo'); + $bar = new Rbac\Role('bar'); + + $this->rbac->addRole($foo); + $this->rbac->addRole($bar, $foo); + + $this->assertEquals($bar->getParent(), $foo); + $this->assertEquals(1, count($foo->getChildren())); + } + + public function testAddRoleWithAutomaticParentsUsingRbac() + { + $foo = new Rbac\Role('foo'); + $bar = new Rbac\Role('bar'); + + $this->rbac->setCreateMissingRoles(true); + $this->rbac->addRole($bar, $foo); + + $this->assertEquals($bar->getParent(), $foo); + $this->assertEquals(1, count($foo->getChildren())); + } +} diff --git a/tests/ZendTest/Permissions/Rbac/TestAsset/RoleMustMatchAssertion.php b/tests/ZendTest/Permissions/Rbac/TestAsset/RoleMustMatchAssertion.php new file mode 100644 index 00000000000..4032e8647b3 --- /dev/null +++ b/tests/ZendTest/Permissions/Rbac/TestAsset/RoleMustMatchAssertion.php @@ -0,0 +1,45 @@ +role = $role; + } + + /** + * Assertion method - must return a boolean. + * + * @param Rbac $bac + * @return boolean + */ + public function assert(Rbac $rbac) + { + return $this->role->getName() == 'foo'; + } +} diff --git a/tests/ZendTest/Permissions/Rbac/TestAsset/SimpleFalseAssertion.php b/tests/ZendTest/Permissions/Rbac/TestAsset/SimpleFalseAssertion.php new file mode 100644 index 00000000000..4b8e2e59d5d --- /dev/null +++ b/tests/ZendTest/Permissions/Rbac/TestAsset/SimpleFalseAssertion.php @@ -0,0 +1,34 @@ +fail("Zend\\Serializer\\Adapter\\MsgPack needs missing ext/msgpack but did't throw exception"); + } catch (ExtensionNotLoadedException $e) {} + $this->markTestSkipped('Zend\\Serializer\\Adapter\\MsgPack needs ext/msgpack'); + } + $this->adapter = new Serializer\Adapter\MsgPack(); + } + + public function tearDown() + { + $this->adapter = null; + } + + public function testSerializeString() + { + $value = 'test'; + $expected = msgpack_serialize($value); + + $data = $this->adapter->serialize($value); + $this->assertEquals($expected, $data); + } + + public function testSerializeFalse() + { + $value = false; + $expected = msgpack_serialize($value); + + $data = $this->adapter->serialize($value); + $this->assertEquals($expected, $data); + } + + public function testSerializeNull() + { + $value = null; + $expected = msgpack_serialize($value); + + $data = $this->adapter->serialize($value); + $this->assertEquals($expected, $data); + } + + public function testSerializeNumeric() + { + $value = 100; + $expected = msgpack_serialize($value); + + $data = $this->adapter->serialize($value); + $this->assertEquals($expected, $data); + } + + public function testSerializeObject() + { + $value = new \stdClass(); + $expected = msgpack_serialize($value); + + $data = $this->adapter->serialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserializeString() + { + $expected = 'test'; + $value = msgpack_serialize($expected); + + $data = $this->adapter->unserialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserializeFalse() + { + $expected = false; + $value = msgpack_serialize($expected); + + $data = $this->adapter->unserialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserializeNull() + { + $expected = null; + $value = msgpack_serialize($expected); + + $data = $this->adapter->unserialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserializeNumeric() + { + $expected = 100; + $value = msgpack_serialize($expected); + + $data = $this->adapter->unserialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserializeObject() + { + $expected = new \stdClass(); + $value = msgpack_serialize($expected); + + $data = $this->adapter->unserialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserialize0() + { + $expected = 0; + $value = msgpack_serialize($expected); + + $data = $this->adapter->unserialize($value); + $this->assertEquals($expected, $data); + } + + public function testUnserialzeInvalid() + { + $value = "\0\1\r\n"; + $this->setExpectedException( + 'Zend\Serializer\Exception\RuntimeException', + 'Unserialization failed' + ); + $this->adapter->unserialize($value); + } +} diff --git a/tests/ZendTest/Session/SaveHandler/MongoDBOptionsTest.php b/tests/ZendTest/Session/SaveHandler/MongoDBOptionsTest.php new file mode 100644 index 00000000000..ad603306b9d --- /dev/null +++ b/tests/ZendTest/Session/SaveHandler/MongoDBOptionsTest.php @@ -0,0 +1,146 @@ +assertNull($options->getDatabase()); + $this->assertNull($options->getCollection()); + $this->assertEquals(array('safe' => true), $options->getSaveOptions()); + $this->assertEquals('name', $options->getNameField()); + $this->assertEquals('data', $options->getDataField()); + $this->assertEquals('lifetime', $options->getLifetimeField()); + $this->assertEquals('modified', $options->getModifiedField()); + } + + public function testSetConstructor() + { + $options = new MongoDBOptions(array( + 'database' => 'testDatabase', + 'collection' => 'testCollection', + 'saveOptions' => array('safe' => 2), + 'nameField' => 'testName', + 'dataField' => 'testData', + 'lifetimeField' => 'testLifetime', + 'modifiedField' => 'testModified', + )); + + $this->assertEquals('testDatabase', $options->getDatabase()); + $this->assertEquals('testCollection', $options->getCollection()); + $this->assertEquals(array('safe' => 2), $options->getSaveOptions()); + $this->assertEquals('testName', $options->getNameField()); + $this->assertEquals('testData', $options->getDataField()); + $this->assertEquals('testLifetime', $options->getLifetimeField()); + $this->assertEquals('testModified', $options->getModifiedField()); + } + + public function testSetters() + { + $options = new MongoDBOptions(); + $options->setDatabase('testDatabase') + ->setCollection('testCollection') + ->setSaveOptions(array('safe' => 2)) + ->setNameField('testName') + ->setDataField('testData') + ->setLifetimeField('testLifetime') + ->setModifiedField('testModified'); + + $this->assertEquals('testDatabase', $options->getDatabase()); + $this->assertEquals('testCollection', $options->getCollection()); + $this->assertEquals(array('safe' => 2), $options->getSaveOptions()); + $this->assertEquals('testName', $options->getNameField()); + $this->assertEquals('testData', $options->getDataField()); + $this->assertEquals('testLifetime', $options->getLifetimeField()); + $this->assertEquals('testModified', $options->getModifiedField()); + } + + /** + * @expectedException Zend\Session\Exception\InvalidArgumentException + */ + public function testInvalidDatabase() + { + $options = new MongoDBOptions(array( + 'database' => null, + )); + } + + /** + * @expectedException Zend\Session\Exception\InvalidArgumentException + */ + public function testInvalidCollection() + { + $options = new MongoDBOptions(array( + 'collection' => null, + )); + } + + /** + * @expectedException PHPUnit_Framework_Error + */ + public function testInvalidSaveOptions() + { + $options = new MongoDBOptions(array( + 'saveOptions' => null, + )); + } + + /** + * @expectedException Zend\Session\Exception\InvalidArgumentException + */ + public function testInvalidNameField() + { + $options = new MongoDBOptions(array( + 'nameField' => null, + )); + } + + /** + * @expectedException Zend\Session\Exception\InvalidArgumentException + */ + public function testInvalidModifiedField() + { + $options = new MongoDBOptions(array( + 'modifiedField' => null, + )); + } + + /** + * @expectedException Zend\Session\Exception\InvalidArgumentException + */ + public function testInvalidLifetimeField() + { + $options = new MongoDBOptions(array( + 'lifetimeField' => null, + )); + } + + /** + * @expectedException Zend\Session\Exception\InvalidArgumentException + */ + public function testInvalidDataField() + { + $options = new MongoDBOptions(array( + 'dataField' => null, + )); + } +} diff --git a/tests/ZendTest/Session/SaveHandler/MongoDBTest.php b/tests/ZendTest/Session/SaveHandler/MongoDBTest.php new file mode 100644 index 00000000000..8a6bbf77182 --- /dev/null +++ b/tests/ZendTest/Session/SaveHandler/MongoDBTest.php @@ -0,0 +1,158 @@ +markTestSkipped('Zend\Session\SaveHandler\MongoDB tests are not enabled due to missing Mongo extension'); + } + + $this->options = new MongoDBOptions(array( + 'database' => 'zf2_tests', + 'collection' => 'sessions', + )); + + $this->mongo = new Mongo(); + $this->mongoCollection = $this->mongo->selectCollection($this->options->getDatabase(), $this->options->getCollection()); + } + + /** + * Tear-down operations performed after each test method + * + * @return void + */ + public function tearDown() + { + if ($this->mongoCollection) { + $this->mongoCollection->drop(); + } + } + + public function testReadWrite() + { + $saveHandler = new MongoDB($this->mongo, $this->options); + $this->assertTrue($saveHandler->open('savepath', 'sessionname')); + + $id = '242'; + $data = array('foo' => 'bar', 'bar' => array('foo' => 'bar')); + + $this->assertTrue($saveHandler->write($id, serialize($data))); + $this->assertEquals($data, unserialize($saveHandler->read($id))); + + $data = array('foo' => array(1, 2, 3)); + + $this->assertTrue($saveHandler->write($id, serialize($data))); + $this->assertEquals($data, unserialize($saveHandler->read($id))); + } + + public function testReadDestroysExpiredSession() + { + /* Note: due to the session save handler's open() method reading the + * "session.gc_maxlifetime" INI value directly, it's necessary to set + * that to simulate natural session expiration. + */ + $oldMaxlifetime = ini_get('session.gc_maxlifetime'); + ini_set('session.gc_maxlifetime', 0); + + $saveHandler = new MongoDB($this->mongo, $this->options); + $this->assertTrue($saveHandler->open('savepath', 'sessionname')); + + $id = '242'; + $data = array('foo' => 'bar'); + + $this->assertNull($this->mongoCollection->findOne(array('_id' => $id))); + + $this->assertTrue($saveHandler->write($id, serialize($data))); + $this->assertNotNull($this->mongoCollection->findOne(array('_id' => $id))); + $this->assertEquals('', $saveHandler->read($id)); + $this->assertNull($this->mongoCollection->findOne(array('_id' => $id))); + + ini_set('session.gc_maxlifetime', $oldMaxlifetime); + } + + public function testGarbageCollection() + { + $saveHandler = new MongoDB($this->mongo, $this->options); + $this->assertTrue($saveHandler->open('savepath', 'sessionname')); + + $data = array('foo' => 'bar'); + + $this->assertTrue($saveHandler->write(123, serialize($data))); + $this->assertTrue($saveHandler->write(456, serialize($data))); + $this->assertEquals(2, $this->mongoCollection->count()); + $saveHandler->gc(5); + $this->assertEquals(2, $this->mongoCollection->count()); + + /* Note: MongoDate uses micro-second precision, so even a maximum + * lifetime of zero would not match records that were just inserted. + * Use a negative number instead. + */ + $saveHandler->gc(-1); + $this->assertEquals(0, $this->mongoCollection->count()); + } + + /** + * @expectedException MongoCursorException + */ + public function testWriteExceptionEdgeCaseForChangedSessionName() + { + $saveHandler = new MongoDB($this->mongo, $this->options); + $this->assertTrue($saveHandler->open('savepath', 'sessionname')); + + $id = '242'; + $data = array('foo' => 'bar'); + + /* 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. + */ + $saveHandler->write($id, serialize($data)); + $saveHandler->open('savepath', 'sessionname_changed'); + $saveHandler->write($id, serialize($data)); + } +} diff --git a/tests/ZendTest/Stdlib/HydratorTest.php b/tests/ZendTest/Stdlib/HydratorTest.php index b44fca5f018..8a30585e3b0 100644 --- a/tests/ZendTest/Stdlib/HydratorTest.php +++ b/tests/ZendTest/Stdlib/HydratorTest.php @@ -16,6 +16,8 @@ use ZendTest\Stdlib\TestAsset\ClassMethodsUnderscore; use ZendTest\Stdlib\TestAsset\ClassMethodsCamelCaseMissing; use ZendTest\Stdlib\TestAsset\Reflection as ReflectionAsset; +use Zend\Stdlib\Hydrator\Strategy\DefaultStrategy; +use Zend\Stdlib\Hydrator\Strategy\SerializableStrategy; /** * @category Zend @@ -163,6 +165,16 @@ public function testHydratorClassMethodsUnderscore() $this->assertEquals($test->hasBar(), false); } + public function testHydratorClassMethodsOptions() + { + $hydrator = new ClassMethods(); + $this->assertTrue($hydrator->getUnderscoreSeparatedKeys()); + $hydrator->setOptions(array('underscoreSeparatedKeys' => false)); + $this->assertFalse($hydrator->getUnderscoreSeparatedKeys()); + $hydrator->setUnderscoreSeparatedKeys(true); + $this->assertTrue($hydrator->getUnderscoreSeparatedKeys()); + } + public function testHydratorClassMethodsIgnoresInvalidValues() { $hydrator = new ClassMethods(true); @@ -189,6 +201,39 @@ public function testHydratorClassMethodsDefaultBehaviorIsConvertUnderscoreToCame $this->assertEquals($test->getFooBarBaz(), 'bar'); } + public function testRetrieveWildStrategyAndOther() + { + $hydrator = new ClassMethods(); + $hydrator->addStrategy('default', new DefaultStrategy()); + $hydrator->addStrategy('*', new SerializableStrategy('phpserialize')); + $default = $hydrator->getStrategy('default'); + $this->assertEquals(get_class($default), 'Zend\Stdlib\Hydrator\Strategy\DefaultStrategy'); + $serializable = $hydrator->getStrategy('*'); + $this->assertEquals(get_class($serializable), 'Zend\Stdlib\Hydrator\Strategy\SerializableStrategy'); + } + + public function testUseWildStrategyByDefault() + { + $hydrator = new ClassMethods(); + $datas = $hydrator->extract($this->classMethodsUnderscore); + $this->assertEquals($datas['foo_bar'], '1'); + $hydrator->addStrategy('*', new SerializableStrategy('phpserialize')); + $datas = $hydrator->extract($this->classMethodsUnderscore); + $this->assertEquals($datas['foo_bar'], 's:1:"1";'); + } + + public function testUseWildStrategyAndOther() + { + $hydrator = new ClassMethods(); + $datas = $hydrator->extract($this->classMethodsUnderscore); + $this->assertEquals($datas['foo_bar'], '1'); + $hydrator->addStrategy('foo_bar', new DefaultStrategy()); + $hydrator->addStrategy('*', new SerializableStrategy('phpserialize')); + $datas = $hydrator->extract($this->classMethodsUnderscore); + $this->assertEquals($datas['foo_bar'], '1'); + $this->assertEquals($datas['foo_bar_baz'], 's:1:"2";'); + } + public function testHydratorClassMethodsCamelCaseWithSetterMissing() { $hydrator = new ClassMethods(false); diff --git a/tests/ZendTest/Stdlib/OptionsTest.php b/tests/ZendTest/Stdlib/OptionsTest.php index bf226e7ec42..93f5b76588a 100644 --- a/tests/ZendTest/Stdlib/OptionsTest.php +++ b/tests/ZendTest/Stdlib/OptionsTest.php @@ -47,7 +47,6 @@ public function testNonStrictOptionsDoesNotThrowException() } } - public function testConstructionWithNull() { try { @@ -65,4 +64,34 @@ public function testUnsetting() unset($options->testField); $this->assertEquals(false, isset($options->test_field)); } + + public function testUnsetThrowsInvalidArgumentException() + { + $this->setExpectedException('InvalidArgumentException'); + $options = new TestOptions; + unset($options->foobarField); + } + + public function testGetThrowsBadMethodCallException() + { + $this->setExpectedException('BadMethodCallException'); + $options = new TestOptions(); + $options->fieldFoobar; + } + + public function testSetFromArrayAcceptsArray() + { + $array = array('test_field' => 3); + $options = new TestOptions(); + + $this->assertSame($options, $options->setFromArray($array)); + $this->assertEquals(3, $options->test_field); + } + + public function testSetFromArrayThrowsInvalidArgumentException() + { + $this->setExpectedException('InvalidArgumentException'); + $options = new TestOptions; + $options->setFromArray('asd'); + } } diff --git a/tests/ZendTest/Stdlib/Strategy/SerializableStrategyTest.php b/tests/ZendTest/Stdlib/Strategy/SerializableStrategyTest.php new file mode 100644 index 00000000000..f36980de2c3 --- /dev/null +++ b/tests/ZendTest/Stdlib/Strategy/SerializableStrategyTest.php @@ -0,0 +1,53 @@ +setExpectedException('Zend\Stdlib\Exception\InvalidArgumentException'); + $serializerStrategy = new SerializableStrategy(false); + } + + public function testUseBadSerilizerObject() + { + $serializer = Serializer::factory('phpserialize'); + $serializerStrategy = new SerializableStrategy($serializer); + $this->assertEquals($serializer, $serializerStrategy->getSerializer()); + } + + public function testUseBadSerilizerString() + { + $serializerStrategy = new SerializableStrategy('phpserialize'); + $this->assertEquals('Zend\Serializer\Adapter\PhpSerialize', get_class($serializerStrategy->getSerializer())); + } + + public function testCanSerialize() + { + $serializer = Serializer::factory('phpserialize'); + $serializerStrategy = new SerializableStrategy($serializer); + $serialized = $serializerStrategy->extract('foo'); + $this->assertEquals($serialized, 's:3:"foo";'); + } + + public function testCanUnserialize() + { + $serializer = Serializer::factory('phpserialize'); + $serializerStrategy = new SerializableStrategy($serializer); + $serialized = $serializerStrategy->hydrate('s:3:"foo";'); + $this->assertEquals($serialized, 'foo'); + } +} diff --git a/tests/ZendTest/Validator/IsInstanceOfTest.php b/tests/ZendTest/Validator/IsInstanceOfTest.php new file mode 100644 index 00000000000..6594147df0b --- /dev/null +++ b/tests/ZendTest/Validator/IsInstanceOfTest.php @@ -0,0 +1,108 @@ +assertTrue($validator->isValid(new DateTime())); // True + $this->assertFalse($validator->isValid(null)); // False + $this->assertFalse($validator->isValid($this)); // False + + $validator = new Validator\IsInstanceOf('Exception'); + $this->assertTrue($validator->isValid(new \Exception())); // True + $this->assertFalse($validator->isValid(null)); // False + $this->assertFalse($validator->isValid($this)); // False + + $validator = new Validator\IsInstanceOf('PHPUnit_Framework_TestCase'); + $this->assertTrue($validator->isValid($this)); // True + } + + /** + * Ensures that getMessages() returns expected default value + * + * @return void + */ + public function testGetMessages() + { + $validator = new Validator\IsInstanceOf('DateTime'); + $this->assertEquals(array(), $validator->getMessages()); + } + + /** + * Ensures that getClassName() returns expected value + * + * @return void + */ + public function testGetClassName() + { + $validator = new Validator\IsInstanceOf('DateTime'); + $this->assertEquals('DateTime', $validator->getClassName()); + } + + public function testEqualsMessageTemplates() + { + $validator = new Validator\IsInstanceOf('DateTime'); + $reflection = new ReflectionClass($validator); + + $property = $reflection->getProperty('messageTemplates'); + $property->setAccessible(true); + + $this->assertEquals( + $property->getValue($validator), + $validator->getOption('messageTemplates') + ); + } + + public function testEqualsMessageVariables() + { + $validator = new Validator\IsInstanceOf('\DateTime'); + $reflection = new ReflectionClass($validator); + + $property = $reflection->getProperty('messageVariables'); + $property->setAccessible(true); + + $this->assertEquals( + $property->getValue($validator), + $validator->getOption('messageVariables') + ); + } +} diff --git a/tests/ZendTest/Validator/ValidatorChainTest.php b/tests/ZendTest/Validator/ValidatorChainTest.php index f1ae3fbd5ea..3d3a80b6fb9 100644 --- a/tests/ZendTest/Validator/ValidatorChainTest.php +++ b/tests/ZendTest/Validator/ValidatorChainTest.php @@ -45,6 +45,7 @@ public function setUp() public function tearDown() { + AbstractValidator::setDefaultTranslator(null); AbstractValidator::setMessageLength(-1); } diff --git a/tests/ZendTest/Validator/ValidatorPluginManagerTest.php b/tests/ZendTest/Validator/ValidatorPluginManagerTest.php new file mode 100644 index 00000000000..fa821242339 --- /dev/null +++ b/tests/ZendTest/Validator/ValidatorPluginManagerTest.php @@ -0,0 +1,76 @@ +validators = new ValidatorPluginManager(); + } + + public function testAllowsInjectingTranslator() + { + $translator = $this->getMock("Zend\I18n\Translator\Translator"); + + $slContents = array(array('translator', $translator)); + $serviceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); + $serviceLocator->expects($this->once()) + ->method('get') + ->will($this->returnValueMap($slContents)); + $serviceLocator->expects($this->once()) + ->method('has') + ->with($this->equalTo('translator')) + ->will($this->returnValue(true)); + + $this->validators->setServiceLocator($serviceLocator); + $this->assertSame($serviceLocator, $this->validators->getServiceLocator()); + + $validator = $this->validators->get('notempty'); + $this->assertSame($translator, $validator->getTranslator()); + } + + public function testNoTranslatorInjectedWhenTranslatorIsNotPresent() + { + $serviceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); + $serviceLocator->expects($this->once()) + ->method('has') + ->with($this->equalTo('translator')) + ->will($this->returnValue(false)); + + $this->validators->setServiceLocator($serviceLocator); + $this->assertSame($serviceLocator, $this->validators->getServiceLocator()); + + $validator = $this->validators->get('notempty'); + $this->assertNull($validator->getTranslator()); + } + + public function testRegisteringInvalidValidatorRaisesException() + { + $this->setExpectedException('Zend\Validator\Exception\RuntimeException'); + $this->validators->setService('test', $this); + } + + public function testLoadingInvalidValidatorRaisesException() + { + $this->validators->setInvokableClass('test', get_class($this)); + $this->setExpectedException('Zend\Validator\Exception\RuntimeException'); + $this->validators->get('test'); + } +} diff --git a/tests/ZendTest/View/Helper/HeadLinkTest.php b/tests/ZendTest/View/Helper/HeadLinkTest.php index 0c4e7b22331..77c078153a9 100644 --- a/tests/ZendTest/View/Helper/HeadLinkTest.php +++ b/tests/ZendTest/View/Helper/HeadLinkTest.php @@ -381,6 +381,22 @@ public function testSetStylesheetWithMediaAsArray() $this->assertContains(' media="screen,print"', $test); } + public function testSetPrevRelationship() + { + $this->helper->appendPrev('/foo/bar'); + $test = $this->helper->toString(); + $this->assertContains('href="/foo/bar"', $test); + $this->assertContains('rel="prev"', $test); + } + + public function testSetNextRelationship() + { + $this->helper->appendNext('/foo/bar'); + $test = $this->helper->toString(); + $this->assertContains('href="/foo/bar"', $test); + $this->assertContains('rel="next"', $test); + } + /** * @issue ZF-5435 */ diff --git a/tests/ZendTest/View/Helper/IdentityTest.php b/tests/ZendTest/View/Helper/IdentityTest.php new file mode 100644 index 00000000000..20dd70a544b --- /dev/null +++ b/tests/ZendTest/View/Helper/IdentityTest.php @@ -0,0 +1,51 @@ +setUsername('a username'); + $identity->setPassword('a password'); + + $authenticationService = new AuthenticationService(new NonPersistentStorage, new TestAsset\AuthenticationAdapter); + + $identityHelper = new IdentityHelper; + $identityHelper->setAuthenticationService($authenticationService); + + $this->assertNull($identityHelper()); + + $this->assertFalse($authenticationService->hasIdentity()); + + $authenticationService->getAdapter()->setIdentity($identity); + $result = $authenticationService->authenticate(); + $this->assertTrue($result->isValid()); + + $this->assertEquals($identity, $identityHelper()); + } +} diff --git a/tests/ZendTest/View/Helper/Placeholder/ContainerTest.php b/tests/ZendTest/View/Helper/Placeholder/ContainerTest.php index e62fb9d5687..7422039e4e7 100644 --- a/tests/ZendTest/View/Helper/Placeholder/ContainerTest.php +++ b/tests/ZendTest/View/Helper/Placeholder/ContainerTest.php @@ -123,6 +123,26 @@ public function testSetPostfixImplementsFluentInterface() $this->assertSame($this->container, $result); } + /** + * @return void + */ + + public function testPrependImplementsFluentInterface() + { + $result = $this->container->prepend( 'test' ); + $this->assertSame($this->container, $result); + } + + /** + * @return void + */ + public function testSetImplementsFluentInterface() + { + $result = $this->container->set( 'test' ); + $this->assertSame($this->container, $result); + } + + /** * @return void */ diff --git a/tests/ZendTest/View/Helper/TestAsset/AuthenticationAdapter.php b/tests/ZendTest/View/Helper/TestAsset/AuthenticationAdapter.php new file mode 100644 index 00000000000..1ed89161614 --- /dev/null +++ b/tests/ZendTest/View/Helper/TestAsset/AuthenticationAdapter.php @@ -0,0 +1,34 @@ +identity = $identity; + } + + public function authenticate() + { + return new Result(Result::SUCCESS, $this->identity); + } +} diff --git a/tests/ZendTest/View/Helper/TestAsset/IdentityObject.php b/tests/ZendTest/View/Helper/TestAsset/IdentityObject.php new file mode 100644 index 00000000000..d1606901a58 --- /dev/null +++ b/tests/ZendTest/View/Helper/TestAsset/IdentityObject.php @@ -0,0 +1,61 @@ +password = (string) $password; + } + + /** + * @return string|null + */ + public function getPassword() + { + return $this->password; + } + + /** + * @param string $username + */ + public function setUsername($username) + { + $this->username = (string) $username; + } + + /** + * @return string|null + */ + public function getUsername() + { + return $this->username; + } +} diff --git a/tests/ZendTest/View/HelperPluginManagerTest.php b/tests/ZendTest/View/HelperPluginManagerTest.php index fd5c8142a0c..b47613c8886 100644 --- a/tests/ZendTest/View/HelperPluginManagerTest.php +++ b/tests/ZendTest/View/HelperPluginManagerTest.php @@ -10,6 +10,7 @@ namespace ZendTest\View; +use Zend\ServiceManager\ServiceManager; use Zend\View\HelperPluginManager; use Zend\View\Renderer\PhpRenderer; @@ -64,4 +65,19 @@ public function testLoadingInvalidHelperRaisesException() $this->setExpectedException('Zend\View\Exception\InvalidHelperException'); $this->helpers->get('test'); } + + public function testDefinesFactoryForIdentityPlugin() + { + $this->assertTrue($this->helpers->has('identity')); + } + + public function testIdentityFactoryCanInjectAuthenticationServiceIfInParentServiceManager() + { + $services = new ServiceManager(); + $services->setInvokableClass('Zend\Authentication\AuthenticationService', 'Zend\Authentication\AuthenticationService'); + $this->helpers->setServiceLocator($services); + $identity = $this->helpers->get('identity'); + $expected = $services->get('Zend\Authentication\AuthenticationService'); + $this->assertSame($expected, $identity->getAuthenticationService()); + } }