diff --git a/library/Zend/Authentication/Adapter/Callback.php b/library/Zend/Authentication/Adapter/Callback.php new file mode 100644 index 000000000..dd3995634 --- /dev/null +++ b/library/Zend/Authentication/Adapter/Callback.php @@ -0,0 +1,90 @@ +setCallback($callback); + } + } + + /** + * Authenticate using the provided callback + * + * @return Result The authentication result + * @throws RuntimeException + */ + public function authenticate() + { + $callback = $this->getCallback(); + if (! $callback) { + throw new RuntimeException('No callback provided'); + } + + try { + $identity = call_user_func($callback, $this->getIdentity(), $this->getCredential()); + } catch (Exception $e) { + return new Result(Result::FAILURE_UNCATEGORIZED, null, array($e->getMessage())); + } + + if (! $identity) { + return new Result(Result::FAILURE, null, array('Authentication failure')); + } + + return new Result(Result::SUCCESS, $identity, array('Authentication success')); + } + + /** + * Gets the value of callback. + * + * @return null|callable + */ + public function getCallback() + { + return $this->callback; + } + + /** + * Sets the value of callback. + * + * @param callable $callback the callback + * @throws InvalidArgumentException + */ + public function setCallback($callback) + { + if (! is_callable($callback)) { + throw new InvalidArgumentException('Invalid callback provided'); + } + + $this->callback = $callback; + } +} diff --git a/library/Zend/Authentication/Adapter/DbTable/AbstractAdapter.php b/library/Zend/Authentication/Adapter/DbTable/AbstractAdapter.php index 11a07ef9b..21c68eb3c 100644 --- a/library/Zend/Authentication/Adapter/DbTable/AbstractAdapter.php +++ b/library/Zend/Authentication/Adapter/DbTable/AbstractAdapter.php @@ -148,7 +148,7 @@ abstract class AbstractAdapter extends BaseAdapter public function setAmbiguityIdentity($flag) { if (is_int($flag)) { - $this->ambiguityIdentity = (1 === $flag ? true : false); + $this->ambiguityIdentity = (1 === $flag); } elseif (is_bool($flag)) { $this->ambiguityIdentity = $flag; } diff --git a/library/Zend/Authentication/Adapter/Http.php b/library/Zend/Authentication/Adapter/Http.php index 7f8517fe7..5a56adc44 100644 --- a/library/Zend/Authentication/Adapter/Http.php +++ b/library/Zend/Authentication/Adapter/Http.php @@ -125,14 +125,14 @@ class Http implements AdapterInterface * * @var bool */ - protected $imaProxy; + protected $imaProxy = false; /** * Flag indicating the client is IE and didn't bother to return the opaque string * * @var bool */ - protected $ieNoOpaque; + protected $ieNoOpaque = false; /** * Constructor @@ -149,10 +149,6 @@ class Http implements AdapterInterface */ public function __construct(array $config) { - $this->request = null; - $this->response = null; - $this->ieNoOpaque = false; - if (empty($config['accept_schemes'])) { throw new Exception\InvalidArgumentException('Config key "accept_schemes" is required'); } @@ -181,6 +177,9 @@ class Http implements AdapterInterface } if (in_array('digest', $this->acceptSchemes)) { + $this->useOpaque = true; + $this->algo = 'MD5'; + if (empty($config['digest_domains']) || !ctype_print($config['digest_domains']) || strpos($config['digest_domains'], '"') !== false) { @@ -204,22 +203,16 @@ class Http implements AdapterInterface // We use the opaque value unless explicitly told not to if (isset($config['use_opaque']) && false == (bool) $config['use_opaque']) { $this->useOpaque = false; - } else { - $this->useOpaque = true; } if (isset($config['algorithm']) && in_array($config['algorithm'], $this->supportedAlgos)) { - $this->algo = $config['algorithm']; - } else { - $this->algo = 'MD5'; + $this->algo = (string) $config['algorithm']; } } // Don't be a proxy unless explicitly told to do so if (isset($config['proxy_auth']) && true == (bool) $config['proxy_auth']) { $this->imaProxy = true; // I'm a Proxy - } else { - $this->imaProxy = false; } } @@ -727,7 +720,7 @@ class Http implements AdapterInterface if (!$ret || empty($temp[1])) { return false; } - if (32 != strlen($temp[1]) || !ctype_xdigit($temp[1])) { + if (!$this->isValidMd5Hash($temp[1])) { return false; } @@ -778,7 +771,7 @@ class Http implements AdapterInterface // This implementation only sends MD5 hex strings in the opaque value if (!$this->ieNoOpaque && - (32 != strlen($temp[1]) || !ctype_xdigit($temp[1]))) { + !$this->isValidMd5Hash($temp[1])) { return false; } @@ -811,8 +804,17 @@ class Http implements AdapterInterface } $data['nc'] = $temp[1]; - $temp = null; return $data; } + + /** + * validates if $value is a valid Md5 hash + * @param string $value + * @return bool + */ + private function isValidMd5Hash($value) + { + return 32 == strlen($value) && ctype_xdigit($value); + } } diff --git a/library/Zend/Authentication/AuthenticationService.php b/library/Zend/Authentication/AuthenticationService.php index d95fc366d..06e82e2e9 100644 --- a/library/Zend/Authentication/AuthenticationService.php +++ b/library/Zend/Authentication/AuthenticationService.php @@ -144,7 +144,7 @@ class AuthenticationService implements AuthenticationServiceInterface $storage = $this->getStorage(); if ($storage->isEmpty()) { - return null; + return; } return $storage->read(); diff --git a/library/Zend/Authentication/Result.php b/library/Zend/Authentication/Result.php index 68cb49f58..086613c00 100644 --- a/library/Zend/Authentication/Result.php +++ b/library/Zend/Authentication/Result.php @@ -85,7 +85,7 @@ class Result */ public function isValid() { - return ($this->code > 0) ? true : false; + return ($this->code > 0); } /** diff --git a/library/Zend/Authentication/composer.json b/library/Zend/Authentication/composer.json index fd6d242b9..78c98ec12 100644 --- a/library/Zend/Authentication/composer.json +++ b/library/Zend/Authentication/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Authentication\\": "" } }, - "target-dir": "Zend/Authentication", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Barcode/Barcode.php b/library/Zend/Barcode/Barcode.php index ecd7df6eb..7cbc7ec44 100644 --- a/library/Zend/Barcode/Barcode.php +++ b/library/Zend/Barcode/Barcode.php @@ -10,6 +10,7 @@ namespace Zend\Barcode; use Traversable; +use Zend\Barcode\Renderer\RendererInterface; use Zend\Stdlib\ArrayUtils; /** @@ -92,7 +93,7 @@ abstract class Barcode * @param mixed $barcodeConfig OPTIONAL; an array or Traversable object with barcode parameters. * @param mixed $rendererConfig OPTIONAL; an array or Traversable object with renderer parameters. * @param bool $automaticRenderError OPTIONAL; set the automatic rendering of exception - * @return Barcode + * @return RendererInterface * @throws Exception\ExceptionInterface */ public static function factory( diff --git a/library/Zend/Barcode/Object/AbstractObject.php b/library/Zend/Barcode/Object/AbstractObject.php index a74c1dc77..b7761fe9a 100644 --- a/library/Zend/Barcode/Object/AbstractObject.php +++ b/library/Zend/Barcode/Object/AbstractObject.php @@ -874,7 +874,7 @@ abstract class AbstractObject implements ObjectInterface * @param string $font * @param int $color * @param string $alignment - * @param float $orientation + * @param float|int $orientation */ protected function addText( $text, diff --git a/library/Zend/Barcode/Renderer/AbstractRenderer.php b/library/Zend/Barcode/Renderer/AbstractRenderer.php index 3dfc1a85e..0d2b631cd 100644 --- a/library/Zend/Barcode/Renderer/AbstractRenderer.php +++ b/library/Zend/Barcode/Renderer/AbstractRenderer.php @@ -52,13 +52,13 @@ abstract class AbstractRenderer implements RendererInterface /** * Horizontal position of the barcode in the rendering resource - * @var int + * @var string */ protected $horizontalPosition = 'left'; /** * Vertical position of the barcode in the rendering resource - * @var int + * @var string */ protected $verticalPosition = 'top'; @@ -501,7 +501,7 @@ abstract class AbstractRenderer implements RendererInterface * @param string $font * @param int $color * @param string $alignment - * @param float $orientation + * @param float|int $orientation */ abstract protected function drawText( $text, diff --git a/library/Zend/Barcode/Renderer/Image.php b/library/Zend/Barcode/Renderer/Image.php index 182c81bcb..2bcd35ae3 100644 --- a/library/Zend/Barcode/Renderer/Image.php +++ b/library/Zend/Barcode/Renderer/Image.php @@ -204,6 +204,11 @@ class Image extends AbstractRenderer $height = $this->userHeight; } + // Cast width and height to ensure they are correct type for image + // operations + $width = (int) $width; + $height = (int) $height; + $this->resource = imagecreatetruecolor($width, $height); $white = imagecolorallocate($this->resource, 255, 255, 255); @@ -238,8 +243,8 @@ class Image extends AbstractRenderer $this->resource, $this->leftOffset, $this->topOffset, - $this->leftOffset + $barcodeWidth - 1, - $this->topOffset + $barcodeHeight - 1, + (int) ($this->leftOffset + $barcodeWidth - 1), + (int) ($this->topOffset + $barcodeHeight - 1), $this->imageBackgroundColor ); } @@ -358,7 +363,7 @@ class Image extends AbstractRenderer * @param string $font * @param int $color * @param string $alignment - * @param float $orientation + * @param float|int $orientation * @throws Exception\RuntimeException */ protected function drawText($text, $size, $position, $font, $color, $alignment = 'center', $orientation = 0) @@ -382,7 +387,7 @@ class Image extends AbstractRenderer * imagestring() doesn't allow orientation, if orientation * needed: a TTF font is required. * Throwing an exception here, allow to use automaticRenderError - * to informe user of the problem instead of simply not drawing + * to inform user of the problem instead of simply not drawing * the text */ throw new Exception\RuntimeException( diff --git a/library/Zend/Barcode/composer.json b/library/Zend/Barcode/composer.json index f351302eb..1014ad0f7 100644 --- a/library/Zend/Barcode/composer.json +++ b/library/Zend/Barcode/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Barcode\\": "" } }, - "target-dir": "Zend/Barcode", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version", diff --git a/library/Zend/Cache/Pattern/CallbackCache.php b/library/Zend/Cache/Pattern/CallbackCache.php index 4359924b6..ea5f0aef4 100644 --- a/library/Zend/Cache/Pattern/CallbackCache.php +++ b/library/Zend/Cache/Pattern/CallbackCache.php @@ -59,7 +59,7 @@ class CallbackCache extends AbstractPattern $cacheOutput = $options->getCacheOutput(); if ($cacheOutput) { ob_start(); - ob_implicit_flush(false); + ob_implicit_flush(0); } // TODO: do not cache on errors using [set|restore]_error_handler @@ -137,9 +137,11 @@ class CallbackCache extends AbstractPattern $callbackKey = strtolower($callbackKey); // generate a unique key of object callbacks - if (is_object($callback)) { // Closures & __invoke + if (is_object($callback)) { + // Closures & __invoke $object = $callback; - } elseif (isset($callback[0])) { // array($object, 'method') + } elseif (isset($callback[0])) { + // array($object, 'method') $object = $callback[0]; } if (isset($object)) { diff --git a/library/Zend/Cache/Pattern/CaptureCache.php b/library/Zend/Cache/Pattern/CaptureCache.php index f74b21619..216198053 100644 --- a/library/Zend/Cache/Pattern/CaptureCache.php +++ b/library/Zend/Cache/Pattern/CaptureCache.php @@ -35,7 +35,7 @@ class CaptureCache extends AbstractPattern return false; }); - ob_implicit_flush(false); + ob_implicit_flush(0); } /** diff --git a/library/Zend/Cache/Pattern/OutputCache.php b/library/Zend/Cache/Pattern/OutputCache.php index 9aa2e7e36..419e264e6 100644 --- a/library/Zend/Cache/Pattern/OutputCache.php +++ b/library/Zend/Cache/Pattern/OutputCache.php @@ -60,7 +60,7 @@ class OutputCache extends AbstractPattern } ob_start(); - ob_implicit_flush(false); + ob_implicit_flush(0); $this->keyStack[] = $key; return false; } diff --git a/library/Zend/Cache/Pattern/PatternOptions.php b/library/Zend/Cache/Pattern/PatternOptions.php index 33f243fe9..22ff70cc8 100644 --- a/library/Zend/Cache/Pattern/PatternOptions.php +++ b/library/Zend/Cache/Pattern/PatternOptions.php @@ -574,7 +574,7 @@ class PatternOptions extends AbstractOptions * Used by: * - ObjectCache * - * @param mixed $objectKey + * @param null|string $objectKey The object key or NULL to use the objects class name * @return PatternOptions */ public function setObjectKey($objectKey) @@ -597,7 +597,7 @@ class PatternOptions extends AbstractOptions */ public function getObjectKey() { - if (!$this->objectKey) { + if ($this->objectKey === null) { return get_class($this->getObject()); } return $this->objectKey; diff --git a/library/Zend/Cache/Storage/Adapter/AbstractAdapter.php b/library/Zend/Cache/Storage/Adapter/AbstractAdapter.php index 5b7a177bd..fdf8182f1 100644 --- a/library/Zend/Cache/Storage/Adapter/AbstractAdapter.php +++ b/library/Zend/Cache/Storage/Adapter/AbstractAdapter.php @@ -217,11 +217,10 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa { $postEvent = new PostEvent($eventName . '.post', $this, $args, $result); $eventRs = $this->getEventManager()->trigger($postEvent); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - return $postEvent->getResult(); + return $eventRs->stopped() + ? $eventRs->last() + : $postEvent->getResult(); } /** @@ -246,11 +245,9 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa throw $exceptionEvent->getException(); } - if ($eventRs->stopped()) { - return $eventRs->last(); - } - - return $exceptionEvent->getResult(); + return $eventRs->stopped() + ? $eventRs->last() + : $exceptionEvent->getResult(); } /** @@ -338,7 +335,7 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa { if (!$this->getOptions()->getReadable()) { $success = false; - return null; + return; } $this->normalizeKey($key); @@ -357,20 +354,21 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - if ($args->offsetExists('success') && $args->offsetExists('casToken')) { + if ($eventRs->stopped()) { + $result = $eventRs->last(); + } elseif ($args->offsetExists('success') && $args->offsetExists('casToken')) { $result = $this->internalGetItem($args['key'], $args['success'], $args['casToken']); } elseif ($args->offsetExists('success')) { $result = $this->internalGetItem($args['key'], $args['success']); } else { $result = $this->internalGetItem($args['key']); } + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { - $result = false; + $result = null; + $success = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } @@ -410,11 +408,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalGetItems($args['keys']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalGetItems($args['keys']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); @@ -467,11 +465,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalHasItem($args['key']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalHasItem($args['key']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -517,11 +515,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalHasItems($args['keys']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalHasItems($args['keys']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); @@ -571,11 +569,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalGetMetadata($args['key']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalGetMetadata($args['key']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -623,11 +621,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalGetMetadatas($args['keys']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalGetMetadatas($args['keys']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); @@ -682,11 +680,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalSetItem($args['key'], $args['value']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalSetItem($args['key'], $args['value']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -728,11 +726,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalSetItems($args['keyValuePairs']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalSetItems($args['keyValuePairs']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array_keys($keyValuePairs); @@ -784,11 +782,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalAddItem($args['key'], $args['value']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalAddItem($args['key'], $args['value']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -836,11 +834,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalAddItems($args['keyValuePairs']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalAddItems($args['keyValuePairs']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array_keys($keyValuePairs); @@ -892,11 +890,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalReplaceItem($args['key'], $args['value']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalReplaceItem($args['key'], $args['value']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -945,11 +943,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalReplaceItems($args['keyValuePairs']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalReplaceItems($args['keyValuePairs']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array_keys($keyValuePairs); @@ -1004,11 +1002,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalCheckAndSetItem($args['token'], $args['key'], $args['value']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalCheckAndSetItem($args['token'], $args['key'], $args['value']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -1061,11 +1059,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalTouchItem($args['key']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalTouchItem($args['key']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -1115,11 +1113,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalTouchItems($args['keys']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalTouchItems($args['keys']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { return $this->triggerException(__FUNCTION__, $args, $keys, $e); @@ -1168,11 +1166,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalRemoveItem($args['key']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalRemoveItem($args['key']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -1213,11 +1211,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalRemoveItems($args['keys']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalRemoveItems($args['keys']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { return $this->triggerException(__FUNCTION__, $args, $keys, $e); @@ -1268,11 +1266,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalIncrementItem($args['key'], $args['value']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalIncrementItem($args['key'], $args['value']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -1328,11 +1326,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalIncrementItems($args['keyValuePairs']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalIncrementItems($args['keyValuePairs']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); @@ -1385,11 +1383,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalDecrementItem($args['key'], $args['value']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalDecrementItem($args['key'], $args['value']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; @@ -1445,11 +1443,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalDecrementItems($args['keyValuePairs']); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalDecrementItems($args['keyValuePairs']); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); @@ -1492,11 +1490,11 @@ abstract class AbstractAdapter implements StorageInterface, EventsCapableInterfa try { $eventRs = $this->triggerPre(__FUNCTION__, $args); - if ($eventRs->stopped()) { - return $eventRs->last(); - } - $result = $this->internalGetCapabilities(); + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalGetCapabilities(); + return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; diff --git a/library/Zend/Cache/Storage/Adapter/Apc.php b/library/Zend/Cache/Storage/Adapter/Apc.php index eb442cef4..ddfcc1d34 100644 --- a/library/Zend/Cache/Storage/Adapter/Apc.php +++ b/library/Zend/Cache/Storage/Adapter/Apc.php @@ -221,7 +221,7 @@ class Apc extends AbstractAdapter implements $result = apc_fetch($internalKey, $success); if (!$success) { - return null; + return; } $casToken = $result; @@ -361,16 +361,19 @@ class Apc extends AbstractAdapter implements $options = $this->getOptions(); $namespace = $options->getNamespace(); + $prefixL = 0; + if ($namespace === '') { $pattern = '/^(' . implode('|', $keysRegExp) . ')' . '$/'; } else { $prefix = $namespace . $options->getNamespaceSeparator(); + $prefixL = strlen($prefix); $pattern = '/^' . preg_quote($prefix, '/') . '(' . implode('|', $keysRegExp) . ')' . '$/'; } + $format = APC_ITER_ALL ^ APC_ITER_VALUE ^ APC_ITER_TYPE ^ APC_ITER_REFCOUNT; $it = new BaseApcIterator('user', $pattern, $format, 100, APC_LIST_ACTIVE); $result = array(); - $prefixL = strlen($prefix); foreach ($it as $internalKey => $metadata) { // @see http://pecl.php.net/bugs/bug.php?id=22564 if (!apc_exists($internalKey)) { @@ -378,7 +381,7 @@ class Apc extends AbstractAdapter implements } $this->normalizeMetadata($metadata); - $result[substr($internalKey, $prefixL)] = & $metadata; + $result[substr($internalKey, $prefixL)] = $metadata; } return $result; diff --git a/library/Zend/Cache/Storage/Adapter/BlackHole.php b/library/Zend/Cache/Storage/Adapter/BlackHole.php index 1b860a06d..9feadbb94 100644 --- a/library/Zend/Cache/Storage/Adapter/BlackHole.php +++ b/library/Zend/Cache/Storage/Adapter/BlackHole.php @@ -113,7 +113,7 @@ class BlackHole implements public function getItem($key, & $success = null, & $casToken = null) { $success = false; - return null; + return; } /** diff --git a/library/Zend/Cache/Storage/Adapter/Dba.php b/library/Zend/Cache/Storage/Adapter/Dba.php index 128410d0c..eb3385035 100644 --- a/library/Zend/Cache/Storage/Adapter/Dba.php +++ b/library/Zend/Cache/Storage/Adapter/Dba.php @@ -81,7 +81,7 @@ class Dba extends AbstractAdapter implements * Set options. * * @param array|Traversable|DbaOptions $options - * @return Apc + * @return self * @see getOptions() */ public function setOptions($options) @@ -153,7 +153,7 @@ class Dba extends AbstractAdapter implements /** * Get available space in bytes * - * @return int|float + * @return float */ public function getAvailableSpace() { @@ -264,7 +264,8 @@ class Dba extends AbstractAdapter implements $this->_open(); - do { // Workaround for PHP-Bug #62491 & #62492 + // Workaround for PHP-Bug #62491 & #62492 + do { $recheck = false; $internalKey = dba_firstkey($this->handle); while ($internalKey !== false && $internalKey !== null) { @@ -285,7 +286,7 @@ class Dba extends AbstractAdapter implements /** * Get the storage iterator * - * @return ApcIterator + * @return DbaIterator */ public function getIterator() { @@ -335,7 +336,7 @@ class Dba extends AbstractAdapter implements if ($value === false) { $success = false; - return null; + return; } $success = true; @@ -377,8 +378,10 @@ class Dba extends AbstractAdapter implements $prefix = ($namespace === '') ? '' : $namespace . $options->getNamespaceSeparator(); $internalKey = $prefix . $normalizedKey; + $cacheableValue = (string) $value; // dba_replace requires a string + $this->_open(); - if (!dba_replace($internalKey, $value, $this->handle)) { + if (!dba_replace($internalKey, $cacheableValue, $this->handle)) { throw new Exception\RuntimeException("dba_replace('{$internalKey}', ...) failed"); } diff --git a/library/Zend/Cache/Storage/Adapter/DbaOptions.php b/library/Zend/Cache/Storage/Adapter/DbaOptions.php index 588141d87..c913e673f 100644 --- a/library/Zend/Cache/Storage/Adapter/DbaOptions.php +++ b/library/Zend/Cache/Storage/Adapter/DbaOptions.php @@ -117,6 +117,12 @@ class DbaOptions extends AdapterOptions throw new Exception\ExtensionNotLoadedException("DBA-Handler '{$handler}' not supported"); } + if ($handler === 'inifile') { + throw new Exception\ExtensionNotLoadedException( + "DBA-Handler 'inifile' does not reliably support write operations" + ); + } + $this->triggerOptionEvent('handler', $handler); $this->handler = $handler; return $this; diff --git a/library/Zend/Cache/Storage/Adapter/Filesystem.php b/library/Zend/Cache/Storage/Adapter/Filesystem.php index 8f0f17e12..5afe887c2 100644 --- a/library/Zend/Cache/Storage/Adapter/Filesystem.php +++ b/library/Zend/Cache/Storage/Adapter/Filesystem.php @@ -433,7 +433,7 @@ class Filesystem extends AbstractAdapter implements * Get available space in bytes * * @throws Exception\RuntimeException - * @return int|float + * @return float */ public function getAvailableSpace() { @@ -508,14 +508,15 @@ class Filesystem extends AbstractAdapter implements * @param string $normalizedKey * @param bool $success * @param mixed $casToken - * @return mixed Data on success, null on failure + * @return null|mixed Data on success, null on failure * @throws Exception\ExceptionInterface + * @throws BaseException */ protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null) { if (!$this->internalHasItem($normalizedKey)) { $success = false; - return null; + return; } try { @@ -915,8 +916,6 @@ class Filesystem extends AbstractAdapter implements */ protected function internalSetItems(array & $normalizedKeyValuePairs) { - $oldUmask = null; - // create an associated array of files and contents to write $contents = array(); foreach ($normalizedKeyValuePairs as $key => & $value) { @@ -1499,6 +1498,11 @@ class Filesystem extends AbstractAdapter implements */ protected function putFileContent($file, $data, $nonBlocking = false, & $wouldblock = null) { + if (! is_string($data)) { + // Ensure we have a string + $data = (string) $data; + } + $options = $this->getOptions(); $locking = $options->getFileLocking(); $nonBlocking = $locking && $nonBlocking; diff --git a/library/Zend/Cache/Storage/Adapter/Memcache.php b/library/Zend/Cache/Storage/Adapter/Memcache.php index d9722a669..8f2512a09 100644 --- a/library/Zend/Cache/Storage/Adapter/Memcache.php +++ b/library/Zend/Cache/Storage/Adapter/Memcache.php @@ -67,7 +67,7 @@ class Memcache extends AbstractAdapter implements // reset initialized flag on update option(s) $initialized = & $this->initialized; - $this->getEventManager()->attach('option', function ($event) use (& $initialized) { + $this->getEventManager()->attach('option', function () use (& $initialized) { $initialized = false; }); } @@ -220,7 +220,7 @@ class Memcache extends AbstractAdapter implements $result = $memc->get($internalKey); $success = ($result !== false); if ($result === false) { - return null; + return; } $casToken = $result; diff --git a/library/Zend/Cache/Storage/Adapter/MemcacheResourceManager.php b/library/Zend/Cache/Storage/Adapter/MemcacheResourceManager.php index 81670a30b..5a5307571 100644 --- a/library/Zend/Cache/Storage/Adapter/MemcacheResourceManager.php +++ b/library/Zend/Cache/Storage/Adapter/MemcacheResourceManager.php @@ -95,6 +95,8 @@ class MemcacheResourceManager * * @param string $id * @param array|Traversable|MemcacheResource $resource + * @param callable $failureCallback + * @param array|Traversable $serverDefaults * @return MemcacheResourceManager */ public function setResource($id, $resource, $failureCallback = null, $serverDefaults = array()) @@ -184,7 +186,8 @@ class MemcacheResourceManager * Set compress threshold on a Memcache resource * * @param MemcacheResource $resource - * @param array $libOptions + * @param int $threshold + * @param float $minSavings */ protected function setResourceAutoCompressThreshold(MemcacheResource $resource, $threshold, $minSavings) { @@ -396,7 +399,7 @@ class MemcacheResourceManager * Get callback for server connection failures * * @param string $id - * @return callable|null + * @return callable * @throws Exception\RuntimeException */ public function getFailureCallback($id) diff --git a/library/Zend/Cache/Storage/Adapter/Memcached.php b/library/Zend/Cache/Storage/Adapter/Memcached.php index f7fab63d5..14bcefb62 100644 --- a/library/Zend/Cache/Storage/Adapter/Memcached.php +++ b/library/Zend/Cache/Storage/Adapter/Memcached.php @@ -79,7 +79,7 @@ class Memcached extends AbstractAdapter implements // reset initialized flag on update option(s) $initialized = & $this->initialized; - $this->getEventManager()->attach('option', function ($event) use (& $initialized) { + $this->getEventManager()->attach('option', function () use (& $initialized) { $initialized = false; }); } diff --git a/library/Zend/Cache/Storage/Adapter/Memory.php b/library/Zend/Cache/Storage/Adapter/Memory.php index b54c03f23..6973d0394 100644 --- a/library/Zend/Cache/Storage/Adapter/Memory.php +++ b/library/Zend/Cache/Storage/Adapter/Memory.php @@ -84,7 +84,7 @@ class Memory extends AbstractAdapter implements /** * Get total space in bytes * - * @return int|float + * @return int */ public function getTotalSpace() { @@ -307,7 +307,7 @@ class Memory extends AbstractAdapter implements } if (!$success) { - return null; + return; } $casToken = $data[0]; diff --git a/library/Zend/Cache/Storage/Adapter/MongoDb.php b/library/Zend/Cache/Storage/Adapter/MongoDb.php new file mode 100644 index 000000000..f962fbd87 --- /dev/null +++ b/library/Zend/Cache/Storage/Adapter/MongoDb.php @@ -0,0 +1,285 @@ +initialized; + + $this->getEventManager()->attach( + 'option', + function () use (& $initialized) { + $initialized = false; + } + ); + } + + /** + * get mongodb resource + * + * @return MongoResource + */ + private function getMongoDbResource() + { + if (! $this->initialized) { + $options = $this->getOptions(); + + $this->resourceManager = $options->getResourceManager(); + $this->resourceId = $options->getResourceId(); + $namespace = $options->getNamespace(); + $this->namespacePrefix = ($namespace === '' ? '' : $namespace . $options->getNamespaceSeparator()); + $this->initialized = true; + } + + return $this->resourceManager->getResource($this->resourceId); + } + + /** + * {@inheritDoc} + */ + public function setOptions($options) + { + return parent::setOptions($options instanceof MongoDbOptions ? $options : new MongoDbOptions($options)); + } + + /** + * Get options. + * + * @return MongoDbOptions + * @see setOptions() + */ + public function getOptions() + { + return $this->options; + } + + /** + * {@inheritDoc} + * + * @throws Exception\RuntimeException + */ + protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null) + { + $result = $this->fetchFromCollection($normalizedKey); + $success = false; + + if (null === $result) { + return; + } + + if (isset($result['expires'])) { + if (! $result['expires'] instanceof MongoDate) { + throw new Exception\RuntimeException(sprintf( + "The found item _id '%s' for key '%s' is not a valid cache item" + . ": the field 'expired' isn't an instance of MongoDate, '%s' found instead", + (string) $result['_id'], + $this->namespacePrefix . $normalizedKey, + is_object($result['expires']) ? get_class($result['expires']) : gettype($result['expires']) + )); + } + + if ($result['expires']->sec < time()) { + $this->internalRemoveItem($key); + + return; + } + } + + if (! array_key_exists('value', $result)) { + throw new Exception\RuntimeException(sprintf( + "The found item _id '%s' for key '%s' is not a valid cache item: missing the field 'value'", + (string) $result['_id'], + $this->namespacePrefix . $normalizedKey + )); + } + + $success = true; + + return $casToken = $result['value']; + } + + /** + * {@inheritDoc} + * + * @throws Exception\RuntimeException + */ + protected function internalSetItem(& $normalizedKey, & $value) + { + $mongo = $this->getMongoDbResource(); + $key = $this->namespacePrefix . $normalizedKey; + $ttl = $this->getOptions()->getTTl(); + $expires = null; + $cacheItem = array( + 'key' => $key, + 'value' => $value, + ); + + if ($ttl > 0) { + $expiresMicro = microtime(true) + $ttl; + $expiresSecs = (int) $expiresMicro; + $cacheItem['expires'] = new MongoDate($expiresSecs, $expiresMicro - $expiresSecs); + } + + try { + $mongo->remove(array('key' => $key)); + + $result = $mongo->insert($cacheItem); + } catch (MongoResourceException $e) { + throw new Exception\RuntimeException($e->getMessage(), $e->getCode(), $e); + } + + return null !== $result && ((double) 1) === $result['ok']; + } + + /** + * {@inheritDoc} + * + * @throws Exception\RuntimeException + */ + protected function internalRemoveItem(& $normalizedKey) + { + try { + $result = $this->getMongoDbResource()->remove(array('key' => $this->namespacePrefix . $normalizedKey)); + } catch (MongoResourceException $e) { + throw new Exception\RuntimeException($e->getMessage(), $e->getCode(), $e); + } + + return false !== $result + && ((double) 1) === $result['ok'] + && $result['n'] > 0; + } + + /** + * {@inheritDoc} + */ + public function flush() + { + $result = $this->getMongoDbResource()->drop(); + + return ((double) 1) === $result['ok']; + } + + /** + * {@inheritDoc} + */ + protected function internalGetCapabilities() + { + if ($this->capabilities) { + return $this->capabilities; + } + + return $this->capabilities = new Capabilities( + $this, + $this->capabilityMarker = new stdClass(), + array( + 'supportedDatatypes' => array( + 'NULL' => true, + 'boolean' => true, + 'integer' => true, + 'double' => true, + 'string' => true, + 'array' => true, + 'object' => false, + 'resource' => false, + ), + 'supportedMetadata' => array( + '_id', + ), + 'minTtl' => 0, + 'maxTtl' => 0, + 'staticTtl' => true, + 'ttlPrecision' => 1, + 'useRequestTime' => false, + 'expiredRead' => false, + 'maxKeyLength' => 255, + 'namespaceIsPrefix' => true, + ) + ); + } + + /** + * {@inheritDoc} + * + * @throws Exception\ExceptionInterface + */ + protected function internalGetMetadata(& $normalizedKey) + { + $result = $this->fetchFromCollection($normalizedKey); + + return null !== $result ? array('_id' => $result['_id']) : false; + } + + /** + * Return raw records from MongoCollection + * + * @param string $normalizedKey + * + * @return array|null + * + * @throws Exception\RuntimeException + */ + private function fetchFromCollection(& $normalizedKey) + { + try { + return $this->getMongoDbResource()->findOne(array('key' => $this->namespacePrefix . $normalizedKey)); + } catch (MongoResourceException $e) { + throw new Exception\RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/library/Zend/Cache/Storage/Adapter/MongoDbOptions.php b/library/Zend/Cache/Storage/Adapter/MongoDbOptions.php new file mode 100644 index 000000000..4b87abc32 --- /dev/null +++ b/library/Zend/Cache/Storage/Adapter/MongoDbOptions.php @@ -0,0 +1,158 @@ +namespaceSeparator !== $namespaceSeparator) { + $this->triggerOptionEvent('namespace_separator', $namespaceSeparator); + + $this->namespaceSeparator = $namespaceSeparator; + } + + return $this; + } + + /** + * Get namespace separator + * + * @return string + */ + public function getNamespaceSeparator() + { + return $this->namespaceSeparator; + } + + /** + * Set the mongodb resource manager to use + * + * @param null|MongoDbResourceManager $resourceManager + * + * @return self + */ + public function setResourceManager(MongoDbResourceManager $resourceManager = null) + { + if ($this->resourceManager !== $resourceManager) { + $this->triggerOptionEvent('resource_manager', $resourceManager); + + $this->resourceManager = $resourceManager; + } + + return $this; + } + + /** + * Get the mongodb resource manager + * + * @return MongoDbResourceManager + */ + public function getResourceManager() + { + return $this->resourceManager ?: $this->resourceManager = new MongoDbResourceManager(); + } + + /** + * Get the mongodb resource id + * + * @return string + */ + public function getResourceId() + { + return $this->resourceId; + } + + /** + * Set the redis resource id + * + * @param string $resourceId + * + * @return self + */ + public function setResourceId($resourceId) + { + $resourceId = (string) $resourceId; + + if ($this->resourceId !== $resourceId) { + $this->triggerOptionEvent('resource_id', $resourceId); + + $this->resourceId = $resourceId; + } + + return $this; + } + + /** + * Set the mongo DB server + * + * @param string $server + * @return self + */ + public function setServer($server) + { + $this->getResourceManager()->setServer($this->getResourceId(), $server); + return $this; + } + + public function setConnectionOptions(array $connectionOptions) + { + $this->getResourceManager()->setConnectionOptions($this->getResourceId(), $connectionOptions); + return $this; + } + + public function setDriverOptions(array $driverOptions) + { + $this->getResourceManager()->setDriverOptions($this->getResourceId(), $driverOptions); + return $this; + } + + public function setDatabase($database) + { + $this->getResourceManager()->setDatabase($this->getResourceId(), $database); + return $this; + } + + public function setCollection($collection) + { + $this->getResourceManager()->setCollection($this->getResourceId(), $collection); + return $this; + } +} diff --git a/library/Zend/Cache/Storage/Adapter/MongoDbResourceManager.php b/library/Zend/Cache/Storage/Adapter/MongoDbResourceManager.php new file mode 100644 index 000000000..fa1878be3 --- /dev/null +++ b/library/Zend/Cache/Storage/Adapter/MongoDbResourceManager.php @@ -0,0 +1,204 @@ +resources[$id]); + } + + /** + * Set a resource + * + * @param string $id + * @param array|MongoCollection $resource + * + * @return self + * + * @throws Exception\RuntimeException + */ + public function setResource($id, $resource) + { + if ($resource instanceof MongoCollection) { + $this->resources[$id] = array( + 'db' => (string) $resource->db, + 'db_instance' => $resource->db, + 'collection' => (string) $resource, + 'collection_instance' => $resource, + ); + return $this; + } + + if (! is_array($resource)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects an array or MongoCollection; received %s', + __METHOD__, + (is_object($resource) ? get_class($resource) : gettype($resource)) + )); + } + + $this->resources[$id] = $resource; + return $this; + } + + /** + * Instantiate and return the MongoCollection resource + * + * @param string $id + * @return MongoCollection + * @throws Exception\RuntimeException + */ + public function getResource($id) + { + if (!$this->hasResource($id)) { + throw new Exception\RuntimeException("No resource with id '{$id}'"); + } + + $resource = $this->resources[$id]; + if (!isset($resource['collection_instance'])) { + try { + if (!isset($resource['db_instance'])) { + if (!isset($resource['client_instance'])) { + $clientClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; + $resource['client_instance'] = new $clientClass( + isset($resource['server']) ? $resource['server'] : null, + isset($resource['connection_options']) ? $resource['connection_options'] : array(), + isset($resource['driver_options']) ? $resource['driver_options'] : array() + ); + } + + $resource['db_instance'] = $resource['client_instance']->selectDB( + isset($resource['db']) ? $resource['db'] : '' + ); + } + + $collection = $resource['db_instance']->selectCollection( + isset($resource['collection']) ? $resource['collection'] : '' + ); + $collection->ensureIndex(array('key' => 1)); + + $this->resources[$id]['collection_instance'] = $collection; + } catch (MongoException $e) { + throw new Exception\RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } + + return $this->resources[$id]['collection_instance']; + } + + public function setServer($id, $server) + { + $this->resources[$id]['server'] = (string)$server; + + unset($this->resource[$id]['client_instance']); + unset($this->resource[$id]['db_instance']); + unset($this->resource[$id]['collection_instance']); + } + + public function getServer($id) + { + if (!$this->hasResource($id)) { + throw new Exception\RuntimeException("No resource with id '{$id}'"); + } + + return isset($this->resources[$id]['server']) ? $this->resources[$id]['server'] : null; + } + + public function setConnectionOptions($id, array $connectionOptions) + { + $this->resources[$id]['connection_options'] = $connectionOptions; + + unset($this->resource[$id]['client_instance']); + unset($this->resource[$id]['db_instance']); + unset($this->resource[$id]['collection_instance']); + } + + public function getConnectionOptions($id) + { + if (!$this->hasResource($id)) { + throw new Exception\RuntimeException("No resource with id '{$id}'"); + } + + return isset($this->resources[$id]['connection_options']) + ? $this->resources[$id]['connection_options'] + : array(); + } + + public function setDriverOptions($id, array $driverOptions) + { + $this->resources[$id]['driver_options'] = $driverOptions; + + unset($this->resource[$id]['client_instance']); + unset($this->resource[$id]['db_instance']); + unset($this->resource[$id]['collection_instance']); + } + + public function getDriverOptions($id) + { + if (!$this->hasResource($id)) { + throw new Exception\RuntimeException("No resource with id '{$id}'"); + } + + return isset($this->resources[$id]['driver_options']) ? $this->resources[$id]['driver_options'] : array(); + } + + public function setDatabase($id, $database) + { + $this->resources[$id]['db'] = (string)$database; + + unset($this->resource[$id]['db_instance']); + unset($this->resource[$id]['collection_instance']); + } + + public function getDatabase($id) + { + if (!$this->hasResource($id)) { + throw new Exception\RuntimeException("No resource with id '{$id}'"); + } + + return isset($this->resources[$id]['db']) ? $this->resources[$id]['db'] : ''; + } + + public function setCollection($id, $collection) + { + $this->resources[$id]['collection'] = (string)$collection; + + unset($this->resource[$id]['collection_instance']); + } + + public function getCollection($id) + { + if (!$this->hasResource($id)) { + throw new Exception\RuntimeException("No resource with id '{$id}'"); + } + + return isset($this->resources[$id]['collection']) ? $this->resources[$id]['collection'] : ''; + } +} diff --git a/library/Zend/Cache/Storage/Adapter/Redis.php b/library/Zend/Cache/Storage/Adapter/Redis.php index ba40ffa70..da76c1fff 100644 --- a/library/Zend/Cache/Storage/Adapter/Redis.php +++ b/library/Zend/Cache/Storage/Adapter/Redis.php @@ -13,12 +13,14 @@ use Redis as RedisResource; use RedisException as RedisResourceException; use stdClass; use Traversable; +use Zend\Cache\Storage\ClearByPrefixInterface; use Zend\Cache\Exception; use Zend\Cache\Storage\Capabilities; use Zend\Cache\Storage\FlushableInterface; use Zend\Cache\Storage\TotalSpaceCapableInterface; class Redis extends AbstractAdapter implements + ClearByPrefixInterface, FlushableInterface, TotalSpaceCapableInterface { @@ -66,7 +68,7 @@ class Redis extends AbstractAdapter implements // reset initialized flag on update option(s) $initialized = & $this->initialized; - $this->getEventManager()->attach('option', function ($event) use (& $initialized) { + $this->getEventManager()->attach('option', function () use (& $initialized) { $initialized = false; }); } @@ -151,7 +153,7 @@ class Redis extends AbstractAdapter implements if ($value === false) { $success = false; - return null; + return; } $success = true; @@ -368,6 +370,32 @@ class Redis extends AbstractAdapter implements } } + /* ClearByPrefixInterface */ + + /** + * Remove items matching given prefix + * + * @param string $prefix + * @return bool + */ + public function clearByPrefix($prefix) + { + $redis = $this->getRedisResource(); + + $prefix = (string) $prefix; + if ($prefix === '') { + throw new Exception\InvalidArgumentException('No prefix given'); + } + + $options = $this->getOptions(); + $namespace = $options->getNamespace(); + $prefix = ($namespace === '') ? '' : $namespace . $options->getNamespaceSeparator() . $prefix; + + $redis->delete($redis->keys($prefix.'*')); + + return true; + } + /* TotalSpaceCapableInterface */ /** diff --git a/library/Zend/Cache/Storage/Adapter/RedisResourceManager.php b/library/Zend/Cache/Storage/Adapter/RedisResourceManager.php index 772bd3c79..3425dc4dc 100644 --- a/library/Zend/Cache/Storage/Adapter/RedisResourceManager.php +++ b/library/Zend/Cache/Storage/Adapter/RedisResourceManager.php @@ -105,7 +105,7 @@ class RedisResourceManager * Gets a redis resource * * @param string $id - * @return RedisResource + * @return RedisResourceManager * @throws Exception\RuntimeException */ public function getResource($id) @@ -233,14 +233,14 @@ class RedisResourceManager } if (! is_string($serverUri)) { - return null; + return; } // parse server from URI host{:?port} $server = trim($serverUri); if (strpos($server, '/') === 0) { - return null; + return; } //non unix domain socket connection @@ -627,7 +627,7 @@ class RedisResourceManager * * @param string $id * @param int $database - * @return RedisResource + * @return RedisResourceManager */ public function setDatabase($id, $database) { diff --git a/library/Zend/Cache/Storage/Adapter/Session.php b/library/Zend/Cache/Storage/Adapter/Session.php index 2be5cc2db..65f4fcbcb 100644 --- a/library/Zend/Cache/Storage/Adapter/Session.php +++ b/library/Zend/Cache/Storage/Adapter/Session.php @@ -152,13 +152,13 @@ class Session extends AbstractAdapter implements if (!$cntr->offsetExists($ns)) { $success = false; - return null; + return; } $data = $cntr->offsetGet($ns); $success = array_key_exists($normalizedKey, $data); if (!$success) { - return null; + return; } $casToken = $value = $data[$normalizedKey]; diff --git a/library/Zend/Cache/Storage/AdapterPluginManager.php b/library/Zend/Cache/Storage/AdapterPluginManager.php index 6278d3c1f..f852cab12 100644 --- a/library/Zend/Cache/Storage/AdapterPluginManager.php +++ b/library/Zend/Cache/Storage/AdapterPluginManager.php @@ -34,6 +34,7 @@ class AdapterPluginManager extends AbstractPluginManager 'memcache' => 'Zend\Cache\Storage\Adapter\Memcache', 'memcached' => 'Zend\Cache\Storage\Adapter\Memcached', 'memory' => 'Zend\Cache\Storage\Adapter\Memory', + 'mongodb' => 'Zend\Cache\Storage\Adapter\MongoDb', 'redis' => 'Zend\Cache\Storage\Adapter\Redis', 'session' => 'Zend\Cache\Storage\Adapter\Session', 'xcache' => 'Zend\Cache\Storage\Adapter\XCache', diff --git a/library/Zend/Cache/Storage/Plugin/PluginOptions.php b/library/Zend/Cache/Storage/Plugin/PluginOptions.php index 59ea170aa..5226dd75e 100644 --- a/library/Zend/Cache/Storage/Plugin/PluginOptions.php +++ b/library/Zend/Cache/Storage/Plugin/PluginOptions.php @@ -26,7 +26,7 @@ class PluginOptions extends AbstractOptions /** * Used by: * - ExceptionHandler - * @var callable + * @var null|callable */ protected $exceptionCallback; @@ -99,7 +99,7 @@ class PluginOptions extends AbstractOptions * Used by: * - ExceptionHandler * - * @param callable $exceptionCallback + * @param null|callable $exceptionCallback * @throws Exception\InvalidArgumentException * @return PluginOptions */ @@ -118,7 +118,7 @@ class PluginOptions extends AbstractOptions * Used by: * - ExceptionHandler * - * @return callable + * @return null|callable */ public function getExceptionCallback() { diff --git a/library/Zend/Cache/composer.json b/library/Zend/Cache/composer.json index 3d20dff9a..c2bfad4ff 100644 --- a/library/Zend/Cache/composer.json +++ b/library/Zend/Cache/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Cache\\": "" } }, - "target-dir": "Zend/Cache", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version", @@ -29,7 +28,9 @@ "ext-apc": "APC >= 3.1.6 to use the APC storage adapter", "ext-dba": "DBA, to use the DBA storage adapter", "ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter", - "ext-wincache": "WinCache, to use the WinCache storage adapter" + "ext-mongo": "Mongo, to use MongoDb storage adapter", + "ext-wincache": "WinCache, to use the WinCache storage adapter", + "mongofill/mongofill": "Alternative to ext-mongo - a pure PHP implementation designed as a drop in replacement" }, "extra": { "branch-alias": { diff --git a/library/Zend/Captcha/composer.json b/library/Zend/Captcha/composer.json index fec1684fe..52842a878 100644 --- a/library/Zend/Captcha/composer.json +++ b/library/Zend/Captcha/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Captcha\\": "" } }, - "target-dir": "Zend/Captcha", "require": { "php": ">=5.3.23", "zendframework/zend-math": "self.version", diff --git a/library/Zend/Code/Generator/ClassGenerator.php b/library/Zend/Code/Generator/ClassGenerator.php index d0791d332..bf9a1f34d 100644 --- a/library/Zend/Code/Generator/ClassGenerator.php +++ b/library/Zend/Code/Generator/ClassGenerator.php @@ -13,6 +13,8 @@ use Zend\Code\Reflection\ClassReflection; class ClassGenerator extends AbstractGenerator { + const OBJECT_TYPE = "class"; + const FLAG_ABSTRACT = 0x01; const FLAG_FINAL = 0x02; @@ -56,15 +58,20 @@ class ClassGenerator extends AbstractGenerator */ protected $properties = array(); + /** + * @var PropertyGenerator[] Array of constants + */ + protected $constants = array(); + /** * @var MethodGenerator[] Array of methods */ protected $methods = array(); /** - * @var array Array of string names + * @var TraitUsageGenerator Object to encapsulate trait usage logic */ - protected $uses = array(); + protected $traitUsageGenerator; /** * Build a Code Generation Php Object from a Class Reflection @@ -74,7 +81,6 @@ class ClassGenerator extends AbstractGenerator */ public static function fromReflection(ClassReflection $classReflection) { - // class generator $cg = new static($classReflection->getName()); $cg->setSourceContent($cg->getSourceContent()); @@ -93,11 +99,12 @@ class ClassGenerator extends AbstractGenerator /* @var \Zend\Code\Reflection\ClassReflection $parentClass */ $parentClass = $classReflection->getParentClass(); + $interfaces = $classReflection->getInterfaces(); + if ($parentClass) { $cg->setExtendedClass($parentClass->getName()); - $interfaces = array_diff($classReflection->getInterfaces(), $parentClass->getInterfaces()); - } else { - $interfaces = $classReflection->getInterfaces(); + + $interfaces = array_diff($interfaces, $parentClass->getInterfaces()); } $interfaceNames = array(); @@ -109,20 +116,36 @@ class ClassGenerator extends AbstractGenerator $cg->setImplementedInterfaces($interfaceNames); $properties = array(); + foreach ($classReflection->getProperties() as $reflectionProperty) { if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) { $properties[] = PropertyGenerator::fromReflection($reflectionProperty); } } + $cg->addProperties($properties); + $constants = array(); + + foreach ($classReflection->getConstants() as $name => $value) { + $constants[] = array( + 'name' => $name, + 'value' => $value + ); + } + + $cg->addConstants($constants); + $methods = array(); + foreach ($classReflection->getMethods() as $reflectionMethod) { - $className = ($cg->getNamespaceName())? $cg->getNamespaceName() . "\\" . $cg->getName() : $cg->getName(); + $className = ($cg->getNamespaceName()) ? $cg->getNamespaceName() . "\\" . $cg->getName() : $cg->getName(); + if ($reflectionMethod->getDeclaringClass()->getName() == $className) { $methods[] = MethodGenerator::fromReflection($reflectionMethod); } } + $cg->addMethods($methods); return $cg; @@ -208,6 +231,8 @@ class ClassGenerator extends AbstractGenerator $methods = array(), $docBlock = null ) { + $this->traitUsageGenerator = new TraitUsageGenerator($this); + if ($name !== null) { $this->setName($name); } @@ -421,6 +446,114 @@ class ClassGenerator extends AbstractGenerator return $this->implementedInterfaces; } + /** + * @param string $constantName + * + * @return PropertyGenerator|false + */ + public function getConstant($constantName) + { + if (isset($this->constants[$constantName])) { + return $this->constants[$constantName]; + } + + return false; + } + + /** + * @return PropertyGenerator[] indexed by constant name + */ + public function getConstants() + { + return $this->constants; + } + + /** + * @param string $constantName + * @return bool + */ + public function hasConstant($constantName) + { + return isset($this->constants[$constantName]); + } + + /** + * Add constant from PropertyGenerator + * + * @param PropertyGenerator $constant + * @throws Exception\InvalidArgumentException + * @return ClassGenerator + */ + public function addConstantFromGenerator(PropertyGenerator $constant) + { + $constantName = $constant->getName(); + + if (isset($this->constants[$constantName])) { + throw new Exception\InvalidArgumentException(sprintf( + 'A constant by name %s already exists in this class.', + $constantName + )); + } + + if (! $constant->isConst()) { + throw new Exception\InvalidArgumentException(sprintf( + 'The value %s is not defined as a constant.', + $constantName + )); + } + + $this->constants[$constantName] = $constant; + + return $this; + } + + /** + * Add Constant + * + * @param string $name + * @param string $value + * @throws Exception\InvalidArgumentException + * @return ClassGenerator + */ + public function addConstant($name, $value) + { + if (!is_string($name)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects string for name', + __METHOD__ + )); + } + + if (empty($value) || !is_string($value)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects value for constant, value must be a string', + __METHOD__ + )); + } + + return $this->addConstantFromGenerator(new PropertyGenerator($name, $value, PropertyGenerator::FLAG_CONSTANT)); + } + + /** + * @param PropertyGenerator[]|array[] $constants + * + * @return ClassGenerator + */ + public function addConstants(array $constants) + { + foreach ($constants as $constant) { + if ($constant instanceof PropertyGenerator) { + $this->addPropertyFromGenerator($constant); + } else { + if (is_array($constant)) { + call_user_func_array(array($this, 'addConstant'), $constant); + } + } + } + + return $this; + } + /** * @param array $properties * @return ClassGenerator @@ -455,11 +588,18 @@ class ClassGenerator extends AbstractGenerator { if (!is_string($name)) { throw new Exception\InvalidArgumentException(sprintf( - '%s expects string for name', - __METHOD__ + '%s::%s expects string for name', + get_class($this), + __FUNCTION__ )); } + // backwards compatibility + // @todo remove this on next major version + if ($flags === PropertyGenerator::FLAG_CONSTANT) { + return $this->addConstant($name, $defaultValue); + } + return $this->addPropertyFromGenerator(new PropertyGenerator($name, $defaultValue, $flags)); } @@ -481,24 +621,13 @@ class ClassGenerator extends AbstractGenerator )); } - $this->properties[$propertyName] = $property; - return $this; - } - - /** - * Add a class to "use" classes - * - * @param string $use - * @param string|null $useAlias - * @return ClassGenerator - */ - public function addUse($use, $useAlias = null) - { - if (!empty($useAlias)) { - $use .= ' as ' . $useAlias; + // backwards compatibility + // @todo remove this on next major version + if ($property->isConst()) { + return $this->addConstantFromGenerator($property); } - $this->uses[$use] = $use; + $this->properties[$propertyName] = $property; return $this; } @@ -525,6 +654,19 @@ class ClassGenerator extends AbstractGenerator return false; } + /** + * Add a class to "use" classes + * + * @param string $use + * @param string|null $useAlias + * @return ClassGenerator + */ + public function addUse($use, $useAlias = null) + { + $this->traitUsageGenerator->addUse($use, $useAlias); + return $this; + } + /** * Returns the "use" classes * @@ -532,7 +674,7 @@ class ClassGenerator extends AbstractGenerator */ public function getUses() { - return array_values($this->uses); + return $this->traitUsageGenerator->getUses(); } /** @@ -585,8 +727,9 @@ class ClassGenerator extends AbstractGenerator ) { if (!is_string($name)) { throw new Exception\InvalidArgumentException(sprintf( - '%s expects string for name', - __METHOD__ + '%s::%s expects string for name', + get_class($this), + __FUNCTION__ )); } @@ -654,6 +797,92 @@ class ClassGenerator extends AbstractGenerator return isset($this->methods[strtolower($methodName)]); } + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTrait($trait) + { + $this->traitUsageGenerator->addTrait($trait); + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTraits(array $traits) + { + $this->traitUsageGenerator->addTraits($traits); + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function hasTrait($traitName) + { + return $this->traitUsageGenerator->hasTrait($traitName); + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getTraits() + { + return $this->traitUsageGenerator->getTraits(); + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function removeTrait($traitName) + { + return $this->traitUsageGenerator->removeTrait($traitName); + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTraitAlias($method, $alias, $visibility = null) + { + $this->traitUsageGenerator->addTraitAlias($method, $alias, $visibility); + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getTraitAliases() + { + return $this->traitUsageGenerator->getTraitAliases(); + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTraitOverride($method, $traitsToReplace) + { + $this->traitUsageGenerator->addTraitOverride($method, $traitsToReplace); + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function removeTraitOverride($method, $overridesToRemove = null) + { + $this->traitUsageGenerator->removeTraitOverride($method, $overridesToRemove); + + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getTraitOverrides() + { + return $this->traitUsageGenerator->getTraitOverrides(); + } + /** * @return bool */ @@ -679,7 +908,7 @@ class ClassGenerator extends AbstractGenerator } /** - * @return string + * @inherit Zend\Code\Generator\GeneratorInterface */ public function generate() { @@ -690,6 +919,7 @@ class ClassGenerator extends AbstractGenerator } } + $indent = $this->getIndentation(); $output = ''; if (null !== ($namespace = $this->getNamespaceName())) { @@ -697,10 +927,12 @@ class ClassGenerator extends AbstractGenerator } $uses = $this->getUses(); + if (!empty($uses)) { foreach ($uses as $use) { $output .= 'use ' . $use . ';' . self::LINE_FEED; } + $output .= self::LINE_FEED; } @@ -713,31 +945,37 @@ class ClassGenerator extends AbstractGenerator $output .= 'abstract '; } - $output .= 'class ' . $this->getName(); + $output .= static::OBJECT_TYPE . ' ' . $this->getName(); if (!empty($this->extendedClass)) { $output .= ' extends ' . $this->extendedClass; } $implemented = $this->getImplementedInterfaces(); + if (!empty($implemented)) { $output .= ' implements ' . implode(', ', $implemented); } $output .= self::LINE_FEED . '{' . self::LINE_FEED . self::LINE_FEED; + $output .= $this->traitUsageGenerator->generate(); + + $constants = $this->getConstants(); + + foreach ($constants as $constant) { + $output .= $constant->generate() . self::LINE_FEED . self::LINE_FEED; + } $properties = $this->getProperties(); - if (!empty($properties)) { - foreach ($properties as $property) { - $output .= $property->generate() . self::LINE_FEED . self::LINE_FEED; - } + + foreach ($properties as $property) { + $output .= $property->generate() . self::LINE_FEED . self::LINE_FEED; } $methods = $this->getMethods(); - if (!empty($methods)) { - foreach ($methods as $method) { - $output .= $method->generate() . self::LINE_FEED; - } + + foreach ($methods as $method) { + $output .= $method->generate() . self::LINE_FEED; } $output .= self::LINE_FEED . '}' . self::LINE_FEED; diff --git a/library/Zend/Code/Generator/FileGenerator.php b/library/Zend/Code/Generator/FileGenerator.php index 27d6b4540..3b531d646 100644 --- a/library/Zend/Code/Generator/FileGenerator.php +++ b/library/Zend/Code/Generator/FileGenerator.php @@ -152,7 +152,7 @@ class FileGenerator extends AbstractGenerator } /** - * @param DocBlockGenerator|string $docBlock + * @param DocBlockGenerator|array|string $docBlock * @throws Exception\InvalidArgumentException * @return FileGenerator */ diff --git a/library/Zend/Code/Generator/MethodGenerator.php b/library/Zend/Code/Generator/MethodGenerator.php index 24f67ead8..1f405dbc1 100644 --- a/library/Zend/Code/Generator/MethodGenerator.php +++ b/library/Zend/Code/Generator/MethodGenerator.php @@ -61,11 +61,40 @@ class MethodGenerator extends AbstractMemberGenerator $method->setParameter(ParameterGenerator::fromReflection($reflectionParameter)); } - $method->setBody($reflectionMethod->getBody()); + $method->setBody(static::clearBodyIndention($reflectionMethod->getBody())); return $method; } + /** + * Identify the space indention from the first line and remove this indention + * from all lines + * + * @param string $body + * + * @return string + */ + protected static function clearBodyIndention($body) + { + if (empty($body)) { + return $body; + } + + $lines = explode(PHP_EOL, $body); + + $indention = str_replace(trim($lines[1]), '', $lines[1]); + + foreach ($lines as $key => $line) { + if (substr($line, 0, strlen($indention)) == $indention) { + $lines[$key] = substr($line, strlen($indention)); + } + } + + $body = implode(PHP_EOL, $lines); + + return $body; + } + /** * Generate from array * @@ -171,7 +200,7 @@ class MethodGenerator extends AbstractMemberGenerator } /** - * @param ParameterGenerator|string $parameter + * @param ParameterGenerator|array|string $parameter * @throws Exception\InvalidArgumentException * @return MethodGenerator */ @@ -179,7 +208,13 @@ class MethodGenerator extends AbstractMemberGenerator { if (is_string($parameter)) { $parameter = new ParameterGenerator($parameter); - } elseif (!$parameter instanceof ParameterGenerator) { + } + + if (is_array($parameter)) { + $parameter = ParameterGenerator::fromArray($parameter); + } + + if (!$parameter instanceof ParameterGenerator) { throw new Exception\InvalidArgumentException(sprintf( '%s is expecting either a string, array or an instance of %s\ParameterGenerator', __METHOD__, @@ -187,9 +222,7 @@ class MethodGenerator extends AbstractMemberGenerator )); } - $parameterName = $parameter->getName(); - - $this->parameters[$parameterName] = $parameter; + $this->parameters[$parameter->getName()] = $parameter; return $this; } diff --git a/library/Zend/Code/Generator/TraitGenerator.php b/library/Zend/Code/Generator/TraitGenerator.php new file mode 100644 index 000000000..4bc28720e --- /dev/null +++ b/library/Zend/Code/Generator/TraitGenerator.php @@ -0,0 +1,173 @@ +getName()); + + $cg->setSourceContent($cg->getSourceContent()); + $cg->setSourceDirty(false); + + if ($classReflection->getDocComment() != '') { + $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); + } + + // set the namespace + if ($classReflection->inNamespace()) { + $cg->setNamespaceName($classReflection->getNamespaceName()); + } + + $properties = array(); + foreach ($classReflection->getProperties() as $reflectionProperty) { + if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) { + $properties[] = PropertyGenerator::fromReflection($reflectionProperty); + } + } + $cg->addProperties($properties); + + $methods = array(); + foreach ($classReflection->getMethods() as $reflectionMethod) { + $className = ($cg->getNamespaceName()) + ? $cg->getNamespaceName() . '\\' . $cg->getName() + : $cg->getName(); + if ($reflectionMethod->getDeclaringClass()->getName() == $className) { + $methods[] = MethodGenerator::fromReflection($reflectionMethod); + } + } + $cg->addMethods($methods); + + return $cg; + } + + /** + * Generate from array + * + * @configkey name string [required] Class Name + * @configkey filegenerator FileGenerator File generator that holds this class + * @configkey namespacename string The namespace for this class + * @configkey docblock string The docblock information + * @configkey properties + * @configkey methods + * + * @throws Exception\InvalidArgumentException + * @param array $array + * @return TraitGenerator + */ + public static function fromArray(array $array) + { + if (! isset($array['name'])) { + throw new Exception\InvalidArgumentException( + 'Class generator requires that a name is provided for this object' + ); + } + + $cg = new static($array['name']); + foreach ($array as $name => $value) { + // normalize key + switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) { + case 'containingfile': + $cg->setContainingFileGenerator($value); + break; + case 'namespacename': + $cg->setNamespaceName($value); + break; + case 'docblock': + $docBlock = ($value instanceof DocBlockGenerator) ? $value : DocBlockGenerator::fromArray($value); + $cg->setDocBlock($docBlock); + break; + case 'properties': + $cg->addProperties($value); + break; + case 'methods': + $cg->addMethods($value); + break; + } + } + + return $cg; + } + + /** + * @param array|string $flags + * @return self + */ + public function setFlags($flags) + { + return $this; + } + + /** + * @param string $flag + * @return self + */ + public function addFlag($flag) + { + return $this; + } + + /** + * @param string $flag + * @return self + */ + public function removeFlag($flag) + { + return $this; + } + + /** + * @param bool $isFinal + * @return self + */ + public function setFinal($isFinal) + { + return $this; + } + + /** + * @param string $extendedClass + * @return self + */ + public function setExtendedClass($extendedClass) + { + return $this; + } + + /** + * @param array $implementedInterfaces + * @return self + */ + public function setImplementedInterfaces(array $implementedInterfaces) + { + return $this; + } + + /** + * @param bool $isAbstract + * @return self + */ + public function setAbstract($isAbstract) + { + return $this; + } +} diff --git a/library/Zend/Code/Generator/TraitUsageGenerator.php b/library/Zend/Code/Generator/TraitUsageGenerator.php new file mode 100644 index 000000000..0cd2b582c --- /dev/null +++ b/library/Zend/Code/Generator/TraitUsageGenerator.php @@ -0,0 +1,353 @@ +classGenerator = $classGenerator; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addUse($use, $useAlias = null) + { + if (! empty($useAlias)) { + $use .= ' as ' . $useAlias; + } + + $this->uses[$use] = $use; + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getUses() + { + return array_values($this->uses); + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTrait($trait) + { + $traitName = $trait; + if (is_array($trait)) { + if (! array_key_exists('traitName', $trait)) { + throw new Exception\InvalidArgumentException('Missing required value for traitName'); + } + $traitName = $trait['traitName']; + + if (array_key_exists('aliases', $trait)) { + foreach ($trait['aliases'] as $alias) { + $this->addAlias($alias); + } + } + + if (array_key_exists('insteadof', $trait)) { + foreach ($trait['insteadof'] as $insteadof) { + $this->addTraitOverride($insteadof); + } + } + } + + if (! $this->hasTrait($traitName)) { + $this->traits[] = $traitName; + } + + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTraits(array $traits) + { + foreach ($traits as $trait) { + $this->addTrait($trait); + } + + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function hasTrait($traitName) + { + return in_array($traitName, $this->traits); + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getTraits() + { + return $this->traits; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function removeTrait($traitName) + { + $key = array_search($traitName, $this->traits); + if (false !== $key) { + unset($this->traits[$key]); + } + + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTraitAlias($method, $alias, $visibility = null) + { + $traitAndMethod = $method; + if (is_array($method)) { + if (! array_key_exists('traitName', $method)) { + throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method'); + } + + if (! array_key_exists('method', $method)) { + throw new Exception\InvalidArgumentException('Missing required argument "method" for $method'); + } + + $traitAndMethod = $method['traitName'] . '::' . $method['method']; + } + + // Validations + if (false === strpos($traitAndMethod, "::")) { + throw new Exception\InvalidArgumentException( + 'Invalid Format: $method must be in the format of trait::method' + ); + } + if (! is_string($alias)) { + throw new Exception\InvalidArgumentException('Invalid Alias: $alias must be a string or array.'); + } + if ($this->classGenerator->hasMethod($alias)) { + throw new Exception\InvalidArgumentException('Invalid Alias: Method name already exists on this class.'); + } + if (null !== $visibility + && $visibility !== ReflectionMethod::IS_PUBLIC + && $visibility !== ReflectionMethod::IS_PRIVATE + && $visibility !== ReflectionMethod::IS_PROTECTED + ) { + throw new Exception\InvalidArgumentException( + 'Invalid Type: $visibility must of ReflectionMethod::IS_PUBLIC,' + . ' ReflectionMethod::IS_PRIVATE or ReflectionMethod::IS_PROTECTED' + ); + } + + list($trait, $method) = explode('::', $traitAndMethod); + if (! $this->hasTrait($trait)) { + throw new Exception\InvalidArgumentException('Invalid trait: Trait does not exists on this class'); + } + + $this->traitAliases[$traitAndMethod] = array( + 'alias' => $alias, + 'visibility' => $visibility + ); + + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getTraitAliases() + { + return $this->traitAliases; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function addTraitOverride($method, $traitsToReplace) + { + if (false === is_array($traitsToReplace)) { + $traitsToReplace = array($traitsToReplace); + } + + $traitAndMethod = $method; + if (is_array($method)) { + if (! array_key_exists('traitName', $method)) { + throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method'); + } + + if (! array_key_exists('method', $method)) { + throw new Exception\InvalidArgumentException('Missing required argument "method" for $method'); + } + + $traitAndMethod = (string) $method['traitName'] . '::' . (string) $method['method']; + } + + // Validations + if (false === strpos($traitAndMethod, "::")) { + throw new Exception\InvalidArgumentException( + 'Invalid Format: $method must be in the format of trait::method' + ); + } + + list($trait, $method) = explode("::", $traitAndMethod); + if (! $this->hasTrait($trait)) { + throw new Exception\InvalidArgumentException('Invalid trait: Trait does not exists on this class'); + } + + if (! array_key_exists($traitAndMethod, $this->traitOverrides)) { + $this->traitOverrides[$traitAndMethod] = array(); + } + + foreach ($traitsToReplace as $traitToReplace) { + if (! is_string($traitToReplace)) { + throw new Exception\InvalidArgumentException( + 'Invalid Argument: $traitToReplace must be a string or array of strings' + ); + } + + if (! in_array($traitToReplace, $this->traitOverrides[$traitAndMethod])) { + $this->traitOverrides[$traitAndMethod][] = $traitToReplace; + } + } + + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function removeTraitOverride($method, $overridesToRemove = null) + { + if (! array_key_exists($method, $this->traitOverrides)) { + return $this; + } + + if (null === $overridesToRemove) { + unset($this->traitOverrides[$method]); + return $this; + } + + $overridesToRemove = (! is_array($overridesToRemove)) + ? array($overridesToRemove) + : $overridesToRemove; + foreach ($overridesToRemove as $traitToRemove) { + $key = array_search($traitToRemove, $this->traitOverrides[$method]); + if (false !== $key) { + unset($this->traitOverrides[$method][$key]); + } + } + return $this; + } + + /** + * @inherit Zend\Code\Generator\TraitUsageInterface + */ + public function getTraitOverrides() + { + return $this->traitOverrides; + } + + /** + * @inherit Zend\Code\Generator\GeneratorInterface + */ + public function generate() + { + $output = ''; + $indent = $this->getIndentation(); + $traits = $this->getTraits(); + + if (empty($traits)) { + return $output; + } + + $output .= $indent . 'use ' . implode(', ', $traits); + + $aliases = $this->getTraitAliases(); + $overrides = $this->getTraitOverrides(); + if (empty($aliases) && empty($overrides)) { + $output .= ";" . self::LINE_FEED . self::LINE_FEED; + return $output; + } + + $output .= ' {' . self::LINE_FEED; + foreach ($aliases as $method => $alias) { + $visibility = (null !== $alias['visibility']) + ? current(Reflection::getModifierNames($alias['visibility'])) . ' ' + : ''; + + // validation check + if ($this->classGenerator->hasMethod($alias['alias'])) { + throw new Exception\RuntimeException(sprintf( + 'Generation Error: Aliased method %s already exists on this class', + $alias['alias'] + )); + } + + $output .= + $indent + . $indent + . $method + . ' as ' + . $visibility + . $alias['alias'] + . ';' + . self::LINE_FEED; + } + + foreach ($overrides as $method => $insteadofTraits) { + foreach ($insteadofTraits as $insteadofTrait) { + $output .= + $indent + . $indent + . $method + . ' insteadof ' + . $insteadofTrait + . ';' + . self::LINE_FEED; + } + } + + $output .= self::LINE_FEED . $indent . '}' . self::LINE_FEED . self::LINE_FEED; + + return $output; + } +} diff --git a/library/Zend/Code/Generator/TraitUsageInterface.php b/library/Zend/Code/Generator/TraitUsageInterface.php new file mode 100644 index 000000000..e5c0bda7c --- /dev/null +++ b/library/Zend/Code/Generator/TraitUsageInterface.php @@ -0,0 +1,159 @@ +:: + * Option 2: Array + * key: traitName value: trait name + * key: method value: method name + * + * $traitToReplace: + * The name of the trait that you wish to supersede. + * + * This method provides 2 ways for defining the trait method. + * Option 1: String of trait to replace + * Option 2: Array of strings of traits to replace + + * @param mixed $method + * @param mixed $traitToReplace + */ + public function addTraitOverride($method, $traitsToReplace); + + /** + * Remove an override for a given trait::method + * + * $method: + * This method provides 2 ways for defining the trait method. + * Option 1: String Format: :: + * Option 2: Array + * key: traitName value: trait name + * key: method value: method name + * + * $overridesToRemove: + * The name of the trait that you wish to remove. + * + * This method provides 2 ways for defining the trait method. + * Option 1: String of trait to replace + * Option 2: Array of strings of traits to replace + * + * @param $traitAndMethod + * @param null $overridesToRemove + * @return $this + */ + public function removeTraitOverride($method, $overridesToRemove = null); + + /** + * Return trait overrides + * + * @return array + */ + public function getTraitOverrides(); +} diff --git a/library/Zend/Code/Generator/ValueGenerator.php b/library/Zend/Code/Generator/ValueGenerator.php index d67402342..50da86516 100644 --- a/library/Zend/Code/Generator/ValueGenerator.php +++ b/library/Zend/Code/Generator/ValueGenerator.php @@ -374,6 +374,9 @@ class ValueGenerator extends AbstractGenerator : ' '; $output .= implode(',' . $padding, $outputParts); if ($this->outputMode == self::OUTPUT_MULTIPLE_LINE) { + if (count($outputParts) > 0) { + $output .= ','; + } $output .= self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth); } $output .= ')'; diff --git a/library/Zend/Code/Reflection/ClassReflection.php b/library/Zend/Code/Reflection/ClassReflection.php index 2d7b4ae72..13801c2fb 100644 --- a/library/Zend/Code/Reflection/ClassReflection.php +++ b/library/Zend/Code/Reflection/ClassReflection.php @@ -177,6 +177,21 @@ class ClassReflection extends ReflectionClass implements ReflectionInterface return $methods; } + public function getTraits() + { + $vals = array(); + $traits = parent::getTraits(); + if (! $traits) { + return; + } + + foreach ($traits as $trait) { + $vals[] = new ClassReflection($trait->getName()); + } + + return $vals; + } + /** * Get parent reflection class of reflected class * @@ -230,11 +245,17 @@ class ClassReflection extends ReflectionClass implements ReflectionInterface return $zendReflections; } + /** + * @return string + */ public function toString() { return parent::__toString(); } + /** + * @return string + */ public function __toString() { return parent::__toString(); diff --git a/library/Zend/Code/Reflection/DocBlock/Tag/MethodTag.php b/library/Zend/Code/Reflection/DocBlock/Tag/MethodTag.php index 7e80861e4..86d409cee 100644 --- a/library/Zend/Code/Reflection/DocBlock/Tag/MethodTag.php +++ b/library/Zend/Code/Reflection/DocBlock/Tag/MethodTag.php @@ -80,7 +80,7 @@ class MethodTag implements TagInterface, PhpDocTypedTagInterface public function getReturnType() { if (empty($this->types)) { - return null; + return; } return $this->types[0]; diff --git a/library/Zend/Code/Reflection/DocBlock/Tag/PropertyTag.php b/library/Zend/Code/Reflection/DocBlock/Tag/PropertyTag.php index 9f5b4b92d..d8b3435ce 100644 --- a/library/Zend/Code/Reflection/DocBlock/Tag/PropertyTag.php +++ b/library/Zend/Code/Reflection/DocBlock/Tag/PropertyTag.php @@ -66,7 +66,7 @@ class PropertyTag implements TagInterface, PhpDocTypedTagInterface public function getType() { if (empty($this->types)) { - return null; + return; } return $this->types[0]; diff --git a/library/Zend/Code/Reflection/DocBlockReflection.php b/library/Zend/Code/Reflection/DocBlockReflection.php index c43db8ddf..a898ca84e 100644 --- a/library/Zend/Code/Reflection/DocBlockReflection.php +++ b/library/Zend/Code/Reflection/DocBlockReflection.php @@ -247,7 +247,7 @@ class DocBlockReflection implements ReflectionInterface return; } - $docComment = $this->docComment; // localize variable + $docComment = preg_replace('#[ ]{0,1}\*/$#', '', $this->docComment); // create a clean docComment $this->cleanDocComment = preg_replace("#[ \t]*(?:/\*\*|\*/|\*)[ ]{0,1}(.*)?#", '$1', $docComment); @@ -264,6 +264,9 @@ class DocBlockReflection implements ReflectionInterface $this->isReflected = true; } + /** + * @return string + */ public function toString() { $str = "DocBlock [ /* DocBlock */ ] {" . PHP_EOL . PHP_EOL; diff --git a/library/Zend/Code/Reflection/FileReflection.php b/library/Zend/Code/Reflection/FileReflection.php index d079ba718..1ab3bc5c7 100644 --- a/library/Zend/Code/Reflection/FileReflection.php +++ b/library/Zend/Code/Reflection/FileReflection.php @@ -34,17 +34,17 @@ class FileReflection implements ReflectionInterface protected $endLine = null; /** - * @var string + * @var string[] */ protected $namespaces = array(); /** - * @var array + * @var string[] */ protected $uses = array(); /** - * @var array + * @var string[] */ protected $requiredFiles = array(); @@ -105,7 +105,7 @@ class FileReflection implements ReflectionInterface */ public static function export() { - return null; + return; } /** @@ -115,8 +115,7 @@ class FileReflection implements ReflectionInterface */ public function getFileName() { - // @todo get file name from path - return $this->filePath; + return basename($this->filePath); } /** @@ -162,7 +161,7 @@ class FileReflection implements ReflectionInterface } /** - * @return array + * @return string[] */ public function getNamespaces() { @@ -175,7 +174,7 @@ class FileReflection implements ReflectionInterface public function getNamespace() { if (count($this->namespaces) == 0) { - return null; + return; } return $this->namespaces[0]; diff --git a/library/Zend/Code/Reflection/FunctionReflection.php b/library/Zend/Code/Reflection/FunctionReflection.php index aed8d5847..b7bb42354 100644 --- a/library/Zend/Code/Reflection/FunctionReflection.php +++ b/library/Zend/Code/Reflection/FunctionReflection.php @@ -203,7 +203,7 @@ class FunctionReflection extends ReflectionFunction implements ReflectionInterfa /** * Get method body * - * @return string|bool + * @return string|false */ public function getBody() { @@ -249,6 +249,9 @@ class FunctionReflection extends ReflectionFunction implements ReflectionInterfa return $body; } + /** + * @return string + */ public function toString() { return $this->__toString(); diff --git a/library/Zend/Code/Reflection/MethodReflection.php b/library/Zend/Code/Reflection/MethodReflection.php index 051d59a4e..514505eaf 100644 --- a/library/Zend/Code/Reflection/MethodReflection.php +++ b/library/Zend/Code/Reflection/MethodReflection.php @@ -184,7 +184,7 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac * Get method contents * * @param bool $includeDocBlock - * @return string|bool + * @return string */ public function getContents($includeDocBlock = true) { @@ -198,7 +198,7 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac /** * Get method body * - * @return string|bool + * @return string */ public function getBody() { @@ -213,7 +213,7 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac */ protected function extractMethodContents($bodyOnly = false) { - $fileName = $this->getDeclaringClass()->getFileName(); + $fileName = $this->getFileName(); if ((class_exists($this->class) && false === $fileName) || ! file_exists($fileName)) { return ''; @@ -331,8 +331,8 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac /** * Take current position and find any whitespace * - * @param $haystack - * @param $position + * @param array $haystack + * @param int $position * @return string */ protected function extractPrefixedWhitespace($haystack, $position) @@ -361,8 +361,8 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac /** * Test for ending brace * - * @param $haystack - * @param $position + * @param array $haystack + * @param int $position * @return bool */ protected function isEndingBrace($haystack, $position) @@ -430,8 +430,9 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac * Test to see if current position is valid function or * closure. Returns true if it's a function and NOT a closure * - * @param $haystack - * @param $position + * @param array $haystack + * @param int $position + * @param string $functionName * @return bool */ protected function isValidFunction($haystack, $position, $functionName = null) @@ -460,11 +461,17 @@ class MethodReflection extends PhpReflectionMethod implements ReflectionInterfac return $isValid; } + /** + * @return string + */ public function toString() { return parent::__toString(); } + /** + * @return string + */ public function __toString() { return parent::__toString(); diff --git a/library/Zend/Code/Reflection/ParameterReflection.php b/library/Zend/Code/Reflection/ParameterReflection.php index 77e72c057..17153f504 100644 --- a/library/Zend/Code/Reflection/ParameterReflection.php +++ b/library/Zend/Code/Reflection/ParameterReflection.php @@ -41,7 +41,7 @@ class ParameterReflection extends ReflectionParameter implements ReflectionInter { $phpReflection = parent::getClass(); if ($phpReflection == null) { - return null; + return; } $zendReflection = new ClassReflection($phpReflection->getName()); @@ -87,7 +87,7 @@ class ParameterReflection extends ReflectionParameter implements ReflectionInter $docBlock = $this->getDeclaringFunction()->getDocBlock(); if (!$docBlock instanceof DocBlockReflection) { - return null; + return; } $params = $docBlock->getTags('param'); @@ -95,14 +95,20 @@ class ParameterReflection extends ReflectionParameter implements ReflectionInter return $params[$this->getPosition()]->getType(); } - return null; + return; } + /** + * @return string + */ public function toString() { return parent::__toString(); } + /** + * @return string + */ public function __toString() { return parent::__toString(); diff --git a/library/Zend/Code/Reflection/PropertyReflection.php b/library/Zend/Code/Reflection/PropertyReflection.php index 8d9ce4975..d5d5a1bcd 100644 --- a/library/Zend/Code/Reflection/PropertyReflection.php +++ b/library/Zend/Code/Reflection/PropertyReflection.php @@ -89,6 +89,9 @@ class PropertyReflection extends PhpReflectionProperty implements ReflectionInte return $this->annotations; } + /** + * @return string + */ public function toString() { return $this->__toString(); diff --git a/library/Zend/Code/Scanner/AnnotationScanner.php b/library/Zend/Code/Scanner/AnnotationScanner.php index 5410c0256..7fb8e6397 100644 --- a/library/Zend/Code/Scanner/AnnotationScanner.php +++ b/library/Zend/Code/Scanner/AnnotationScanner.php @@ -160,7 +160,7 @@ class AnnotationScanner extends AnnotationCollection implements ScannerInterface } $currentChar = $stream[$streamIndex]; $matches = array(); - $currentLine = (preg_match('#(.*)\n#', $stream, $matches, null, $streamIndex) === 1) ? $matches[1] : substr($stream, $streamIndex); + $currentLine = (preg_match('#(.*?)(?:\n|\r\n?)#', $stream, $matches, null, $streamIndex) === 1) ? $matches[1] : substr($stream, $streamIndex); if ($currentChar === ' ') { $currentWord = (preg_match('#( +)#', $currentLine, $matches) === 1) ? $matches[1] : $currentLine; } else { @@ -213,7 +213,7 @@ class AnnotationScanner extends AnnotationCollection implements ScannerInterface } if ($MACRO_HAS_CONTEXT($CONTEXT_CLASS)) { - if (in_array($currentChar, array(' ', '(', "\n"))) { + if (in_array($currentChar, array(' ', '(', "\n", "\r"))) { $context &= ~$CONTEXT_CLASS; $MACRO_TOKEN_ADVANCE(); } else { @@ -225,7 +225,22 @@ class AnnotationScanner extends AnnotationCollection implements ScannerInterface } } - if ($currentChar === "\n") { + // Since we don't know what line endings are used in the file, we check for all scenarios. If we find a + // cariage return (\r), we check the next character for a line feed (\n). If so we consume it and act as + // if the cariage return was a line feed. + $lineEnded = $currentChar === "\n"; + if ($currentChar === "\r") { + $lineEnded = true; + + $nextChar = $MACRO_STREAM_ADVANCE_CHAR(); + if ($nextChar !== "\n") { + $streamIndex--; + } + + $currentChar = "\n"; + } + + if ($lineEnded) { $MACRO_TOKEN_SET_TYPE('ANNOTATION_NEWLINE'); $MACRO_TOKEN_APPEND_CHAR(); $MACRO_TOKEN_ADVANCE(); diff --git a/library/Zend/Code/Scanner/ClassScanner.php b/library/Zend/Code/Scanner/ClassScanner.php index 8680c4948..86b7438b2 100644 --- a/library/Zend/Code/Scanner/ClassScanner.php +++ b/library/Zend/Code/Scanner/ClassScanner.php @@ -9,6 +9,7 @@ namespace Zend\Code\Scanner; +use ReflectionClass; use Zend\Code\Annotation; use Zend\Code\Exception; use Zend\Code\NameInformation; @@ -45,6 +46,11 @@ class ClassScanner implements ScannerInterface */ protected $lineEnd = null; + /** + * @var bool + */ + protected $isTrait = false; + /** * @var bool */ @@ -95,6 +101,16 @@ class ClassScanner implements ScannerInterface */ protected $infos = array(); + /** + * @var array + */ + protected $traits = array(); + + /** + * @var array + */ + protected $methods = array(); + /** * @param array $classTokens * @param NameInformation|null $nameInformation @@ -202,6 +218,16 @@ class ClassScanner implements ScannerInterface return $this->isFinal; } + /** + * Verify if class is a trait + * @return bool + */ + public function isTrait() + { + $this->scan(); + return $this->isTrait; + } + /** * Verify if class is instantiable * @@ -344,7 +370,9 @@ class ClassScanner implements ScannerInterface return false; } } else { - throw new Exception\InvalidArgumentException('Invalid constant name of info index type. Must be of type int or string'); + throw new Exception\InvalidArgumentException( + 'Invalid constant name of info index type. Must be of type int or string' + ); } if (!isset($info)) { return false; @@ -447,7 +475,9 @@ class ClassScanner implements ScannerInterface return false; } } else { - throw new Exception\InvalidArgumentException('Invalid property name of info index type. Must be of type int or string'); + throw new Exception\InvalidArgumentException( + 'Invalid property name of info index type. Must be of type int or string' + ); } if (!isset($info)) { return false; @@ -480,6 +510,170 @@ class ClassScanner implements ScannerInterface return false; } + /** + * Retrieve any traits used by the class. + * + * @return ClassScanner[] + */ + public function getTraits() + { + if (! empty($this->traits)) { + return $this->traits; + } + + // get list of trait names + $traitNames = $this->getTraitNames(); + foreach ($traitNames as $traitName) { + $r = new ReflectionClass($traitName); + if (! $r->isTrait()) { + throw new Exception\RuntimeException(sprintf( + 'Non-trait class detected as a trait: %s', + $traitName + )); + } + $fileName = $r->getFileName(); + + $file = new FileScanner($fileName); + $this->traits[] = $file->getClass($traitName); + } + + return $this->traits; + } + + /** + * Retrieve a list of trait names used by this class. + * + * @return array + */ + public function getTraitNames() + { + $return = array(); + foreach ($this->infos as $info) { + if ($info['type'] !== 'use') { + continue; + } + + if (is_array($info['use_statements'])) { + foreach ($info['use_statements'] as $trait) { + $traitName = $trait; + if ($this->nameInformation instanceof NameInformation) { + $traitName = $this->nameInformation->resolveName($traitName); + } + $return[] = $traitName; + } + } + break; + } + + return $return; + } + + /** + * Retrieve a list of aliased traits used by the class. + * + * @return array + */ + public function getTraitAliases() + { + $return = array(); + foreach ($this->infos as $info) { + if ($info['type'] !== 'use') { + continue; + } + + if (is_array($info['aliases'])) { + foreach ($info['aliases'] as $alias) { + if (null === $alias + || (! empty($alias['type']) && $alias['type'] !== 'as') + ) { + continue; + } + + // attempt to get fqcn + list($trait, $method) = explode('::', $alias['original']); + if ($this->nameInformation instanceof NameInformation) { + $trait = $this->nameInformation->resolveName($trait); + } + + $return[$alias['alias']] = $trait . '::' . $method; + } + } + break; + } + + return $return; + } + + /** + * Retrieve visibility for a given alias. + * + * @param mixed $aliasName + * @return string + */ + protected function getVisibilityForAlias($aliasName) + { + $return = null; + foreach ($this->infos as $info) { + if ($info['type'] !== 'use') { + continue; + } + + if (is_array($info['aliases'])) { + foreach ($info['aliases'] as $alias) { + if (null === $alias + && (! empty($alias['type']) && $alias['type'] !== 'as') + ) { + continue; + } + + if ($alias['alias'] === $aliasName) { + $return = $alias['visibility']; + break 2; + } + } + } + break; + } + + return $return; + } + + /** + * Return an array of key = trait to keep, value = trait::method to ignore + * + * @return array + */ + protected function getBlockedTraitMethods() + { + $return = array(); + foreach ($this->infos as $info) { + if ($info['type'] !== 'use') { + continue; + } + + if (is_array($info['aliases'])) { + foreach ($info['aliases'] as $alias) { + if (null === $alias + || (! empty($alias['type']) && $alias['type'] !== 'insteadof') + ) { + continue; + } + + // attempt to get fqcn + list($trait, $method) = explode('::', $alias['original']); + if ($this->nameInformation instanceof NameInformation) { + $trait = $this->nameInformation->resolveName($alias['alias']); + } + + $return[] = $trait . '::' . $method; + } + } + break; + } + + return $return; + } + /** * Return a list of method names * @@ -489,13 +683,10 @@ class ClassScanner implements ScannerInterface { $this->scan(); + $methods = $this->getMethods(); $return = array(); - foreach ($this->infos as $info) { - if ($info['type'] != 'method') { - continue; - } - - $return[] = $info['name']; + foreach ($methods as $method) { + $return[] = $method->getName(); } return $return; @@ -510,16 +701,82 @@ class ClassScanner implements ScannerInterface { $this->scan(); - $return = array(); + if (! empty($this->methods)) { + return $this->methods; + } + foreach ($this->infos as $info) { - if ($info['type'] != 'method') { + if ($info['type'] !== 'method' && $info['type'] !== 'use') { continue; } - $return[] = $this->getMethod($info['name']); + // Merge in trait methods + if ($info['type'] === "use") { + $traitMethods = array(); + $traits = $this->getTraits(); + $insteadof = $this->getBlockedTraitMethods(); + $aliases = $this->getTraitAliases(); + + foreach ($traits as $trait) { + $tempMethods = $trait->getMethods(); + foreach ($tempMethods as $tempMethod) { + $methodFullName = $trait->getName() . '::' . $tempMethod->getName(); + $methodAlias = array_search($methodFullName, $aliases); + + if (false !== $methodAlias) { + // trait::method is aliased + // clone the tempMethod as we need to change + // the name and possibly the visibility of the + // scanned method. + // + // @todo setName and setVisibility were added to + // MethodScanner to accomplish this, may not be the + // best option, could use ReflectionClass instead? + $newMethod = clone $tempMethod; + $newMethod->setName($methodAlias); + + // if visibility exists, change it on the MethodScanner + $visibility = $this->getVisibilityForAlias($methodAlias); + if (null !== $visibility) { + $newMethod->setVisibility($visibility); + } + $traitMethods[$methodAlias] = $newMethod; + } elseif (in_array($methodFullName, $insteadof)) { + // ignore overridden methods + continue; + } else { + if (array_key_exists($tempMethod->getName(), $traitMethods)) { + throw new Exception\RuntimeException(sprintf( + 'Trait method %s has not been applied because there are' + . ' collisions with other trait methods see: (insteadof OR as)', + $tempMethod->getName() + )); + } + + $traitMethods[$tempMethod->getName()] = $tempMethod; + } + } + } + + $this->methods = array_merge($this->methods, array_values($traitMethods)); + continue; + } + + $m = new MethodScanner( + array_slice( + $this->tokens, + $info['tokenStart'], + $info['tokenEnd'] - $info['tokenStart'] + 1 + ), + $this->nameInformation + ); + $m->setClass($this->name); + $m->setScannerClass($this); + + $this->methods[] = $m; } - return $return; + return $this->methods; } /** @@ -538,31 +795,19 @@ class ClassScanner implements ScannerInterface if ($info['type'] != 'method') { throw new Exception\InvalidArgumentException('Index of info offset is not about a method'); } - } elseif (is_string($methodNameOrInfoIndex)) { - $methodFound = false; - foreach ($this->infos as $info) { - if ($info['type'] === 'method' && $info['name'] === $methodNameOrInfoIndex) { - $methodFound = true; - break; - } - } - if (!$methodFound) { - return false; - } - } - if (!isset($info)) { - // @todo find a way to test this - die('Massive Failure, test this'); + $methodNameOrInfoIndex = $info['name']; } - $m = new MethodScanner( - array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1), - $this->nameInformation - ); - $m->setClass($this->name); - $m->setScannerClass($this); + $returnMethod = false; + $methods = $this->getMethods(); + foreach ($methods as $method) { + if ($method->getName() === $methodNameOrInfoIndex) { + $returnMethod = $method; + break; + } + } - return $m; + return $returnMethod; } /** @@ -575,13 +820,7 @@ class ClassScanner implements ScannerInterface { $this->scan(); - foreach ($this->infos as $info) { - if ($info['type'] === 'method' && $info['name'] === $name) { - return true; - } - } - - return false; + return is_object($this->getMethod($name)); } public static function export() @@ -628,7 +867,14 @@ class ClassScanner implements ScannerInterface /* * MACRO creation */ - $MACRO_TOKEN_ADVANCE = function () use (&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) { + $MACRO_TOKEN_ADVANCE = function () use ( + &$tokens, + &$tokenIndex, + &$token, + &$tokenType, + &$tokenContent, + &$tokenLine + ) { static $lastTokenArray = null; $tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1; if (!isset($tokens[$tokenIndex])) { @@ -684,6 +930,7 @@ class ClassScanner implements ScannerInterface case T_ABSTRACT: case T_CLASS: case T_INTERFACE: + case T_TRAIT: // CLASS INFORMATION @@ -703,12 +950,22 @@ class ClassScanner implements ScannerInterface case T_FINAL: $this->isFinal = true; goto SCANNER_CLASS_INFO_CONTINUE; - //goto no break needed + // goto no break needed case T_ABSTRACT: $this->isAbstract = true; goto SCANNER_CLASS_INFO_CONTINUE; - //goto no break needed + // goto no break needed + + case T_TRAIT: + $this->isTrait = true; + $this->shortName = $tokens[$tokenIndex + 2][1]; + if ($this->nameInformation && $this->nameInformation->hasNamespace()) { + $this->name = $this->nameInformation->getNamespace() . '\\' . $this->shortName; + } else { + $this->name = $this->shortName; + } + goto SCANNER_CLASS_INFO_CONTINUE; case T_INTERFACE: $this->isInterface = true; @@ -815,7 +1072,121 @@ class ClassScanner implements ScannerInterface $MACRO_INFO_ADVANCE(); goto SCANNER_CLASS_BODY_CONTINUE; - //goto no break needed + // goto no break needed + + case T_USE: + // ensure php backwards compatibility + if (! defined('T_INSTEADOF')) { + define('T_INSTEADOF', 24000); + } + + $infos[$infoIndex] = array( + 'type' => 'use', + 'tokenStart' => $tokenIndex, + 'tokenEnd' => null, + 'lineStart' => $tokens[$tokenIndex][2], + 'lineEnd' => null, + 'name' => $namespace, + 'use_statements' => array(0 => null), + 'aliases' => array(0 => null), + ); + + $isOriginalName = array(T_STRING, T_DOUBLE_COLON); + $isAlias = array(T_STRING); + $isVisibility = array(T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC); + $isAliasType = array(T_AS, T_INSTEADOF); + $isValidAlias = array_merge($isOriginalName, $isAlias, $isVisibility, $isAliasType); + + $useStatementIndex = 0; + $aliasStatementIndex = 0; + $useAliasContext = false; + $useAsContext = false; + + // start processing with next token + if ($MACRO_TOKEN_ADVANCE() === false) { + goto SCANNER_END; + } + + SCANNER_USE_TOP: + + if ($tokenType === null) { + if ($tokenContent === "{") { + $useStatementIndex = 0; + $useAliasContext = true; + $infos[$infoIndex]['aliases'][$useStatementIndex] = array( + 'original' => null, + 'alias' => null, + 'visibility' => null, + 'type' => 'as' + ); + } elseif ($tokenContent === "}") { + $useAliasContext = false; + goto SCANNER_USE_END; + } elseif ($tokenContent === ';') { + if ($useAliasContext === true) { + $useStatementIndex++; + $useAsContext = false; + } + // only end if we aren't inside braces + if (false === $useAliasContext) { + goto SCANNER_USE_END; + } + } elseif ($tokenContent === ',') { + $useStatementIndex++; + $infos[$infoIndex]['use_statements'][$useStatementIndex] = ''; + } + } + + // ANALYZE + if ($tokenType !== null) { + // use context + if (false === $useAliasContext) { + if ($tokenType == T_NS_SEPARATOR || $tokenType == T_STRING) { + $infos[$infoIndex]['use_statements'][$useStatementIndex] .= $tokenContent; + } + } else { + if (in_array($tokenType, $isValidAlias) + && empty($infos[$infoIndex]['aliases'][$useStatementIndex]) + ) { + $infos[$infoIndex]['aliases'][$useStatementIndex] = array( + 'original' => null, + 'visibility' => null, + 'alias' => null, + 'type' => null + ); + } + + if ($tokenType == T_AS || $tokenType == T_INSTEADOF) { + $useAsContext = true; + $infos[$infoIndex]['aliases'][$useStatementIndex]['type'] = ($tokenType == T_INSTEADOF) + ? 'insteadof' + : 'as'; + goto SCANNER_USE_CONTINUE; + } + + // in alias context + if ($useAsContext === true && in_array($tokenType, $isAlias)) { + $infos[$infoIndex]['aliases'][$useStatementIndex]['alias'] = $tokenContent; + } elseif (in_array($tokenType, $isOriginalName)) { + $infos[$infoIndex]['aliases'][$useStatementIndex]['original'] .= $tokenContent; + } elseif (in_array($tokenType, $isVisibility)) { + //add whitespace (will trim later) + $infos[$infoIndex]['aliases'][$useStatementIndex]['visibility'] = $tokenType; + } + } + } + + SCANNER_USE_CONTINUE: + + if ($MACRO_TOKEN_ADVANCE() === false) { + goto SCANNER_END; + } + goto SCANNER_USE_TOP; + + SCANNER_USE_END: + + $MACRO_INFO_ADVANCE(); + goto SCANNER_CLASS_BODY_CONTINUE; case T_DOC_COMMENT: case T_PUBLIC: @@ -846,7 +1217,7 @@ class ClassScanner implements ScannerInterface $methodBodyStarted = true; $braceCount++; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; - //goto no break needed + // goto no break needed case '}': $braceCount--; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; @@ -882,20 +1253,20 @@ class ClassScanner implements ScannerInterface $infos[$infoIndex]['name'] = ltrim($tokenContent, '$'); } goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; - //goto no break needed + // goto no break needed case T_FUNCTION: $memberContext = 'method'; $infos[$infoIndex]['type'] = 'method'; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; - //goto no break needed + // goto no break needed case T_STRING: if ($memberContext === 'method' && null === $infos[$infoIndex]['name']) { $infos[$infoIndex]['name'] = $tokenContent; } goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; - //goto no break needed + // goto no break needed } SCANNER_CLASS_BODY_MEMBER_CONTINUE: @@ -910,7 +1281,7 @@ class ClassScanner implements ScannerInterface $memberContext = null; $MACRO_INFO_ADVANCE(); goto SCANNER_CLASS_BODY_CONTINUE; - //goto no break needed + // goto no break needed case null: // no type, is a string @@ -918,7 +1289,8 @@ class ClassScanner implements ScannerInterface case '{': $braceCount++; goto SCANNER_CLASS_BODY_CONTINUE; - //fall-through + // goto no break needed + case '}': $braceCount--; goto SCANNER_CLASS_BODY_CONTINUE; diff --git a/library/Zend/Code/Scanner/MethodScanner.php b/library/Zend/Code/Scanner/MethodScanner.php index 3724fa471..e2c299f6a 100644 --- a/library/Zend/Code/Scanner/MethodScanner.php +++ b/library/Zend/Code/Scanner/MethodScanner.php @@ -251,6 +251,55 @@ class MethodScanner implements ScannerInterface return $this->isStatic; } + /** + * Override the given name for a method, this is necessary to + * support traits. + * + * @param $name + * @return self + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * Visibility must be of T_PUBLIC, T_PRIVATE or T_PROTECTED + * Needed to support traits + * + * @param $visibility T_PUBLIC | T_PRIVATE | T_PROTECTED + * @return self + * @throws \Zend\Code\Exception + */ + public function setVisibility($visibility) + { + switch (strtolower($visibility)) { + case T_PUBLIC: + $this->isPublic = true; + $this->isPrivate = false; + $this->isProtected = false; + break; + + case T_PRIVATE: + $this->isPublic = false; + $this->isPrivate = true; + $this->isProtected = false; + break; + + case T_PROTECTED: + $this->isPublic = false; + $this->isPrivate = false; + $this->isProtected = true; + break; + + default: + throw new Exception("Invalid visibility argument passed to setVisibility."); + } + + return $this; + } + /** * @return int */ @@ -372,7 +421,14 @@ class MethodScanner implements ScannerInterface /* * MACRO creation */ - $MACRO_TOKEN_ADVANCE = function () use (&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) { + $MACRO_TOKEN_ADVANCE = function () use ( + &$tokens, + &$tokenIndex, + &$token, + &$tokenType, + &$tokenContent, + &$tokenLine + ) { static $lastTokenArray = null; $tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1; if (!isset($tokens[$tokenIndex])) { @@ -452,14 +508,12 @@ class MethodScanner implements ScannerInterface //goto (no break needed); case T_PROTECTED: - $this->isProtected = true; - $this->isPublic = false; + $this->setVisibility(T_PROTECTED); goto SCANNER_CONTINUE_SIGNATURE; //goto (no break needed); case T_PRIVATE: - $this->isPrivate = true; - $this->isPublic = false; + $this->setVisibility(T_PRIVATE); goto SCANNER_CONTINUE_SIGNATURE; //goto (no break needed); diff --git a/library/Zend/Code/Scanner/TokenArrayScanner.php b/library/Zend/Code/Scanner/TokenArrayScanner.php index c04be33e3..4abc60376 100644 --- a/library/Zend/Code/Scanner/TokenArrayScanner.php +++ b/library/Zend/Code/Scanner/TokenArrayScanner.php @@ -225,7 +225,7 @@ class TokenArrayScanner implements ScannerInterface } if (!isset($info)) { - return null; + return; } return new NameInformation($info['namespace'], $info['uses']); @@ -669,7 +669,7 @@ class TokenArrayScanner implements ScannerInterface } elseif (!is_string($namespace)) { throw new Exception\InvalidArgumentException('Invalid namespace provided'); } elseif (!in_array($namespace, $namespaces)) { - return null; + return; } $uses = array(); diff --git a/library/Zend/Code/composer.json b/library/Zend/Code/composer.json index 5cc564133..3d72c672d 100644 --- a/library/Zend/Code/composer.json +++ b/library/Zend/Code/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Code\\": "" } }, - "target-dir": "Zend/Code", "require": { "php": ">=5.3.23", "zendframework/zend-eventmanager": "self.version" diff --git a/library/Zend/Config/AbstractConfigFactory.php b/library/Zend/Config/AbstractConfigFactory.php index 2f19f392a..b9c8766cc 100644 --- a/library/Zend/Config/AbstractConfigFactory.php +++ b/library/Zend/Config/AbstractConfigFactory.php @@ -84,7 +84,7 @@ class AbstractConfigFactory implements ServiceManager\AbstractFactoryInterface $config = $serviceLocator->get('Config'); $this->configs[$requestedName] = $this->configs[$key] = $config[$key]; - return $config; + return $config[$key]; } /** @@ -167,6 +167,6 @@ class AbstractConfigFactory implements ServiceManager\AbstractFactoryInterface return $matches[1]; } } - return null; + return; } } diff --git a/library/Zend/Config/Config.php b/library/Zend/Config/Config.php index 402b6e42e..d2a0f0002 100644 --- a/library/Zend/Config/Config.php +++ b/library/Zend/Config/Config.php @@ -30,13 +30,6 @@ class Config implements Countable, Iterator, ArrayAccess */ protected $allowModifications; - /** - * Number of elements in configuration data. - * - * @var int - */ - protected $count; - /** * Data within the configuration. * @@ -71,8 +64,6 @@ class Config implements Countable, Iterator, ArrayAccess } else { $this->data[$key] = $value; } - - $this->count++; } } @@ -126,8 +117,6 @@ class Config implements Countable, Iterator, ArrayAccess } else { $this->data[$name] = $value; } - - $this->count++; } else { throw new Exception\RuntimeException('Config is read only'); } @@ -200,7 +189,6 @@ class Config implements Countable, Iterator, ArrayAccess throw new Exception\InvalidArgumentException('Config is read only'); } elseif (isset($this->data[$name])) { unset($this->data[$name]); - $this->count--; $this->skipNextIteration = true; } } @@ -213,7 +201,7 @@ class Config implements Countable, Iterator, ArrayAccess */ public function count() { - return $this->count; + return count($this->data); } /** @@ -360,8 +348,6 @@ class Config implements Countable, Iterator, ArrayAccess } else { $this->data[$key] = $value; } - - $this->count++; } } diff --git a/library/Zend/Config/Processor/Token.php b/library/Zend/Config/Processor/Token.php index cf0ecab86..096ad93f1 100644 --- a/library/Zend/Config/Processor/Token.php +++ b/library/Zend/Config/Processor/Token.php @@ -259,7 +259,7 @@ class Token implements ProcessorInterface if (!is_string($value) && (is_bool($value) || is_numeric($value))) { $stringVal = (string) $value; - $changedVal = strtr($value, $this->map); + $changedVal = strtr($stringVal, $this->map); // replace the value only if a string replacement occurred if ($changedVal !== $stringVal) { diff --git a/library/Zend/Config/Reader/Ini.php b/library/Zend/Config/Reader/Ini.php index b78a21d9e..23e397037 100644 --- a/library/Zend/Config/Reader/Ini.php +++ b/library/Zend/Config/Reader/Ini.php @@ -72,7 +72,7 @@ class Ini implements ReaderInterface $this->directory = dirname($filename); set_error_handler( - function ($error, $message = '', $file = '', $line = 0) use ($filename) { + function ($error, $message = '') use ($filename) { throw new Exception\RuntimeException( sprintf('Error reading INI file "%s": %s', $filename, $message), $error @@ -101,7 +101,7 @@ class Ini implements ReaderInterface $this->directory = null; set_error_handler( - function ($error, $message = '', $file = '', $line = 0) { + function ($error, $message = '') { throw new Exception\RuntimeException( sprintf('Error reading INI string: %s', $message), $error diff --git a/library/Zend/Config/Reader/Xml.php b/library/Zend/Config/Reader/Xml.php index b0cb4bb9f..8ecb542cd 100644 --- a/library/Zend/Config/Reader/Xml.php +++ b/library/Zend/Config/Reader/Xml.php @@ -65,7 +65,7 @@ class Xml implements ReaderInterface $this->directory = dirname($filename); set_error_handler( - function ($error, $message = '', $file = '', $line = 0) use ($filename) { + function ($error, $message = '') use ($filename) { throw new Exception\RuntimeException( sprintf('Error reading XML file "%s": %s', $filename, $message), $error @@ -100,7 +100,7 @@ class Xml implements ReaderInterface $this->directory = null; set_error_handler( - function ($error, $message = '', $file = '', $line = 0) { + function ($error, $message = '') { throw new Exception\RuntimeException( sprintf('Error reading XML string: %s', $message), $error @@ -155,7 +155,7 @@ class Xml implements ReaderInterface $child = array('_' => $child); } - if (! is_array($child) ) { + if (! is_array($child)) { $child = array(); } diff --git a/library/Zend/Config/Writer/AbstractWriter.php b/library/Zend/Config/Writer/AbstractWriter.php index 0acd8453e..c9451ceb0 100644 --- a/library/Zend/Config/Writer/AbstractWriter.php +++ b/library/Zend/Config/Writer/AbstractWriter.php @@ -38,7 +38,7 @@ abstract class AbstractWriter implements WriterInterface } set_error_handler( - function ($error, $message = '', $file = '', $line = 0) use ($filename) { + function ($error, $message = '') use ($filename) { throw new Exception\RuntimeException( sprintf('Error writing to "%s": %s', $filename, $message), $error diff --git a/library/Zend/Config/Writer/PhpArray.php b/library/Zend/Config/Writer/PhpArray.php index f70c10b94..f7d72edc8 100644 --- a/library/Zend/Config/Writer/PhpArray.php +++ b/library/Zend/Config/Writer/PhpArray.php @@ -76,7 +76,7 @@ class PhpArray extends AbstractWriter } set_error_handler( - function ($error, $message = '', $file = '', $line = 0) use ($filename) { + function ($error, $message = '') use ($filename) { throw new Exception\RuntimeException( sprintf('Error writing to "%s": %s', $filename, $message), $error diff --git a/library/Zend/Config/WriterPluginManager.php b/library/Zend/Config/WriterPluginManager.php old mode 100755 new mode 100644 diff --git a/library/Zend/Config/composer.json b/library/Zend/Config/composer.json index 6ea7fa11e..8123db628 100644 --- a/library/Zend/Config/composer.json +++ b/library/Zend/Config/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Config\\": "" } }, - "target-dir": "Zend/Config", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Console/Adapter/AbstractAdapter.php b/library/Zend/Console/Adapter/AbstractAdapter.php index c85e47d96..bc73d91f3 100644 --- a/library/Zend/Console/Adapter/AbstractAdapter.php +++ b/library/Zend/Console/Adapter/AbstractAdapter.php @@ -159,7 +159,6 @@ abstract class AbstractAdapter implements AdapterInterface // Determine charset and dimensions $charset = $this->getCharset(); $width = $x2 - $x1 + 1; - $height = $y2 - $y1 + 1; if ($width <= 2) { $lineStyle = static::LINE_NONE; diff --git a/library/Zend/Console/Adapter/Posix.php b/library/Zend/Console/Adapter/Posix.php index ee2a3376a..5424892cf 100644 --- a/library/Zend/Console/Adapter/Posix.php +++ b/library/Zend/Console/Adapter/Posix.php @@ -402,6 +402,6 @@ class Posix extends AbstractAdapter return static::$ansiColorMap[$type][$color]; } - return null; + return; } } diff --git a/library/Zend/Console/Adapter/Windows.php b/library/Zend/Console/Adapter/Windows.php index ce6d4c4f5..83f5688d5 100644 --- a/library/Zend/Console/Adapter/Windows.php +++ b/library/Zend/Console/Adapter/Windows.php @@ -299,7 +299,7 @@ class Windows extends Virtual exec( 'powershell -NonInteractive -NoProfile -NoLogo -OutputFormat Text -Command "' - . '[int[]] $mask = ' . join(',', $asciiMask) . ';' + . '[int[]] $mask = ' . implode(',', $asciiMask) . ';' . 'do {' . '$key = $Host.UI.RawUI.ReadKey(\'NoEcho,IncludeKeyDown\').VirtualKeyCode;' . '} while ( !($mask -contains $key) );' diff --git a/library/Zend/Console/Adapter/WindowsAnsicon.php b/library/Zend/Console/Adapter/WindowsAnsicon.php index 3808ee8aa..1ffc728ed 100644 --- a/library/Zend/Console/Adapter/WindowsAnsicon.php +++ b/library/Zend/Console/Adapter/WindowsAnsicon.php @@ -165,7 +165,6 @@ class WindowsAnsicon extends Posix /** * Get charset currently in use by this adapter. * - * @return CharsetInterface $charset */ public function getCharset() @@ -259,7 +258,7 @@ class WindowsAnsicon extends Posix $result = $return = null; exec( 'powershell -NonInteractive -NoProfile -NoLogo -OutputFormat Text -Command "' - . '[int[]] $mask = '.join(',', $asciiMask).';' + . '[int[]] $mask = '.implode(',', $asciiMask).';' . 'do {' . '$key = $Host.UI.RawUI.ReadKey(\'NoEcho,IncludeKeyDown\').VirtualKeyCode;' . '} while ( !($mask -contains $key) );' diff --git a/library/Zend/Console/Console.php b/library/Zend/Console/Console.php index 1d380ddb4..1c77b0b5b 100644 --- a/library/Zend/Console/Console.php +++ b/library/Zend/Console/Console.php @@ -170,7 +170,7 @@ abstract class Console { // Check if we are in a console environment if (!static::isConsole()) { - return null; + return; } // Check if we're on windows diff --git a/library/Zend/Console/Getopt.php b/library/Zend/Console/Getopt.php index 77e830bae..94ccac0ed 100644 --- a/library/Zend/Console/Getopt.php +++ b/library/Zend/Console/Getopt.php @@ -514,7 +514,7 @@ class Getopt return $this->options[$flag]; } } - return null; + return; } /** diff --git a/library/Zend/Console/Prompt/Checkbox.php b/library/Zend/Console/Prompt/Checkbox.php new file mode 100644 index 000000000..30bfabbb6 --- /dev/null +++ b/library/Zend/Console/Prompt/Checkbox.php @@ -0,0 +1,183 @@ +promptText = (string) $promptText; + + $this->setOptions($options); + + $this->echo = (bool) $echo; + + $this->ignoreCase = (bool) $ignoreCase; + } + + /** + * Show a list of options and prompt the user to select any number of them. + * + * @return array Checked options + */ + public function show() + { + $this->checkedOptions = array(); + $mask = $this->prepareMask(); + + do { + $this->showAvailableOptions(); + + $response = $this->readOption($mask); + + if ($this->echo) { + $this->showResponse($response); + } + + $this->checkOrUncheckOption($response); + } while ($response != "\r" && $response != "\n"); + + $this->lastResponse = $this->checkedOptions; + + return $this->checkedOptions; + } + + /** + * Shows the selected option to the screen + * @param string $response + */ + private function showResponse($response) + { + $console = $this->getConsole(); + if (isset($this->options[$response])) { + $console->writeLine($this->options[$response]); + } else { + $console->writeLine(); + } + } + + /** + * Check or uncheck an option + * + * @param string $response + */ + private function checkOrUncheckOption($response) + { + if ($response != "\r" && $response != "\n" && isset($this->options[$response])) { + $pos = array_search($this->options[$response], $this->checkedOptions); + if ($pos === false) { + $this->checkedOptions[] = $this->options[$response]; + } else { + array_splice($this->checkedOptions, $pos, 1); + } + } + } + + /** + * Generates a mask to to be used by the readChar method. + * + * @return string + */ + private function prepareMask() + { + $mask = implode("", array_keys($this->options)) . "\r\n"; + + /** + * Normalize the mask if case is irrelevant + */ + if (!$this->ignoreCase) { + return $mask; + } + + $mask = implode("", array_unique(str_split(strtolower($mask) . strtoupper($mask)))); + + return $mask; + } + + /** + * Reads a char from console. + * + * @param string $mask + * @return string + */ + private function readOption($mask) + { + /** + * Read char from console + */ + + return $this->getConsole()->readChar($mask); + } + + /** + * Shows the available options with checked and unchecked states + */ + private function showAvailableOptions() + { + $console = $this->getConsole(); + $console->writeLine($this->promptText); + foreach ($this->options as $k => $v) { + $console->writeLine(' ' . $k . ') ' . (in_array($v, $this->checkedOptions) ? '[X] ' : '[ ] ') . $v); + } + } + + /** + * Set allowed options + * + * @param array|\Traversable $options + * @throws Exception\InvalidArgumentException + */ + private function setOptions($options) + { + $options = ArrayUtils::iteratorToArray($options); + + if (empty($options)) { + throw new Exception\InvalidArgumentException('Please, specify at least one option'); + } + + $this->options = $options; + } +} diff --git a/library/Zend/Console/Prompt/Password.php b/library/Zend/Console/Prompt/Password.php new file mode 100644 index 000000000..ac96303e1 --- /dev/null +++ b/library/Zend/Console/Prompt/Password.php @@ -0,0 +1,70 @@ +promptText = (string) $promptText; + $this->echo = (bool) $echo; + } + + /** + * Show the prompt to user and return a string. + * + * @return string + */ + public function show() + { + $console = $this->getConsole(); + + $console->writeLine($this->promptText); + + $password = ''; + + /** + * Read characters from console + */ + while (true) { + $char = $console->readChar(); + + $console->clearLine(); + + if (PHP_EOL == $char) { + break; + } + + $password .= $char; + + if ($this->echo) { + $console->write(str_repeat('*', strlen($password))); + } + } + + return $password; + } +} diff --git a/library/Zend/Console/RouteMatcher/DefaultRouteMatcher.php b/library/Zend/Console/RouteMatcher/DefaultRouteMatcher.php index 07a65504e..55a92e38b 100644 --- a/library/Zend/Console/RouteMatcher/DefaultRouteMatcher.php +++ b/library/Zend/Console/RouteMatcher/DefaultRouteMatcher.php @@ -136,7 +136,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface * Optional literal param, i.e. * [something] */ - elseif (preg_match('/\G\[ *?(?P[a-zA-Z][a-zA-Z0-9\_\-]*?) *?\](?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G\[ *?(?P[a-zA-Z][a-zA-Z0-9\_\-\:]*?) *?\](?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'literal' => true, @@ -175,7 +175,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface * Mandatory literal param, i.e. * something */ - elseif (preg_match('/\G(?P[a-zA-Z][a-zA-Z0-9\_\-]*?)(?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G(?P[a-zA-Z][a-zA-Z0-9\_\-\:]*?)(?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'literal' => true, @@ -372,7 +372,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface array_unique($options); // remove prefix - array_walk($options, function (&$val, $key) { + array_walk($options, function (&$val) { $val = ltrim($val, '-'); }); @@ -415,7 +415,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface array_unique($options); // remove prefix - array_walk($options, function (&$val, $key) { + array_walk($options, function (&$val) { $val = ltrim($val, '-'); }); @@ -510,7 +510,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface $alternativeAliases[] = '(?:' . implode('|', $this->getAliases($alternative)) . ')'; } - $regex .= join('|', $alternativeAliases); + $regex .= implode('|', $alternativeAliases); if ($part['hasValue']) { $regex .= ')(?:\=(?P.*?)$)?$/'; @@ -568,7 +568,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface * Drop out if that was a mandatory param */ if ($part['required']) { - return null; + return; } /* @@ -599,7 +599,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface array_splice($params, $x, 1); } else { // there are no more params available - return null; + return; } } @@ -611,7 +611,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface !preg_match($this->constraints[$part['name']], $value) ) { // constraint failed - return null; + return; } } @@ -653,7 +653,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface */ foreach ($params as $param) { if (preg_match('#^\-+#', $param)) { - return null; // there is an unrecognized flag + return; // there is an unrecognized flag } } @@ -668,7 +668,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface if (!isset($params[$argPos])) { if ($part['required']) { // cannot find required positional param - return null; + return; } else { // stop matching break; @@ -685,7 +685,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface (isset($part['alternatives']) && !in_array($value, $part['alternatives'])) || (!isset($part['alternatives']) && $value != $part['name']) ) { - return null; + return; } } @@ -697,7 +697,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface !preg_match($this->constraints[$part['name']], $value) ) { // constraint failed - return null; + return; } } @@ -734,7 +734,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface * Check if we have consumed all positional parameters */ if ($argPos < count($params)) { - return null; // there are extraneous params that were not consumed + return; // there are extraneous params that were not consumed } /* @@ -772,7 +772,7 @@ class DefaultRouteMatcher implements RouteMatcherInterface } if (!$valid) { - return null; + return; } return array_replace($this->defaults, $matches); diff --git a/library/Zend/Console/composer.json b/library/Zend/Console/composer.json index 8265ef2bd..41af21119 100644 --- a/library/Zend/Console/composer.json +++ b/library/Zend/Console/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Console\\": "" } }, - "target-dir": "Zend/Console", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Crypt/BlockCipher.php b/library/Zend/Crypt/BlockCipher.php index 4cba25617..1a6acb026 100644 --- a/library/Zend/Crypt/BlockCipher.php +++ b/library/Zend/Crypt/BlockCipher.php @@ -461,7 +461,7 @@ class BlockCipher } $hmacSize = Hmac::getOutputSize($this->hash); $hmac = substr($data, 0, $hmacSize); - $ciphertext = substr($data, $hmacSize); + $ciphertext = substr($data, $hmacSize) ?: ''; if (!$this->binaryOutput) { $ciphertext = base64_decode($ciphertext); } diff --git a/library/Zend/Crypt/FileCipher.php b/library/Zend/Crypt/FileCipher.php new file mode 100644 index 000000000..da7dfca68 --- /dev/null +++ b/library/Zend/Crypt/FileCipher.php @@ -0,0 +1,374 @@ +cipher = new Mcrypt; + } + + /** + * Set the cipher object + * + * @param SymmetricInterface $cipher + */ + public function setCipher(SymmetricInterface $cipher) + { + $this->cipher = $cipher; + } + + /** + * Get the cipher object + * + * @return SymmetricInterface + */ + public function getCipher() + { + return $this->cipher; + } + + /** + * Set the number of iterations for Pbkdf2 + * + * @param int $num + */ + public function setKeyIteration($num) + { + $this->keyIteration = (int) $num; + } + + /** + * Get the number of iterations for Pbkdf2 + * + * @return int + */ + public function getKeyIteration() + { + return $this->keyIteration; + } + + /** + * Set the encryption/decryption key + * + * @param string $key + * @throws Exception\InvalidArgumentException + */ + public function setKey($key) + { + if (empty($key)) { + throw new Exception\InvalidArgumentException('The key cannot be empty'); + } + $this->key = (string) $key; + } + + /** + * Get the key + * + * @return string|null + */ + public function getKey() + { + return $this->key; + } + + /** + * Set algorithm of the symmetric cipher + * + * @param string $algo + */ + public function setCipherAlgorithm($algo) + { + $this->cipher->setAlgorithm($algo); + } + + /** + * Get the cipher algorithm + * + * @return string|bool + */ + public function getCipherAlgorithm() + { + return $this->cipher->getAlgorithm(); + } + + /** + * Get the supported algorithms of the symmetric cipher + * + * @return array + */ + public function getCipherSupportedAlgorithms() + { + return $this->cipher->getSupportedAlgorithms(); + } + + /** + * Set the hash algorithm for HMAC authentication + * + * @param string $hash + * @throws Exception\InvalidArgumentException + */ + public function setHashAlgorithm($hash) + { + if (!Hash::isSupported($hash)) { + throw new Exception\InvalidArgumentException( + "The specified hash algorithm '{$hash}' is not supported by Zend\Crypt\Hash" + ); + } + $this->hash = (string) $hash; + } + + /** + * Get the hash algorithm for HMAC authentication + * + * @return string + */ + public function getHashAlgorithm() + { + return $this->hash; + } + + /** + * Set the hash algorithm for the Pbkdf2 + * + * @param string $hash + * @throws Exception\InvalidArgumentException + */ + public function setPbkdf2HashAlgorithm($hash) + { + if (!Hash::isSupported($hash)) { + throw new Exception\InvalidArgumentException( + "The specified hash algorithm '{$hash}' is not supported by Zend\Crypt\Hash" + ); + } + $this->pbkdf2Hash = (string) $hash; + } + + /** + * Get the Pbkdf2 hash algorithm + * + * @return string + */ + public function getPbkdf2HashAlgorithm() + { + return $this->pbkdf2Hash; + } + + /** + * Encrypt then authenticate a file using HMAC + * + * @param string $fileIn + * @param string $fileOut + * @return bool + * @throws Exception\InvalidArgumentException + */ + public function encrypt($fileIn, $fileOut) + { + $this->checkFileInOut($fileIn, $fileOut); + if (empty($this->key)) { + throw new Exception\InvalidArgumentException('No key specified for encryption'); + } + + $read = fopen($fileIn, "r"); + $write = fopen($fileOut, "w"); + $iv = Rand::getBytes($this->cipher->getSaltSize(), true); + $keys = Pbkdf2::calc($this->getPbkdf2HashAlgorithm(), + $this->getKey(), + $iv, + $this->getKeyIteration(), + $this->cipher->getKeySize() * 2); + $hmac = ''; + $size = 0; + $tot = filesize($fileIn); + $padding = $this->cipher->getPadding(); + + $this->cipher->setKey(substr($keys, 0, $this->cipher->getKeySize())); + $this->cipher->setPadding(new Symmetric\Padding\NoPadding); + $this->cipher->setSalt($iv); + $this->cipher->setMode('cbc'); + + $hashAlgo = $this->getHashAlgorithm(); + $saltSize = $this->cipher->getSaltSize(); + $algorithm = $this->cipher->getAlgorithm(); + $keyHmac = substr($keys, $this->cipher->getKeySize()); + + while ($data = fread($read, self::BUFFER_SIZE)) { + $size += strlen($data); + // Padding if last block + if ($size == $tot) { + $this->cipher->setPadding($padding); + } + $result = $this->cipher->encrypt($data); + if ($size <= self::BUFFER_SIZE) { + // Write a placeholder for the HMAC and write the IV + fwrite($write, str_repeat(0, Hmac::getOutputSize($hashAlgo))); + } else { + $result = substr($result, $saltSize); + } + $hmac = Hmac::compute($keyHmac, + $hashAlgo, + $algorithm . $hmac . $result); + $this->cipher->setSalt(substr($result, -1 * $saltSize)); + if (fwrite($write, $result) !== strlen($result)) { + return false; + } + } + $result = true; + // write the HMAC at the beginning of the file + fseek($write, 0); + if (fwrite($write, $hmac) !== strlen($hmac)) { + $result = false; + } + fclose($write); + fclose($read); + + return $result; + } + + /** + * Decrypt a file + * + * @param string $fileIn + * @param string $fileOut + * @param bool $compress + * @return bool + * @throws Exception\InvalidArgumentException + */ + public function decrypt($fileIn, $fileOut) + { + $this->checkFileInOut($fileIn, $fileOut); + if (empty($this->key)) { + throw new Exception\InvalidArgumentException('No key specified for decryption'); + } + + $read = fopen($fileIn, "r"); + $write = fopen($fileOut, "w"); + $hmacRead = fread($read, Hmac::getOutputSize($this->getHashAlgorithm())); + $iv = fread($read, $this->cipher->getSaltSize()); + $tot = filesize($fileIn); + $hmac = $iv; + $size = strlen($iv) + strlen($hmacRead); + $keys = Pbkdf2::calc($this->getPbkdf2HashAlgorithm(), + $this->getKey(), + $iv, + $this->getKeyIteration(), + $this->cipher->getKeySize() * 2); + $padding = $this->cipher->getPadding(); + $this->cipher->setPadding(new Symmetric\Padding\NoPadding); + $this->cipher->setKey(substr($keys, 0, $this->cipher->getKeySize())); + $this->cipher->setMode('cbc'); + + $blockSize = $this->cipher->getBlockSize(); + $hashAlgo = $this->getHashAlgorithm(); + $algorithm = $this->cipher->getAlgorithm(); + $saltSize = $this->cipher->getSaltSize(); + $keyHmac = substr($keys, $this->cipher->getKeySize()); + + while ($data = fread($read, self::BUFFER_SIZE)) { + $size += strlen($data); + // Unpadding if last block + if ($size + $blockSize >= $tot) { + $this->cipher->setPadding($padding); + $data .= fread($read, $blockSize); + } + $result = $this->cipher->decrypt($iv . $data); + $hmac = Hmac::compute($keyHmac, + $hashAlgo, + $algorithm . $hmac . $data); + $iv = substr($data, -1 * $saltSize); + if (fwrite($write, $result) !== strlen($result)) { + return false; + } + } + fclose($write); + fclose($read); + + // check for data integrity + if (!Utils::compareStrings($hmac, $hmacRead)) { + unlink($fileOut); + return false; + } + + return true; + } + + /** + * Check that input file exists and output file dont + * + * @param string $fileIn + * @param string $fileOut + * @throws Exception\InvalidArgumentException + */ + protected function checkFileInOut($fileIn, $fileOut) + { + if (!file_exists($fileIn)) { + throw new Exception\InvalidArgumentException(sprintf( + "I cannot open the %s file", $fileIn + )); + } + if (file_exists($fileOut)) { + throw new Exception\InvalidArgumentException(sprintf( + "The file %s already exists", $fileOut + )); + } + } +} diff --git a/library/Zend/Crypt/Key/Derivation/SaltedS2k.php b/library/Zend/Crypt/Key/Derivation/SaltedS2k.php index 4a01e1907..c3a71e160 100644 --- a/library/Zend/Crypt/Key/Derivation/SaltedS2k.php +++ b/library/Zend/Crypt/Key/Derivation/SaltedS2k.php @@ -14,7 +14,7 @@ namespace Zend\Crypt\Key\Derivation; */ class SaltedS2k { - protected static $supportedMhashAlgos = array ( + protected static $supportedMhashAlgos = array( 'adler32' => MHASH_ADLER32, 'md2' => MHASH_MD2, 'md4' => MHASH_MD4, diff --git a/library/Zend/Crypt/Key/Derivation/Scrypt.php b/library/Zend/Crypt/Key/Derivation/Scrypt.php index a5923dea8..fe8a53974 100644 --- a/library/Zend/Crypt/Key/Derivation/Scrypt.php +++ b/library/Zend/Crypt/Key/Derivation/Scrypt.php @@ -315,7 +315,7 @@ abstract class Scrypt if (PHP_INT_SIZE === 8) { $v = 'V'; } - list(,$n) = unpack($v, substr($b, -64)); + list(, $n) = unpack($v, substr($b, -64)); return $n; } diff --git a/library/Zend/Crypt/Password/Apache.php b/library/Zend/Crypt/Password/Apache.php index 7bbb3dc65..7a0cd12fb 100644 --- a/library/Zend/Crypt/Password/Apache.php +++ b/library/Zend/Crypt/Password/Apache.php @@ -11,6 +11,7 @@ namespace Zend\Crypt\Password; use Traversable; use Zend\Math\Rand; +use Zend\Crypt\Utils; /** * Apache password authentication @@ -126,8 +127,9 @@ class Apache implements PasswordInterface { if (substr($hash, 0, 5) === '{SHA}') { $hash2 = '{SHA}' . base64_encode(sha1($password, true)); - return ($hash === $hash2); + return Utils::compareStrings($hash, $hash2); } + if (substr($hash, 0, 6) === '$apr1$') { $token = explode('$', $hash); if (empty($token[2])) { @@ -136,18 +138,22 @@ class Apache implements PasswordInterface ); } $hash2 = $this->apr1Md5($password, $token[2]); - return ($hash === $hash2); + return Utils::compareStrings($hash, $hash2); } - if (strlen($hash) > 13) { // digest + + $bcryptPattern = '/\$2[ay]?\$[0-9]{2}\$[' . addcslashes(static::BASE64, '+/') . '\.]{53}/'; + + if (strlen($hash) > 13 && ! preg_match($bcryptPattern, $hash)) { // digest if (empty($this->userName) || empty($this->authName)) { throw new Exception\RuntimeException( 'You must specify UserName and AuthName (realm) to verify the digest' ); } $hash2 = md5($this->userName . ':' . $this->authName . ':' .$password); - return ($hash === $hash2); + return Utils::compareStrings($hash, $hash2); } - return (crypt($password, $hash) === $hash); + + return Utils::compareStrings($hash, crypt($password, $hash)); } /** diff --git a/library/Zend/Crypt/Password/Bcrypt.php b/library/Zend/Crypt/Password/Bcrypt.php index 94e6e89fa..a55627448 100644 --- a/library/Zend/Crypt/Password/Bcrypt.php +++ b/library/Zend/Crypt/Password/Bcrypt.php @@ -12,6 +12,7 @@ namespace Zend\Crypt\Password; use Traversable; use Zend\Math\Rand; use Zend\Stdlib\ArrayUtils; +use Zend\Crypt\Utils; /** * Bcrypt algorithm using crypt() function of PHP @@ -101,10 +102,7 @@ class Bcrypt implements PasswordInterface public function verify($password, $hash) { $result = crypt($password, $hash); - if ($result === $hash) { - return true; - } - return false; + return Utils::compareStrings($hash, $result); } /** diff --git a/library/Zend/Crypt/Password/BcryptSha.php b/library/Zend/Crypt/Password/BcryptSha.php new file mode 100644 index 000000000..b33a7be47 --- /dev/null +++ b/library/Zend/Crypt/Password/BcryptSha.php @@ -0,0 +1,45 @@ +72 characters. + */ +class BcryptSha extends Bcrypt +{ + + /** + * BcryptSha + * + * @param string $password + * @throws Exception\RuntimeException + * @return string + */ + public function create($password) + { + return parent::create(Hash::compute('sha256', $password)); + } + + /** + * Verify if a password is correct against a hash value + * + * @param string $password + * @param string $hash + * @throws Exception\RuntimeException when the hash is unable to be processed + * @return bool + */ + public function verify($password, $hash) + { + return parent::verify(Hash::compute('sha256', $password), $hash); + } +} diff --git a/library/Zend/Crypt/PublicKey/DiffieHellman.php b/library/Zend/Crypt/PublicKey/DiffieHellman.php index 3ca593f2f..deeb5bf26 100644 --- a/library/Zend/Crypt/PublicKey/DiffieHellman.php +++ b/library/Zend/Crypt/PublicKey/DiffieHellman.php @@ -414,14 +414,11 @@ class DiffieHellman switch ($outputFormat) { case self::FORMAT_BINARY: return $this->math->intToBin($number); - break; case self::FORMAT_BTWOC: return $this->math->intToBin($number, true); - break; case self::FORMAT_NUMBER: default: return $number; - break; } } diff --git a/library/Zend/Crypt/Symmetric/Mcrypt.php b/library/Zend/Crypt/Symmetric/Mcrypt.php old mode 100755 new mode 100644 index 38fd84733..44178afe5 --- a/library/Zend/Crypt/Symmetric/Mcrypt.php +++ b/library/Zend/Crypt/Symmetric/Mcrypt.php @@ -258,7 +258,7 @@ class Mcrypt implements SymmetricInterface public function getKey() { if (empty($this->key)) { - return null; + return; } return substr($this->key, 0, $this->getKeySize()); } @@ -433,7 +433,7 @@ class Mcrypt implements SymmetricInterface public function getSalt() { if (empty($this->iv)) { - return null; + return; } if (strlen($this->iv) < $this->getSaltSize()) { throw new Exception\RuntimeException( diff --git a/library/Zend/Crypt/Symmetric/Padding/NoPadding.php b/library/Zend/Crypt/Symmetric/Padding/NoPadding.php new file mode 100644 index 000000000..afbee052f --- /dev/null +++ b/library/Zend/Crypt/Symmetric/Padding/NoPadding.php @@ -0,0 +1,39 @@ +=5.3.23", "zendframework/zend-math": "self.version", diff --git a/library/Zend/Db/Adapter/AdapterAwareTrait.php b/library/Zend/Db/Adapter/AdapterAwareTrait.php index be888d9f1..93e99856b 100644 --- a/library/Zend/Db/Adapter/AdapterAwareTrait.php +++ b/library/Zend/Db/Adapter/AdapterAwareTrait.php @@ -9,7 +9,6 @@ namespace Zend\Db\Adapter; - trait AdapterAwareTrait { /** diff --git a/library/Zend/Db/Adapter/Driver/AbstractConnection.php b/library/Zend/Db/Adapter/Driver/AbstractConnection.php new file mode 100644 index 000000000..09cb075d5 --- /dev/null +++ b/library/Zend/Db/Adapter/Driver/AbstractConnection.php @@ -0,0 +1,135 @@ +isConnected()) { + $this->resource = null; + } + + return $this; + } + + /** + * Get connection parameters + * + * @return array + */ + public function getConnectionParameters() + { + return $this->connectionParameters; + } + + /** + * Get driver name + * + * @return null|string + */ + public function getDriverName() + { + return $this->driverName; + } + + /** + * @return null|ProfilerInterface + */ + public function getProfiler() + { + return $this->profiler; + } + + /** + * {@inheritDoc} + * + * @return resource + */ + public function getResource() + { + if (!$this->isConnected()) { + $this->connect(); + } + + return $this->resource; + } + + /** + * Checks whether the connection is in transaction state. + * + * @return boolean + */ + public function inTransaction() + { + return $this->inTransaction; + } + + /** + * @param array $connectionParameters + * @return self + */ + public function setConnectionParameters(array $connectionParameters) + { + $this->connectionParameters = $connectionParameters; + + return $this; + } + + /** + * {@inheritDoc} + * + * @return self + */ + public function setProfiler(ProfilerInterface $profiler) + { + $this->profiler = $profiler; + + return $this; + } +} diff --git a/library/Zend/Db/Adapter/Driver/IbmDb2/Connection.php b/library/Zend/Db/Adapter/Driver/IbmDb2/Connection.php old mode 100755 new mode 100644 index 7d756e355..3d474c9b7 --- a/library/Zend/Db/Adapter/Driver/IbmDb2/Connection.php +++ b/library/Zend/Db/Adapter/Driver/IbmDb2/Connection.php @@ -9,39 +9,16 @@ namespace Zend\Db\Adapter\Driver\IbmDb2; -use Zend\Db\Adapter\Driver\ConnectionInterface; +use Zend\Db\Adapter\Driver\AbstractConnection; use Zend\Db\Adapter\Exception; -use Zend\Db\Adapter\Profiler; -class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface +class Connection extends AbstractConnection { /** - * @var IbmDb2 + * @var IbmDb2 */ protected $driver = null; - /** - * @var array - */ - protected $connectionParameters = null; - - /** - * @var resource - */ - protected $resource = null; - - /** - * @var Profiler\ProfilerInterface - */ - protected $profiler = null; - - /** - * In transaction - * - * @var bool - */ - protected $inTransaction = false; - /** * i5 OS * @@ -78,54 +55,19 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface /** * Set driver * - * @param IbmDb2 $driver - * @return Connection + * @param IbmDb2 $driver + * @return self */ public function setDriver(IbmDb2 $driver) { $this->driver = $driver; + return $this; } /** - * @param Profiler\ProfilerInterface $profiler - * @return Connection - */ - public function setProfiler(Profiler\ProfilerInterface $profiler) - { - $this->profiler = $profiler; - return $this; - } - - /** - * @return null|Profiler\ProfilerInterface - */ - public function getProfiler() - { - return $this->profiler; - } - - /** - * @param array $connectionParameters - * @return Connection - */ - public function setConnectionParameters(array $connectionParameters) - { - $this->connectionParameters = $connectionParameters; - return $this; - } - - /** - * @return array - */ - public function getConnectionParameters() - { - return $this->connectionParameters; - } - - /** - * @param resource $resource DB2 resource - * @return Connection + * @param resource $resource DB2 resource + * @return self */ public function setResource($resource) { @@ -133,13 +75,12 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface throw new Exception\InvalidArgumentException('The resource provided must be of type "DB2 Connection"'); } $this->resource = $resource; + return $this; } /** - * Get current schema - * - * @return string + * {@inheritDoc} */ public function getCurrentSchema() { @@ -148,23 +89,12 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $info = db2_server_info($this->resource); + return (isset($info->DB_NAME) ? $info->DB_NAME : ''); } /** - * Get resource - * - * @return mixed - */ - public function getResource() - { - return $this->resource; - } - - /** - * Connect - * - * @return self + * {@inheritDoc} */ public function connect() { @@ -183,7 +113,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } } - return null; + return; }; $database = $findParameterValue(array('database', 'db')); @@ -206,9 +136,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Is connected - * - * @return bool + * {@inheritDoc} */ public function isConnected() { @@ -216,9 +144,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Disconnect - * - * @return ConnectionInterface + * {@inheritDoc} */ public function disconnect() { @@ -231,9 +157,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Begin transaction - * - * @return ConnectionInterface + * {@inheritDoc} */ public function beginTransaction() { @@ -250,23 +174,12 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $this->prevAutocommit = db2_autocommit($this->resource); db2_autocommit($this->resource, DB2_AUTOCOMMIT_OFF); $this->inTransaction = true; + return $this; } /** - * In transaction - * - * @return bool - */ - public function inTransaction() - { - return $this->inTransaction; - } - - /** - * Commit - * - * @return ConnectionInterface + * {@inheritDoc} */ public function commit() { @@ -283,21 +196,22 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $this->inTransaction = false; + return $this; } /** * Rollback * - * @return ConnectionInterface + * @return Connection */ public function rollback() { - if (!$this->resource) { + if (!$this->isConnected()) { throw new Exception\RuntimeException('Must be connected before you can rollback.'); } - if (!$this->inTransaction) { + if (!$this->inTransaction()) { throw new Exception\RuntimeException('Must call beginTransaction() before you can rollback.'); } @@ -310,14 +224,12 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $this->inTransaction = false; + return $this; } /** - * Execute - * - * @param string $sql - * @return Result + * {@inheritDoc} */ public function execute($sql) { @@ -346,10 +258,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Get last generated id - * - * @param null $name Ignored - * @return int + * {@inheritDoc} */ public function getLastGeneratedValue($name = null) { @@ -367,7 +276,8 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface return $this->i5; } - $this->i5 = php_uname('s') == 'OS400' ? true : false; + $this->i5 = (php_uname('s') == 'OS400'); + return $this->i5; } } diff --git a/library/Zend/Db/Adapter/Driver/IbmDb2/IbmDb2.php b/library/Zend/Db/Adapter/Driver/IbmDb2/IbmDb2.php old mode 100755 new mode 100644 diff --git a/library/Zend/Db/Adapter/Driver/IbmDb2/Result.php b/library/Zend/Db/Adapter/Driver/IbmDb2/Result.php old mode 100755 new mode 100644 index b425f2483..5c9dc53b9 --- a/library/Zend/Db/Adapter/Driver/IbmDb2/Result.php +++ b/library/Zend/Db/Adapter/Driver/IbmDb2/Result.php @@ -119,7 +119,7 @@ class Result implements ResultInterface */ public function buffer() { - return null; + return; } /** @@ -187,6 +187,6 @@ class Result implements ResultInterface */ public function count() { - return null; + return; } } diff --git a/library/Zend/Db/Adapter/Driver/IbmDb2/Statement.php b/library/Zend/Db/Adapter/Driver/IbmDb2/Statement.php index 35c4243a1..dc7e3df4c 100644 --- a/library/Zend/Db/Adapter/Driver/IbmDb2/Statement.php +++ b/library/Zend/Db/Adapter/Driver/IbmDb2/Statement.php @@ -194,7 +194,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface /** * Execute * - * @param null $parameters + * @param null|array|ParameterContainer $parameters * @return Result */ public function execute($parameters = null) diff --git a/library/Zend/Db/Adapter/Driver/Mysqli/Connection.php b/library/Zend/Db/Adapter/Driver/Mysqli/Connection.php index 587d25f36..b855ee124 100644 --- a/library/Zend/Db/Adapter/Driver/Mysqli/Connection.php +++ b/library/Zend/Db/Adapter/Driver/Mysqli/Connection.php @@ -9,45 +9,25 @@ namespace Zend\Db\Adapter\Driver\Mysqli; -use Zend\Db\Adapter\Driver\ConnectionInterface; +use Zend\Db\Adapter\Driver\AbstractConnection; use Zend\Db\Adapter\Exception; -use Zend\Db\Adapter\Profiler; -class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface +class Connection extends AbstractConnection { /** * @var Mysqli */ protected $driver = null; - /** - * @var Profiler\ProfilerInterface - */ - protected $profiler = null; - - /** - * Connection parameters - * - * @var array - */ - protected $connectionParameters = array(); - /** * @var \mysqli */ protected $resource = null; - /** - * In transaction - * - * @var bool - */ - protected $inTransaction = false; - /** * Constructor * - * @param array|mysqli|null $connectionInfo + * @param array|mysqli|null $connectionInfo * @throws \Zend\Db\Adapter\Exception\InvalidArgumentException */ public function __construct($connectionInfo = null) @@ -62,59 +42,18 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * @param Mysqli $driver - * @return Connection + * @param Mysqli $driver + * @return self */ public function setDriver(Mysqli $driver) { $this->driver = $driver; + return $this; } /** - * @param Profiler\ProfilerInterface $profiler - * @return Connection - */ - public function setProfiler(Profiler\ProfilerInterface $profiler) - { - $this->profiler = $profiler; - return $this; - } - - /** - * @return null|Profiler\ProfilerInterface - */ - public function getProfiler() - { - return $this->profiler; - } - - /** - * Set connection parameters - * - * @param array $connectionParameters - * @return Connection - */ - public function setConnectionParameters(array $connectionParameters) - { - $this->connectionParameters = $connectionParameters; - return $this; - } - - /** - * Get connection parameters - * - * @return array - */ - public function getConnectionParameters() - { - return $this->connectionParameters; - } - - /** - * Get current schema - * - * @return string + * {@inheritDoc} */ public function getCurrentSchema() { @@ -125,6 +64,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface /** @var $result \mysqli_result */ $result = $this->resource->query('SELECT DATABASE()'); $r = $result->fetch_row(); + return $r[0]; } @@ -132,30 +72,17 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface * Set resource * * @param \mysqli $resource - * @return Connection + * @return self */ public function setResource(\mysqli $resource) { $this->resource = $resource; + return $this; } /** - * Get resource - * - * @return \mysqli - */ - public function getResource() - { - $this->connect(); - return $this->resource; - } - - /** - * Connect - * - * @throws Exception\RuntimeException - * @return Connection + * {@inheritDoc} */ public function connect() { @@ -173,6 +100,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface return $p[$name]; } } + return; }; @@ -217,9 +145,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Is connected - * - * @return bool + * {@inheritDoc} */ public function isConnected() { @@ -227,9 +153,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Disconnect - * - * @return void + * {@inheritDoc} */ public function disconnect() { @@ -240,9 +164,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Begin transaction - * - * @return void + * {@inheritDoc} */ public function beginTransaction() { @@ -252,43 +174,32 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $this->resource->autocommit(false); $this->inTransaction = true; + + return $this; } /** - * In transaction - * - * @return bool - */ - public function inTransaction() - { - return $this->inTransaction; - } - - /** - * Commit - * - * @return void + * {@inheritDoc} */ public function commit() { - if (!$this->resource) { + if (!$this->isConnected()) { $this->connect(); } $this->resource->commit(); $this->inTransaction = false; $this->resource->autocommit(true); + + return $this; } /** - * Rollback - * - * @throws Exception\RuntimeException - * @return Connection + * {@inheritDoc} */ public function rollback() { - if (!$this->resource) { + if (!$this->isConnected()) { throw new Exception\RuntimeException('Must be connected before you can rollback.'); } @@ -298,15 +209,15 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $this->resource->rollback(); $this->resource->autocommit(true); + $this->inTransaction = false; + return $this; } /** - * Execute + * {@inheritDoc} * - * @param string $sql * @throws Exception\InvalidQueryException - * @return Result */ public function execute($sql) { @@ -330,14 +241,12 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $resultPrototype = $this->driver->createResult(($resultResource === true) ? $this->resource : $resultResource); + return $resultPrototype; } /** - * Get last generated id - * - * @param null $name Ignored - * @return int + * {@inheritDoc} */ public function getLastGeneratedValue($name = null) { diff --git a/library/Zend/Db/Adapter/Driver/Mysqli/Result.php b/library/Zend/Db/Adapter/Driver/Mysqli/Result.php index d620ee15a..d4af5c5c0 100644 --- a/library/Zend/Db/Adapter/Driver/Mysqli/Result.php +++ b/library/Zend/Db/Adapter/Driver/Mysqli/Result.php @@ -187,7 +187,6 @@ class Result implements */ protected function loadDataFromMysqliStatement() { - $data = null; // build the default reference based bind structure, if it does not already exist if ($this->statementBindValues['keys'] === null) { $this->statementBindValues['keys'] = array(); diff --git a/library/Zend/Db/Adapter/Driver/Mysqli/Statement.php b/library/Zend/Db/Adapter/Driver/Mysqli/Statement.php index 1c68e37cd..361ec3f50 100644 --- a/library/Zend/Db/Adapter/Driver/Mysqli/Statement.php +++ b/library/Zend/Db/Adapter/Driver/Mysqli/Statement.php @@ -219,7 +219,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface /** * Execute * - * @param ParameterContainer|array $parameters + * @param null|array|ParameterContainer $parameters * @throws Exception\RuntimeException * @return mixed */ diff --git a/library/Zend/Db/Adapter/Driver/Oci8/Connection.php b/library/Zend/Db/Adapter/Driver/Oci8/Connection.php old mode 100755 new mode 100644 index 0bb3b2544..4a231917b --- a/library/Zend/Db/Adapter/Driver/Oci8/Connection.php +++ b/library/Zend/Db/Adapter/Driver/Oci8/Connection.php @@ -9,45 +9,20 @@ namespace Zend\Db\Adapter\Driver\Oci8; -use Zend\Db\Adapter\Driver\ConnectionInterface; +use Zend\Db\Adapter\Driver\AbstractConnection; use Zend\Db\Adapter\Exception; -use Zend\Db\Adapter\Profiler; -class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface +class Connection extends AbstractConnection { /** * @var Oci8 */ protected $driver = null; - /** - * @var Profiler\ProfilerInterface - */ - protected $profiler = null; - - /** - * Connection parameters - * - * @var array - */ - protected $connectionParameters = array(); - - /** - * @var - */ - protected $resource = null; - - /** - * In transaction - * - * @var bool - */ - protected $inTransaction = false; - /** * Constructor * - * @param array|resource|null $connectionInfo + * @param array|resource|null $connectionInfo * @throws \Zend\Db\Adapter\Exception\InvalidArgumentException */ public function __construct($connectionInfo = null) @@ -62,59 +37,18 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * @param Oci8 $driver - * @return Connection + * @param Oci8 $driver + * @return self */ public function setDriver(Oci8 $driver) { $this->driver = $driver; + return $this; } /** - * @param Profiler\ProfilerInterface $profiler - * @return Connection - */ - public function setProfiler(Profiler\ProfilerInterface $profiler) - { - $this->profiler = $profiler; - return $this; - } - - /** - * @return null|Profiler\ProfilerInterface - */ - public function getProfiler() - { - return $this->profiler; - } - - /** - * Set connection parameters - * - * @param array $connectionParameters - * @return Connection - */ - public function setConnectionParameters(array $connectionParameters) - { - $this->connectionParameters = $connectionParameters; - return $this; - } - - /** - * Get connection parameters - * - * @return array - */ - public function getConnectionParameters() - { - return $this->connectionParameters; - } - - /** - * Get current schema - * - * @return string + * {@inheritDoc} */ public function getCurrentSchema() { @@ -126,6 +60,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $stmt = oci_parse($this->resource, $query); oci_execute($stmt); $dbNameArray = oci_fetch_array($stmt, OCI_ASSOC); + return $dbNameArray['current_schema']; } @@ -133,7 +68,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface * Set resource * * @param resource $resource - * @return Connection + * @return self */ public function setResource($resource) { @@ -141,24 +76,12 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface throw new Exception\InvalidArgumentException('A resource of type "oci8 connection" was expected'); } $this->resource = $resource; + return $this; } /** - * Get resource - * - * @return \oci8 - */ - public function getResource() - { - $this->connect(); - return $this->resource; - } - - /** - * Connect - * - * @return Connection + * {@inheritDoc} */ public function connect() { @@ -176,7 +99,8 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface return $p[$name]; } } - return null; + + return; }; // http://www.php.net/manual/en/function.oci-connect.php @@ -211,9 +135,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Is connected - * - * @return bool + * {@inheritDoc} */ public function isConnected() { @@ -221,7 +143,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Disconnect + * {@inheritDoc} */ public function disconnect() { @@ -231,7 +153,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Begin transaction + * {@inheritDoc} */ public function beginTransaction() { @@ -241,48 +163,42 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface // A transaction begins when the first SQL statement that changes data is executed with oci_execute() using the OCI_NO_AUTO_COMMIT flag. $this->inTransaction = true; + + return $this; } /** - * In transaction - * - * @return bool - */ - public function inTransaction() - { - return $this->inTransaction; - } - - /** - * Commit + * {@inheritDoc} */ public function commit() { - if (!$this->resource) { + if (!$this->isConnected()) { $this->connect(); } - if ($this->inTransaction) { + if ($this->inTransaction()) { $valid = oci_commit($this->resource); if ($valid === false) { $e = oci_error($this->resource); throw new Exception\InvalidQueryException($e['message'], $e['code']); } + + $this->inTransaction = false; } + + return $this; } /** - * Rollback - * - * @return Connection + * {@inheritDoc} */ public function rollback() { - if (!$this->resource) { + if (!$this->isConnected()) { throw new Exception\RuntimeException('Must be connected before you can rollback.'); } - if (!$this->inTransaction) { + if (!$this->inTransaction()) { throw new Exception\RuntimeException('Must call commit() before you can rollback.'); } @@ -292,14 +208,13 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface throw new Exception\InvalidQueryException($e['message'], $e['code']); } + $this->inTransaction = false; + return $this; } /** - * Execute - * - * @param string $sql - * @return Result + * {@inheritDoc} */ public function execute($sql) { @@ -329,18 +244,16 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $resultPrototype = $this->driver->createResult($ociStmt); + return $resultPrototype; } /** - * Get last generated id - * - * @param null $name Ignored - * @return int + * {@inheritDoc} */ public function getLastGeneratedValue($name = null) { // @todo Get Last Generated Value in Connection (this might not apply) - return null; + return; } } diff --git a/library/Zend/Db/Adapter/Driver/Oci8/Oci8.php b/library/Zend/Db/Adapter/Driver/Oci8/Oci8.php old mode 100755 new mode 100644 diff --git a/library/Zend/Db/Adapter/Driver/Oci8/Result.php b/library/Zend/Db/Adapter/Driver/Oci8/Result.php old mode 100755 new mode 100644 index b993743f1..03111b9d4 --- a/library/Zend/Db/Adapter/Driver/Oci8/Result.php +++ b/library/Zend/Db/Adapter/Driver/Oci8/Result.php @@ -82,7 +82,7 @@ class Result implements Iterator, ResultInterface */ public function buffer() { - return null; + return; } /** @@ -202,7 +202,7 @@ class Result implements Iterator, ResultInterface public function count() { // @todo OCI8 row count in Driver Result - return null; + return; } /** @@ -219,6 +219,6 @@ class Result implements Iterator, ResultInterface public function getGeneratedValue() { // @todo OCI8 generated value in Driver Result - return null; + return; } } diff --git a/library/Zend/Db/Adapter/Driver/Oci8/Statement.php b/library/Zend/Db/Adapter/Driver/Oci8/Statement.php index 15d5fb5b8..c14f83024 100644 --- a/library/Zend/Db/Adapter/Driver/Oci8/Statement.php +++ b/library/Zend/Db/Adapter/Driver/Oci8/Statement.php @@ -213,7 +213,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface /** * Execute * - * @param ParameterContainer $parameters + * @param null|array|ParameterContainer $parameters * @return mixed */ public function execute($parameters = null) @@ -305,7 +305,12 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface $type = SQLT_CHR; } - oci_bind_by_name($this->resource, $name, $value, -1, $type); + $maxLength = -1; + if ($this->parameterContainer->offsetHasMaxLength($name)) { + $maxLength = $this->parameterContainer->offsetGetMaxLength($name); + } + + oci_bind_by_name($this->resource, $name, $value, $maxLength, $type); } } } diff --git a/library/Zend/Db/Adapter/Driver/Pdo/Connection.php b/library/Zend/Db/Adapter/Driver/Pdo/Connection.php index 7a8bff4ca..6e5f22cf5 100644 --- a/library/Zend/Db/Adapter/Driver/Pdo/Connection.php +++ b/library/Zend/Db/Adapter/Driver/Pdo/Connection.php @@ -9,42 +9,21 @@ namespace Zend\Db\Adapter\Driver\Pdo; -use Zend\Db\Adapter\Driver\ConnectionInterface; +use Zend\Db\Adapter\Driver\AbstractConnection; use Zend\Db\Adapter\Exception; -use Zend\Db\Adapter\Profiler; -class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface +class Connection extends AbstractConnection { /** * @var Pdo */ protected $driver = null; - /** - * @var Profiler\ProfilerInterface - */ - protected $profiler = null; - - /** - * @var string - */ - protected $driverName = null; - - /** - * @var array - */ - protected $connectionParameters = array(); - /** * @var \PDO */ protected $resource = null; - /** - * @var bool - */ - protected $inTransaction = false; - /** * @var string */ @@ -53,7 +32,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface /** * Constructor * - * @param array|\PDO|null $connectionParameters + * @param array|\PDO|null $connectionParameters * @throws Exception\InvalidArgumentException */ public function __construct($connectionParameters = null) @@ -63,61 +42,35 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } elseif ($connectionParameters instanceof \PDO) { $this->setResource($connectionParameters); } elseif (null !== $connectionParameters) { - throw new Exception\InvalidArgumentException('$connection must be an array of parameters, a PDO object or null'); + throw new Exception\InvalidArgumentException( + '$connection must be an array of parameters, a PDO object or null' + ); } } /** * Set driver * - * @param Pdo $driver - * @return Connection + * @param Pdo $driver + * @return self */ public function setDriver(Pdo $driver) { $this->driver = $driver; + return $this; } /** - * @param Profiler\ProfilerInterface $profiler - * @return Connection - */ - public function setProfiler(Profiler\ProfilerInterface $profiler) - { - $this->profiler = $profiler; - return $this; - } - - /** - * @return null|Profiler\ProfilerInterface - */ - public function getProfiler() - { - return $this->profiler; - } - - /** - * Get driver name - * - * @return null|string - */ - public function getDriverName() - { - return $this->driverName; - } - - /** - * Set connection parameters - * - * @param array $connectionParameters - * @return void + * {@inheritDoc} */ public function setConnectionParameters(array $connectionParameters) { $this->connectionParameters = $connectionParameters; if (isset($connectionParameters['dsn'])) { - $this->driverName = substr($connectionParameters['dsn'], 0, + $this->driverName = substr( + $connectionParameters['dsn'], + 0, strpos($connectionParameters['dsn'], ':') ); } elseif (isset($connectionParameters['pdodriver'])) { @@ -130,16 +83,6 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } } - /** - * Get connection parameters - * - * @return array - */ - public function getConnectionParameters() - { - return $this->connectionParameters; - } - /** * Get the dsn string for this connection * @throws \Zend\Db\Adapter\Exception\RunTimeException @@ -148,16 +91,16 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface public function getDsn() { if (!$this->dsn) { - throw new Exception\RunTimeException("The DSN has not been set or constructed from parameters in connect() for this Connection"); + throw new Exception\RunTimeException( + 'The DSN has not been set or constructed from parameters in connect() for this Connection' + ); } return $this->dsn; } /** - * Get current schema - * - * @return string + * {@inheritDoc} */ public function getCurrentSchema() { @@ -186,6 +129,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface if ($result instanceof \PDOStatement) { return $result->fetchColumn(); } + return false; } @@ -193,32 +137,19 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface * Set resource * * @param \PDO $resource - * @return Connection + * @return self */ public function setResource(\PDO $resource) { $this->resource = $resource; $this->driverName = strtolower($this->resource->getAttribute(\PDO::ATTR_DRIVER_NAME)); + return $this; } /** - * Get resource + * {@inheritDoc} * - * @return \PDO - */ - public function getResource() - { - if (!$this->isConnected()) { - $this->connect(); - } - return $this->resource; - } - - /** - * Connect - * - * @return Connection * @throws Exception\InvalidConnectionParametersException * @throws Exception\RuntimeException */ @@ -236,9 +167,11 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $dsn = $value; break; case 'driver': - $value = strtolower($value); + $value = strtolower((string) $value); if (strpos($value, 'pdo') === 0) { - $pdoDriver = strtolower(substr(str_replace(array('-', '_', ' '), '', $value), 3)); + $pdoDriver = str_replace(array('-', '_', ' '), '', $value); + $pdoDriver = substr($pdoDriver, 3) ?: ''; + $pdoDriver = strtolower($pdoDriver); } break; case 'pdodriver': @@ -335,9 +268,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Is connected - * - * @return bool + * {@inheritDoc} */ public function isConnected() { @@ -345,47 +276,26 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Disconnect - * - * @return Connection - */ - public function disconnect() - { - if ($this->isConnected()) { - $this->resource = null; - } - return $this; - } - - /** - * Begin transaction - * - * @return Connection + * {@inheritDoc} */ public function beginTransaction() { if (!$this->isConnected()) { $this->connect(); } - $this->resource->beginTransaction(); - $this->inTransaction = true; + + if (0 === $this->nestedTransactionsCount) { + $this->resource->beginTransaction(); + $this->inTransaction = true; + } + + $this->nestedTransactionsCount ++; + return $this; } /** - * In transaction - * - * @return bool - */ - public function inTransaction() - { - return $this->inTransaction; - } - - /** - * Commit - * - * @return Connection + * {@inheritDoc} */ public function commit() { @@ -393,15 +303,25 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $this->connect(); } - $this->resource->commit(); - $this->inTransaction = false; + if ($this->inTransaction) { + $this->nestedTransactionsCount -= 1; + } + + /* + * This shouldn't check for being in a transaction since + * after issuing a SET autocommit=0; we have to commit too. + */ + if (0 === $this->nestedTransactionsCount) { + $this->resource->commit(); + $this->inTransaction = false; + } + return $this; } /** - * Rollback + * {@inheritDoc} * - * @return Connection * @throws Exception\RuntimeException */ public function rollback() @@ -410,19 +330,21 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface throw new Exception\RuntimeException('Must be connected before you can rollback'); } - if (!$this->inTransaction) { + if (!$this->inTransaction()) { throw new Exception\RuntimeException('Must call beginTransaction() before you can rollback'); } $this->resource->rollBack(); + + $this->inTransaction = false; + $this->nestedTransactionsCount = 0; + return $this; } /** - * Execute + * {@inheritDoc} * - * @param $sql - * @return Result * @throws Exception\InvalidQueryException */ public function execute($sql) @@ -447,13 +369,14 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $result = $this->driver->createResult($resultResource, $sql); + return $result; } /** * Prepare * - * @param string $sql + * @param string $sql * @return Statement */ public function prepare($sql) @@ -463,19 +386,20 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $statement = $this->driver->createStatement($sql); + return $statement; } /** - * Get last generated id + * {@inheritDoc} * - * @param string $name + * @param string $name * @return string|null|false */ public function getLastGeneratedValue($name = null) { if ($name === null && $this->driverName == 'pgsql') { - return null; + return; } try { @@ -483,6 +407,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } catch (\Exception $e) { // do nothing } + return false; } } diff --git a/library/Zend/Db/Adapter/Driver/Pdo/Feature/OracleRowCounter.php b/library/Zend/Db/Adapter/Driver/Pdo/Feature/OracleRowCounter.php index 1f62aa6ec..199949a98 100644 --- a/library/Zend/Db/Adapter/Driver/Pdo/Feature/OracleRowCounter.php +++ b/library/Zend/Db/Adapter/Driver/Pdo/Feature/OracleRowCounter.php @@ -34,7 +34,7 @@ class OracleRowCounter extends AbstractFeature $countStmt = clone $statement; $sql = $statement->getSql(); if ($sql == '' || stripos($sql, 'select') === false) { - return null; + return; } $countSql = 'SELECT COUNT(*) as "count" FROM (' . $sql . ')'; $countStmt->prepare($countSql); @@ -51,7 +51,7 @@ class OracleRowCounter extends AbstractFeature public function getCountForSql($sql) { if (stripos($sql, 'select') === false) { - return null; + return; } $countSql = 'SELECT COUNT(*) as count FROM (' . $sql . ')'; /** @var $pdo \PDO */ diff --git a/library/Zend/Db/Adapter/Driver/Pdo/Feature/SqliteRowCounter.php b/library/Zend/Db/Adapter/Driver/Pdo/Feature/SqliteRowCounter.php index 2a73c663e..9f795fef6 100644 --- a/library/Zend/Db/Adapter/Driver/Pdo/Feature/SqliteRowCounter.php +++ b/library/Zend/Db/Adapter/Driver/Pdo/Feature/SqliteRowCounter.php @@ -34,7 +34,7 @@ class SqliteRowCounter extends AbstractFeature $countStmt = clone $statement; $sql = $statement->getSql(); if ($sql == '' || stripos($sql, 'select') === false) { - return null; + return; } $countSql = 'SELECT COUNT(*) as "count" FROM (' . $sql . ')'; $countStmt->prepare($countSql); @@ -51,7 +51,7 @@ class SqliteRowCounter extends AbstractFeature public function getCountForSql($sql) { if (stripos($sql, 'select') === false) { - return null; + return; } $countSql = 'SELECT COUNT(*) as count FROM (' . $sql . ')'; /** @var $pdo \PDO */ diff --git a/library/Zend/Db/Adapter/Driver/Pdo/Result.php b/library/Zend/Db/Adapter/Driver/Pdo/Result.php index 613abb12b..478362328 100644 --- a/library/Zend/Db/Adapter/Driver/Pdo/Result.php +++ b/library/Zend/Db/Adapter/Driver/Pdo/Result.php @@ -26,7 +26,12 @@ class Result implements Iterator, ResultInterface protected $statementMode = self::STATEMENT_MODE_FORWARD; /** - * @var \PDOStatement + * @var int + */ + protected $fetchMode = \PDO::FETCH_ASSOC; + + /** + * @var PDOStatement */ protected $resource = null; @@ -85,7 +90,7 @@ class Result implements Iterator, ResultInterface */ public function buffer() { - return null; + return; } /** @@ -96,6 +101,29 @@ class Result implements Iterator, ResultInterface return false; } + /** + * @param int $fetchMode + * @throws Exception\InvalidArgumentException on invalid fetch mode + */ + public function setFetchMode($fetchMode) + { + if ($fetchMode < 1 || $fetchMode > 10) { + throw new Exception\InvalidArgumentException( + 'The fetch mode must be one of the PDO::FETCH_* constants.' + ); + } + + $this->fetchMode = (int) $fetchMode; + } + + /** + * @return int + */ + public function getFetchMode() + { + return $this->fetchMode; + } + /** * Get resource * @@ -116,7 +144,7 @@ class Result implements Iterator, ResultInterface return $this->currentData; } - $this->currentData = $this->resource->fetch(\PDO::FETCH_ASSOC); + $this->currentData = $this->resource->fetch($this->fetchMode); $this->currentComplete = true; return $this->currentData; } @@ -128,7 +156,7 @@ class Result implements Iterator, ResultInterface */ public function next() { - $this->currentData = $this->resource->fetch(\PDO::FETCH_ASSOC); + $this->currentData = $this->resource->fetch($this->fetchMode); $this->currentComplete = true; $this->position++; return $this->currentData; @@ -155,7 +183,7 @@ class Result implements Iterator, ResultInterface 'This result is a forward only result set, calling rewind() after moving forward is not supported' ); } - $this->currentData = $this->resource->fetch(\PDO::FETCH_ASSOC); + $this->currentData = $this->resource->fetch($this->fetchMode); $this->currentComplete = true; $this->position = 0; } diff --git a/library/Zend/Db/Adapter/Driver/Pdo/Statement.php b/library/Zend/Db/Adapter/Driver/Pdo/Statement.php index 244863984..730ee8540 100644 --- a/library/Zend/Db/Adapter/Driver/Pdo/Statement.php +++ b/library/Zend/Db/Adapter/Driver/Pdo/Statement.php @@ -202,7 +202,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface } /** - * @param mixed $parameters + * @param null|array|ParameterContainer $parameters * @throws Exception\InvalidQueryException * @return Result */ diff --git a/library/Zend/Db/Adapter/Driver/Pgsql/Connection.php b/library/Zend/Db/Adapter/Driver/Pgsql/Connection.php index 8aa80819c..762a50041 100644 --- a/library/Zend/Db/Adapter/Driver/Pgsql/Connection.php +++ b/library/Zend/Db/Adapter/Driver/Pgsql/Connection.php @@ -9,41 +9,16 @@ namespace Zend\Db\Adapter\Driver\Pgsql; -use Zend\Db\Adapter\Driver\ConnectionInterface; +use Zend\Db\Adapter\Driver\AbstractConnection; use Zend\Db\Adapter\Exception; -use Zend\Db\Adapter\Profiler; -class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface +class Connection extends AbstractConnection { /** * @var Pgsql */ protected $driver = null; - /** - * @var Profiler\ProfilerInterface - */ - protected $profiler = null; - - /** - * Connection parameters - * - * @var array - */ - protected $connectionParameters = array(); - - /** - * @var resource - */ - protected $resource = null; - - /** - * In transaction - * - * @var bool - */ - protected $inTransaction = false; - /** * Constructor * @@ -58,62 +33,21 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } } - /** - * Set connection parameters - * - * @param array $connectionParameters - * @return Connection - */ - public function setConnectionParameters(array $connectionParameters) - { - $this->connectionParameters = $connectionParameters; - return $this; - } - /** * Set driver * * @param Pgsql $driver - * @return Connection + * @return self */ public function setDriver(Pgsql $driver) { $this->driver = $driver; + return $this; } /** - * @param Profiler\ProfilerInterface $profiler - * @return Connection - */ - public function setProfiler(Profiler\ProfilerInterface $profiler) - { - $this->profiler = $profiler; - return $this; - } - - /** - * @return null|Profiler\ProfilerInterface - */ - public function getProfiler() - { - return $this->profiler; - } - - /** - * Set resource - * - * @param resource $resource - * @return Connection - */ - public function setResource($resource) - { - $this->resource = $resource; - return; - } - - /** - * Get current schema + * {@inheritDoc} * * @return null|string */ @@ -125,28 +59,15 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $result = pg_query($this->resource, 'SELECT CURRENT_SCHEMA AS "currentschema"'); if ($result == false) { - return null; + return; } + return pg_fetch_result($result, 0, 'currentschema'); } /** - * Get resource + * {@inheritDoc} * - * @return resource - */ - public function getResource() - { - if (!$this->isConnected()) { - $this->connect(); - } - return $this->resource; - } - - /** - * Connect to the database - * - * @return Connection * @throws Exception\RuntimeException on failure */ public function connect() @@ -175,7 +96,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * @return bool + * {@inheritDoc} */ public function isConnected() { @@ -183,7 +104,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * @return void + * {@inheritDoc} */ public function disconnect() { @@ -191,11 +112,11 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * @return void + * {@inheritDoc} */ public function beginTransaction() { - if ($this->inTransaction) { + if ($this->inTransaction()) { throw new Exception\RuntimeException('Nested transactions are not supported'); } @@ -205,46 +126,51 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface pg_query($this->resource, 'BEGIN'); $this->inTransaction = true; + + return $this; } /** - * In transaction - * - * @return bool - */ - public function inTransaction() - { - return $this->inTransaction; - } - - /** - * @return void + * {@inheritDoc} */ public function commit() { - if (!$this->inTransaction) { + if (!$this->isConnected()) { + $this->connect(); + } + + if (!$this->inTransaction()) { return; // We ignore attempts to commit non-existing transaction } pg_query($this->resource, 'COMMIT'); $this->inTransaction = false; + + return $this; } /** - * @return void + * {@inheritDoc} */ public function rollback() { - if (!$this->inTransaction) { - return; + if (!$this->isConnected()) { + throw new Exception\RuntimeException('Must be connected before you can rollback'); + } + + if (!$this->inTransaction()) { + throw new Exception\RuntimeException('Must call beginTransaction() before you can rollback'); } pg_query($this->resource, 'ROLLBACK'); $this->inTransaction = false; + + return $this; } /** - * @param string $sql + * {@inheritDoc} + * * @throws Exception\InvalidQueryException * @return resource|\Zend\Db\ResultSet\ResultSetInterface */ @@ -270,19 +196,22 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $resultPrototype = $this->driver->createResult(($resultResource === true) ? $this->resource : $resultResource); + return $resultPrototype; } /** - * @param null $name Ignored + * {@inheritDoc} + * * @return string */ public function getLastGeneratedValue($name = null) { if ($name == null) { - return null; + return; } $result = pg_query($this->resource, 'SELECT CURRVAL(\'' . str_replace('\'', '\\\'', $name) . '\') as "currval"'); + return pg_fetch_result($result, 0, 'currval'); } @@ -303,7 +232,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface return $p[$name]; } } - return null; + return; }; $connectionParameters = array( diff --git a/library/Zend/Db/Adapter/Driver/Pgsql/Result.php b/library/Zend/Db/Adapter/Driver/Pgsql/Result.php index a37391468..a19f226ef 100644 --- a/library/Zend/Db/Adapter/Driver/Pgsql/Result.php +++ b/library/Zend/Db/Adapter/Driver/Pgsql/Result.php @@ -113,7 +113,7 @@ class Result implements ResultInterface */ public function buffer() { - return null; + return; } /** diff --git a/library/Zend/Db/Adapter/Driver/Pgsql/Statement.php b/library/Zend/Db/Adapter/Driver/Pgsql/Statement.php index c58a70559..a0dc26f79 100644 --- a/library/Zend/Db/Adapter/Driver/Pgsql/Statement.php +++ b/library/Zend/Db/Adapter/Driver/Pgsql/Statement.php @@ -168,7 +168,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface $pCount = 1; $sql = preg_replace_callback( - '#\$\##', function ($foo) use (&$pCount) { + '#\$\##', function () use (&$pCount) { return '$' . $pCount++; }, $sql @@ -192,7 +192,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface /** * Execute * - * @param ParameterContainer|null $parameters + * @param null|array|ParameterContainer $parameters * @throws Exception\InvalidQueryException * @return Result */ diff --git a/library/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php b/library/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php index 9fcd36754..7ce54d90b 100644 --- a/library/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php +++ b/library/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php @@ -9,42 +9,21 @@ namespace Zend\Db\Adapter\Driver\Sqlsrv; -use Zend\Db\Adapter\Driver\ConnectionInterface; +use Zend\Db\Adapter\Driver\AbstractConnection; use Zend\Db\Adapter\Driver\Sqlsrv\Exception\ErrorException; use Zend\Db\Adapter\Exception; -use Zend\Db\Adapter\Profiler; -class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface +class Connection extends AbstractConnection { /** * @var Sqlsrv */ protected $driver = null; - /** - * @var Profiler\ProfilerInterface - */ - protected $profiler = null; - - /** - * @var array - */ - protected $connectionParameters = array(); - - /** - * @var resource - */ - protected $resource = null; - - /** - * @var bool - */ - protected $inTransaction = false; - /** * Constructor * - * @param array|resource $connectionInfo + * @param array|resource $connectionInfo * @throws \Zend\Db\Adapter\Exception\InvalidArgumentException */ public function __construct($connectionInfo) @@ -62,58 +41,17 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface * Set driver * * @param Sqlsrv $driver - * @return Connection + * @return self */ public function setDriver(Sqlsrv $driver) { $this->driver = $driver; + return $this; } /** - * @param Profiler\ProfilerInterface $profiler - * @return Connection - */ - public function setProfiler(Profiler\ProfilerInterface $profiler) - { - $this->profiler = $profiler; - return $this; - } - - /** - * @return null|Profiler\ProfilerInterface - */ - public function getProfiler() - { - return $this->profiler; - } - - /** - * Set connection parameters - * - * @param array $connectionParameters - * @return Connection - */ - public function setConnectionParameters(array $connectionParameters) - { - $this->connectionParameters = $connectionParameters; - return $this; - } - - /** - * Get connection parameters - * - * @return array - */ - public function getConnectionParameters() - { - return $this->connectionParameters; - } - - /** - * Get current schema - * - * @return string + * {@inheritDoc} */ public function getCurrentSchema() { @@ -123,15 +61,16 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $result = sqlsrv_query($this->resource, 'SELECT SCHEMA_NAME()'); $r = sqlsrv_fetch_array($result); + return $r[0]; } /** * Set resource * - * @param resource $resource + * @param resource $resource * @throws Exception\InvalidArgumentException - * @return Connection + * @return self */ public function setResource($resource) { @@ -139,25 +78,14 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface throw new Exception\InvalidArgumentException('Resource provided was not of type SQL Server Connection'); } $this->resource = $resource; + return $this; } /** - * @return resource - */ - public function getResource() - { - if (!$this->isConnected()) { - $this->connect(); - } - return $this->resource; - } - - /** - * Connect + * {@inheritDoc} * * @throws Exception\RuntimeException - * @return Connection */ public function connect() { @@ -212,8 +140,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Is connected - * @return bool + * {@inheritDoc} */ public function isConnected() { @@ -221,7 +148,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Disconnect + * {@inheritDoc} */ public function disconnect() { @@ -230,70 +157,64 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } /** - * Begin transaction + * {@inheritDoc} */ public function beginTransaction() { - if (!$this->resource) { + if (!$this->isConnected()) { $this->connect(); } + if (sqlsrv_begin_transaction($this->resource) === false) { throw new Exception\RuntimeException( - 'Begin transaction failed', - null, new ErrorException(sqlsrv_errors()) ); } $this->inTransaction = true; + + return $this; } /** - * In transaction - * - * @return bool - */ - public function inTransaction() - { - return $this->inTransaction; - } - - /** - * Commit + * {@inheritDoc} */ public function commit() { // http://msdn.microsoft.com/en-us/library/cc296194.aspx - if (!$this->resource) { + if (!$this->isConnected()) { $this->connect(); } + sqlsrv_commit($this->resource); + $this->inTransaction = false; - return sqlsrv_commit($this->resource); + return $this; } /** - * Rollback + * {@inheritDoc} */ public function rollback() { // http://msdn.microsoft.com/en-us/library/cc296176.aspx - if (!$this->resource) { + if (!$this->isConnected()) { throw new Exception\RuntimeException('Must be connected before you can rollback.'); } - return sqlsrv_rollback($this->resource); + sqlsrv_rollback($this->resource); + $this->inTransaction = false; + + return $this; } /** - * Execute + * {@inheritDoc} * - * @param string $sql * @throws Exception\RuntimeException - * @return mixed */ public function execute($sql) { @@ -329,6 +250,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $result = $this->driver->createResult($returnValue); + return $result; } @@ -345,13 +267,13 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface } $statement = $this->driver->createStatement($sql); + return $statement; } /** - * Get last generated id + * {@inheritDoc} * - * @param string $name * @return mixed */ public function getLastGeneratedValue($name = null) @@ -362,6 +284,7 @@ class Connection implements ConnectionInterface, Profiler\ProfilerAwareInterface $sql = 'SELECT @@IDENTITY as Current_Identity'; $result = sqlsrv_query($this->resource, $sql); $row = sqlsrv_fetch_array($result); + return $row['Current_Identity']; } } diff --git a/library/Zend/Db/Adapter/Driver/Sqlsrv/Result.php b/library/Zend/Db/Adapter/Driver/Sqlsrv/Result.php index dafefbfde..4edef486d 100644 --- a/library/Zend/Db/Adapter/Driver/Sqlsrv/Result.php +++ b/library/Zend/Db/Adapter/Driver/Sqlsrv/Result.php @@ -60,7 +60,7 @@ class Result implements Iterator, ResultInterface */ public function buffer() { - return null; + return; } /** diff --git a/library/Zend/Db/Adapter/Driver/Sqlsrv/Sqlsrv.php b/library/Zend/Db/Adapter/Driver/Sqlsrv/Sqlsrv.php old mode 100755 new mode 100644 diff --git a/library/Zend/Db/Adapter/Driver/Sqlsrv/Statement.php b/library/Zend/Db/Adapter/Driver/Sqlsrv/Statement.php index c0b83ff11..0a40bc58a 100644 --- a/library/Zend/Db/Adapter/Driver/Sqlsrv/Statement.php +++ b/library/Zend/Db/Adapter/Driver/Sqlsrv/Statement.php @@ -231,7 +231,7 @@ class Statement implements StatementInterface, Profiler\ProfilerAwareInterface /** * Execute * - * @param array|ParameterContainer $parameters + * @param null|array|ParameterContainer $parameters * @throws Exception\RuntimeException * @return Result */ diff --git a/library/Zend/Db/Adapter/Driver/StatementInterface.php b/library/Zend/Db/Adapter/Driver/StatementInterface.php index 6c9e8858a..e18c364a4 100644 --- a/library/Zend/Db/Adapter/Driver/StatementInterface.php +++ b/library/Zend/Db/Adapter/Driver/StatementInterface.php @@ -9,6 +9,7 @@ namespace Zend\Db\Adapter\Driver; +use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\StatementContainerInterface; interface StatementInterface extends StatementContainerInterface @@ -37,7 +38,7 @@ interface StatementInterface extends StatementContainerInterface /** * Execute * - * @param null $parameters + * @param null|array|ParameterContainer $parameters * @return ResultInterface */ public function execute($parameters = null); diff --git a/library/Zend/Db/Adapter/ParameterContainer.php b/library/Zend/Db/Adapter/ParameterContainer.php index e3e9228c7..9c180b8fb 100644 --- a/library/Zend/Db/Adapter/ParameterContainer.php +++ b/library/Zend/Db/Adapter/ParameterContainer.php @@ -42,6 +42,13 @@ class ParameterContainer implements Iterator, ArrayAccess, Countable */ protected $errata = array(); + /** + * Max length + * + * @var array + */ + protected $maxLength = array(); + /** * Constructor * @@ -91,8 +98,10 @@ class ParameterContainer implements Iterator, ArrayAccess, Countable * @param string|int $name * @param mixed $value * @param mixed $errata + * @param mixed $maxLength + * @throws Exception\InvalidArgumentException */ - public function offsetSet($name, $value, $errata = null) + public function offsetSet($name, $value, $errata = null, $maxLength = null) { $position = false; @@ -122,6 +131,10 @@ class ParameterContainer implements Iterator, ArrayAccess, Countable if ($errata) { $this->offsetSetErrata($name, $errata); } + + if ($maxLength) { + $this->offsetSetMaxLength($name, $maxLength); + } } /** @@ -153,6 +166,79 @@ class ParameterContainer implements Iterator, ArrayAccess, Countable return $this; } + /** + * Offset set max length + * + * @param string|int $name + * @param mixed $maxLength + */ + public function offsetSetMaxLength($name, $maxLength) + { + if (is_int($name)) { + $name = $this->positions[$name]; + } + $this->maxLength[$name] = $maxLength; + } + + /** + * Offset get max length + * + * @param string|int $name + * @throws Exception\InvalidArgumentException + * @return mixed + */ + public function offsetGetMaxLength($name) + { + if (is_int($name)) { + $name = $this->positions[$name]; + } + if (!array_key_exists($name, $this->data)) { + throw new Exception\InvalidArgumentException('Data does not exist for this name/position'); + } + return $this->maxLength[$name]; + } + + /** + * Offset has max length + * + * @param string|int $name + * @return bool + */ + public function offsetHasMaxLength($name) + { + if (is_int($name)) { + $name = $this->positions[$name]; + } + return (isset($this->maxLength[$name])); + } + + /** + * Offset unset max length + * + * @param string|int $name + * @throws Exception\InvalidArgumentException + */ + public function offsetUnsetMaxLength($name) + { + if (is_int($name)) { + $name = $this->positions[$name]; + } + if (!array_key_exists($name, $this->maxLength)) { + throw new Exception\InvalidArgumentException('Data does not exist for this name/position'); + } + $this->maxLength[$name] = null; + } + + /** + * Get max length iterator + * + * @return \ArrayIterator + */ + public function getMaxLengthIterator() + { + return new \ArrayIterator($this->maxLength); + } + /** * Offset set errata * diff --git a/library/Zend/Db/Adapter/Platform/AbstractPlatform.php b/library/Zend/Db/Adapter/Platform/AbstractPlatform.php new file mode 100644 index 000000000..44d0d5c71 --- /dev/null +++ b/library/Zend/Db/Adapter/Platform/AbstractPlatform.php @@ -0,0 +1,137 @@ +quoteIdentifiers) { + return $identifier; + } + + $safeWordsInt = array('*' => true, ' ' => true, '.' => true, 'as' => true); + + foreach ($safeWords as $sWord) { + $safeWordsInt[strtolower($sWord)] = true; + } + + $parts = preg_split( + '/([^0-9,a-z,A-Z$_:])/i', + $identifier, + -1, + PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY + ); + + $identifier = ''; + + foreach ($parts as $part) { + $identifier .= isset($safeWordsInt[strtolower($part)]) + ? $part + : $this->quoteIdentifier[0] + . str_replace($this->quoteIdentifier[0], $this->quoteIdentifierTo, $part) + . $this->quoteIdentifier[1]; + } + + return $identifier; + } + + /** + * {@inheritDoc} + */ + public function quoteIdentifier($identifier) + { + if (! $this->quoteIdentifiers) { + return $identifier; + } + + return $this->quoteIdentifier[0] + . str_replace($this->quoteIdentifier[0], $this->quoteIdentifierTo, $identifier) + . $this->quoteIdentifier[1]; + } + + /** + * {@inheritDoc} + */ + public function quoteIdentifierChain($identifierChain) + { + return '"' . implode('"."', (array) str_replace('"', '\\"', $identifierChain)) . '"'; + } + + /** + * {@inheritDoc} + */ + public function getQuoteIdentifierSymbol() + { + return $this->quoteIdentifier[0]; + } + + /** + * {@inheritDoc} + */ + public function getQuoteValueSymbol() + { + return '\''; + } + + /** + * {@inheritDoc} + */ + public function quoteValue($value) + { + trigger_error( + 'Attempting to quote a value in ' . get_class($this) . + ' without extension/driver support can introduce security vulnerabilities in a production environment' + ); + return '\'' . addcslashes((string) $value, "\x00\n\r\\'\"\x1a") . '\''; + } + + /** + * {@inheritDoc} + */ + public function quoteTrustedValue($value) + { + return '\'' . addcslashes((string) $value, "\x00\n\r\\'\"\x1a") . '\''; + } + + /** + * {@inheritDoc} + */ + public function quoteValueList($valueList) + { + return implode(', ', array_map(array($this, 'quoteValue'), (array) $valueList)); + } + + /** + * {@inheritDoc} + */ + public function getIdentifierSeparator() + { + return '.'; + } +} diff --git a/library/Zend/Db/Adapter/Platform/IbmDb2.php b/library/Zend/Db/Adapter/Platform/IbmDb2.php old mode 100755 new mode 100644 index 182600c2d..4f6ea19e6 --- a/library/Zend/Db/Adapter/Platform/IbmDb2.php +++ b/library/Zend/Db/Adapter/Platform/IbmDb2.php @@ -9,15 +9,8 @@ namespace Zend\Db\Adapter\Platform; -class IbmDb2 implements PlatformInterface +class IbmDb2 extends AbstractPlatform { - protected $quoteValueAllowed = false; - - /** - * @var bool - */ - protected $quoteIdentifiers = true; - /** * @var string */ @@ -41,9 +34,7 @@ class IbmDb2 implements PlatformInterface } /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -51,34 +42,7 @@ class IbmDb2 implements PlatformInterface } /** - * Get quote indentifier symbol - * - * @return string - */ - public function getQuoteIdentifierSymbol() - { - return '"'; - } - - /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - if ($this->quoteIdentifiers === false) { - return $identifier; - } - return '"' . str_replace('"', '\\' . '"', $identifier) . '"'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string + * {@inheritDoc} */ public function quoteIdentifierChain($identifierChain) { @@ -93,20 +57,7 @@ class IbmDb2 implements PlatformInterface } /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { @@ -121,12 +72,7 @@ class IbmDb2 implements PlatformInterface } /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed + * {@inheritDoc} */ public function quoteTrustedValue($value) { @@ -137,71 +83,10 @@ class IbmDb2 implements PlatformInterface } /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string + * {@inheritDoc} */ public function getIdentifierSeparator() { return $this->identifierSeparator; } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - if ($this->quoteIdentifiers === false) { - return $identifier; - } - $parts = preg_split('#([\.\s\W])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '"' . str_replace('"', '\\' . '"', $part) . '"'; - } - } - - return implode('', $parts); - } } diff --git a/library/Zend/Db/Adapter/Platform/Mysql.php b/library/Zend/Db/Adapter/Platform/Mysql.php index 366901cd6..42fc769bb 100644 --- a/library/Zend/Db/Adapter/Platform/Mysql.php +++ b/library/Zend/Db/Adapter/Platform/Mysql.php @@ -14,11 +14,26 @@ use Zend\Db\Adapter\Driver\Mysqli; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; -class Mysql implements PlatformInterface +class Mysql extends AbstractPlatform { - /** @var \mysqli|\PDO */ + /** + * {@inheritDoc} + */ + protected $quoteIdentifier = array('`', '`'); + + /** + * {@inheritDoc} + */ + protected $quoteIdentifierTo = '``'; + + /** + * @var \mysqli|\PDO + */ protected $resource = null; + /** + * @param null|\Zend\Db\Adapter\Driver\Mysqli\Mysqli|\Zend\Db\Adapter\Driver\Pdo\Pdo|\mysqli|\PDO $driver + */ public function __construct($driver = null) { if ($driver) { @@ -27,9 +42,10 @@ class Mysql implements PlatformInterface } /** - * @param \Zend\Db\Adapter\Driver\Mysqli\Mysqli|\Zend\Db\Adapter\Driver\Pdo\Pdo||\mysqli|\PDO $driver + * @param \Zend\Db\Adapter\Driver\Mysqli\Mysqli|\Zend\Db\Adapter\Driver\Pdo\Pdo|\mysqli|\PDO $driver * @throws \Zend\Db\Adapter\Exception\InvalidArgumentException - * @return $this + * + * @return self */ public function setDriver($driver) { @@ -47,9 +63,7 @@ class Mysql implements PlatformInterface } /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -57,56 +71,15 @@ class Mysql implements PlatformInterface } /** - * Get quote identifier symbol - * - * @return string - */ - public function getQuoteIdentifierSymbol() - { - return '`'; - } - - /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - return '`' . str_replace('`', '``', $identifier) . '`'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string + * {@inheritDoc} */ public function quoteIdentifierChain($identifierChain) { - $identifierChain = str_replace('`', '``', $identifierChain); - if (is_array($identifierChain)) { - $identifierChain = implode('`.`', $identifierChain); - } - return '`' . $identifierChain . '`'; + return '`' . implode('`.`', (array) str_replace('`', '``', $identifierChain)) . '`'; } /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { @@ -119,20 +92,11 @@ class Mysql implements PlatformInterface if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } - trigger_error( - 'Attempting to quote a value in ' . __CLASS__ . ' without extension/driver support ' - . 'can introduce security vulnerabilities in a production environment.' - ); - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; + return parent::quoteValue($value); } /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed + * {@inheritDoc} */ public function quoteTrustedValue($value) { @@ -145,70 +109,6 @@ class Mysql implements PlatformInterface if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; - } - - /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string - */ - public function getIdentifierSeparator() - { - return '.'; - } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - // regex taken from @link http://dev.mysql.com/doc/refman/5.0/en/identifiers.html - $parts = preg_split('#([^0-9,a-z,A-Z$_])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '`' . str_replace('`', '``', $part) . '`'; - } - } - return implode('', $parts); + return parent::quoteTrustedValue($value); } } diff --git a/library/Zend/Db/Adapter/Platform/Oracle.php b/library/Zend/Db/Adapter/Platform/Oracle.php old mode 100755 new mode 100644 index 24390c8dd..cb64ab34e --- a/library/Zend/Db/Adapter/Platform/Oracle.php +++ b/library/Zend/Db/Adapter/Platform/Oracle.php @@ -9,13 +9,8 @@ namespace Zend\Db\Adapter\Platform; -class Oracle implements PlatformInterface +class Oracle extends AbstractPlatform { - /** - * @var bool - */ - protected $quoteIdentifiers = true; - /** * @param array $options */ @@ -30,9 +25,7 @@ class Oracle implements PlatformInterface } /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -40,62 +33,19 @@ class Oracle implements PlatformInterface } /** - * Get quote identifier symbol - * - * @return string - */ - public function getQuoteIdentifierSymbol() - { - return '"'; - } - - /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - if ($this->quoteIdentifiers === false) { - return $identifier; - } - return '"' . str_replace('"', '\\' . '"', $identifier) . '"'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string + * {@inheritDoc} */ public function quoteIdentifierChain($identifierChain) { if ($this->quoteIdentifiers === false) { - return (is_array($identifierChain)) ? implode('.', $identifierChain) : $identifierChain; + return implode('.', (array) $identifierChain); } - $identifierChain = str_replace('"', '\\"', $identifierChain); - if (is_array($identifierChain)) { - $identifierChain = implode('"."', $identifierChain); - } - return '"' . $identifierChain . '"'; + + return '"' . implode('"."', (array) str_replace('"', '\\"', $identifierChain)) . '"'; } /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { @@ -103,85 +53,14 @@ class Oracle implements PlatformInterface 'Attempting to quote a value in ' . __CLASS__ . ' without extension/driver support ' . 'can introduce security vulnerabilities in a production environment.' ); - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; + return '\'' . addcslashes(str_replace('\'', '\'\'', $value), "\x00\n\r\"\x1a") . '\''; } /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed + * {@inheritDoc} */ public function quoteTrustedValue($value) { - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; - } - - /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string - */ - public function getIdentifierSeparator() - { - return '.'; - } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - if ($this->quoteIdentifiers === false) { - return $identifier; - } - $parts = preg_split('#([\.\s\W])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '"' . str_replace('"', '\\' . '"', $part) . '"'; - } - } - return implode('', $parts); + return '\'' . addcslashes(str_replace('\'', '\'\'', $value), "\x00\n\r\"\x1a") . '\''; } } diff --git a/library/Zend/Db/Adapter/Platform/Postgresql.php b/library/Zend/Db/Adapter/Platform/Postgresql.php index 07149febc..440e9a784 100644 --- a/library/Zend/Db/Adapter/Platform/Postgresql.php +++ b/library/Zend/Db/Adapter/Platform/Postgresql.php @@ -14,11 +14,23 @@ use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Driver\Pgsql; use Zend\Db\Adapter\Exception; -class Postgresql implements PlatformInterface +class Postgresql extends AbstractPlatform { - /** @var resource|\PDO */ + /** + * Overrides value from AbstractPlatform to use proper escaping for Postgres + * + * @var string + */ + protected $quoteIdentifierTo = '""'; + + /** + * @var resource|\PDO + */ protected $resource = null; + /** + * @param null|\Zend\Db\Adapter\Driver\Pgsql\Pgsql|\Zend\Db\Adapter\Driver\Pdo\Pdo|resource|\PDO $driver + */ public function __construct($driver = null) { if ($driver) { @@ -46,9 +58,7 @@ class Postgresql implements PlatformInterface } /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -56,56 +66,15 @@ class Postgresql implements PlatformInterface } /** - * Get quote indentifier symbol - * - * @return string - */ - public function getQuoteIdentifierSymbol() - { - return '"'; - } - - /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - return '"' . str_replace('"', '\\' . '"', $identifier) . '"'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string + * {@inheritDoc} */ public function quoteIdentifierChain($identifierChain) { - $identifierChain = str_replace('"', '\\"', $identifierChain); - if (is_array($identifierChain)) { - $identifierChain = implode('"."', $identifierChain); - } - return '"' . $identifierChain . '"'; + return '"' . implode('"."', (array) str_replace('"', '""', $identifierChain)) . '"'; } /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { @@ -118,20 +87,11 @@ class Postgresql implements PlatformInterface if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } - trigger_error( - 'Attempting to quote a value in ' . __CLASS__ . ' without extension/driver support ' - . 'can introduce security vulnerabilities in a production environment.' - ); - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; + return 'E' . parent::quoteValue($value); } /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed + * {@inheritDoc} */ public function quoteTrustedValue($value) { @@ -144,69 +104,6 @@ class Postgresql implements PlatformInterface if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; - } - - /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string - */ - public function getIdentifierSeparator() - { - return '.'; - } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - $parts = preg_split('#([\.\s\W])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '"' . str_replace('"', '\\' . '"', $part) . '"'; - } - } - return implode('', $parts); + return 'E' . parent::quoteTrustedValue($value); } } diff --git a/library/Zend/Db/Adapter/Platform/Sql92.php b/library/Zend/Db/Adapter/Platform/Sql92.php index 181956c55..afbe90d2d 100644 --- a/library/Zend/Db/Adapter/Platform/Sql92.php +++ b/library/Zend/Db/Adapter/Platform/Sql92.php @@ -9,12 +9,10 @@ namespace Zend\Db\Adapter\Platform; -class Sql92 implements PlatformInterface +class Sql92 extends AbstractPlatform { /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -22,140 +20,14 @@ class Sql92 implements PlatformInterface } /** - * Get quote indentifier symbol - * - * @return string - */ - public function getQuoteIdentifierSymbol() - { - return '"'; - } - - /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - return '"' . str_replace('"', '\\' . '"', $identifier) . '"'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string - */ - public function quoteIdentifierChain($identifierChain) - { - $identifierChain = str_replace('"', '\\"', $identifierChain); - if (is_array($identifierChain)) { - $identifierChain = implode('"."', $identifierChain); - } - return '"' . $identifierChain . '"'; - } - - /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { trigger_error( - 'Attempting to quote a value without specific driver level support can introduce security vulnerabilities in a production environment.' + 'Attempting to quote a value without specific driver level support' + . ' can introduce security vulnerabilities in a production environment.' ); return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; } - - /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed - */ - public function quoteTrustedValue($value) - { - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; - } - - /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string - */ - public function getIdentifierSeparator() - { - return '.'; - } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - $parts = preg_split('#([\.\s\W])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '"' . str_replace('"', '\\' . '"', $part) . '"'; - } - } - - return implode('', $parts); - } } diff --git a/library/Zend/Db/Adapter/Platform/SqlServer.php b/library/Zend/Db/Adapter/Platform/SqlServer.php old mode 100755 new mode 100644 index 3a21b3c47..5716c06b5 --- a/library/Zend/Db/Adapter/Platform/SqlServer.php +++ b/library/Zend/Db/Adapter/Platform/SqlServer.php @@ -13,11 +13,26 @@ use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; -class SqlServer implements PlatformInterface +class SqlServer extends AbstractPlatform { - /** @var resource|\PDO */ + /** + * {@inheritDoc} + */ + protected $quoteIdentifier = array('[',']'); + + /** + * {@inheritDoc} + */ + protected $quoteIdentifierTo = '\\'; + + /** + * @var resource|\PDO + */ protected $resource = null; + /** + * @param null|\Zend\Db\Adapter\Driver\Sqlsrv\Sqlsrv|\Zend\Db\Adapter\Driver\Pdo\Pdo|resource|\PDO $driver + */ public function __construct($driver = null) { if ($driver) { @@ -26,9 +41,10 @@ class SqlServer implements PlatformInterface } /** - * @param \Zend\Db\Adapter\Driver\Sqlsrv\Sqlsrv|\Zend\Db\Adapter\Driver\Pdo\Pdo||resource|\PDO $driver + * @param \Zend\Db\Adapter\Driver\Sqlsrv\Sqlsrv|\Zend\Db\Adapter\Driver\Pdo\Pdo|resource|\PDO $driver * @throws \Zend\Db\Adapter\Exception\InvalidArgumentException - * @return $this + * + * @return self */ public function setDriver($driver) { @@ -44,9 +60,7 @@ class SqlServer implements PlatformInterface } /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -54,55 +68,23 @@ class SqlServer implements PlatformInterface } /** - * Get quote identifier symbol - * - * @return string + * {@inheritDoc} */ public function getQuoteIdentifierSymbol() { - return array('[', ']'); + return $this->quoteIdentifier; } /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - return '[' . $identifier . ']'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string + * {@inheritDoc} */ public function quoteIdentifierChain($identifierChain) { - if (is_array($identifierChain)) { - $identifierChain = implode('].[', $identifierChain); - } - return '[' . $identifierChain . ']'; + return '[' . implode('].[', (array) $identifierChain) . ']'; } /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { @@ -116,17 +98,12 @@ class SqlServer implements PlatformInterface 'Attempting to quote a value in ' . __CLASS__ . ' without extension/driver support ' . 'can introduce security vulnerabilities in a production environment.' ); - $value = addcslashes($value, "\000\032"); - return '\'' . str_replace('\'', '\'\'', $value) . '\''; + + return '\'' . str_replace('\'', '\'\'', addcslashes($value, "\000\032")) . '\''; } /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed + * {@inheritDoc} */ public function quoteTrustedValue($value) { @@ -138,66 +115,4 @@ class SqlServer implements PlatformInterface } return '\'' . str_replace('\'', '\'\'', $value) . '\''; } - - /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string - */ - public function getIdentifierSeparator() - { - return '.'; - } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - $parts = preg_split('#([\.\s\W])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '[' . $part . ']'; - } - } - return implode('', $parts); - } } diff --git a/library/Zend/Db/Adapter/Platform/Sqlite.php b/library/Zend/Db/Adapter/Platform/Sqlite.php index 5ff195d99..46fece87c 100644 --- a/library/Zend/Db/Adapter/Platform/Sqlite.php +++ b/library/Zend/Db/Adapter/Platform/Sqlite.php @@ -13,11 +13,26 @@ use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; -class Sqlite implements PlatformInterface +class Sqlite extends AbstractPlatform { - /** @var \PDO */ + /** + * {@inheritDoc} + */ + protected $quoteIdentifier = array('"','"'); + + /** + * {@inheritDoc} + */ + protected $quoteIdentifierTo = '\''; + + /** + * @var \PDO + */ protected $resource = null; + /** + * @param null|\Zend\Db\Adapter\Driver\Pdo\Pdo||\PDO $driver + */ public function __construct($driver = null) { if ($driver) { @@ -26,9 +41,10 @@ class Sqlite implements PlatformInterface } /** - * @param \Zend\Db\Adapter\Driver\Pdo\Pdo||\PDO $driver + * @param \Zend\Db\Adapter\Driver\Pdo\Pdo|\PDO $driver * @throws \Zend\Db\Adapter\Exception\InvalidArgumentException - * @return $this + * + * @return self */ public function setDriver($driver) { @@ -43,9 +59,7 @@ class Sqlite implements PlatformInterface } /** - * Get name - * - * @return string + * {@inheritDoc} */ public function getName() { @@ -53,56 +67,7 @@ class Sqlite implements PlatformInterface } /** - * Get quote identifier symbol - * - * @return string - */ - public function getQuoteIdentifierSymbol() - { - return '"'; - } - - /** - * Quote identifier - * - * @param string $identifier - * @return string - */ - public function quoteIdentifier($identifier) - { - return '"' . str_replace('"', '\\' . '"', $identifier) . '"'; - } - - /** - * Quote identifier chain - * - * @param string|string[] $identifierChain - * @return string - */ - public function quoteIdentifierChain($identifierChain) - { - $identifierChain = str_replace('"', '\\"', $identifierChain); - if (is_array($identifierChain)) { - $identifierChain = implode('"."', $identifierChain); - } - return '"' . $identifierChain . '"'; - } - - /** - * Get quote value symbol - * - * @return string - */ - public function getQuoteValueSymbol() - { - return '\''; - } - - /** - * Quote value - * - * @param string $value - * @return string + * {@inheritDoc} */ public function quoteValue($value) { @@ -116,20 +81,11 @@ class Sqlite implements PlatformInterface return $resource->quote($value); } - trigger_error( - 'Attempting to quote a value in ' . __CLASS__ . ' without extension/driver support ' - . 'can introduce security vulnerabilities in a production environment.' - ); - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; + return parent::quoteValue($value); } /** - * Quote Trusted Value - * - * The ability to quote values without notices - * - * @param $value - * @return mixed + * {@inheritDoc} */ public function quoteTrustedValue($value) { @@ -143,68 +99,6 @@ class Sqlite implements PlatformInterface return $resource->quote($value); } - return '\'' . addcslashes($value, "\x00\n\r\\'\"\x1a") . '\''; - } - - /** - * Quote value list - * - * @param string|string[] $valueList - * @return string - */ - public function quoteValueList($valueList) - { - if (!is_array($valueList)) { - return $this->quoteValue($valueList); - } - $value = reset($valueList); - do { - $valueList[key($valueList)] = $this->quoteValue($value); - } while ($value = next($valueList)); - return implode(', ', $valueList); - } - - /** - * Get identifier separator - * - * @return string - */ - public function getIdentifierSeparator() - { - return '.'; - } - - /** - * Quote identifier in fragment - * - * @param string $identifier - * @param array $safeWords - * @return string - */ - public function quoteIdentifierInFragment($identifier, array $safeWords = array()) - { - $parts = preg_split('#([\.\s\W])#', $identifier, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if ($safeWords) { - $safeWords = array_flip($safeWords); - $safeWords = array_change_key_case($safeWords, CASE_LOWER); - } - foreach ($parts as $i => $part) { - if ($safeWords && isset($safeWords[strtolower($part)])) { - continue; - } - switch ($part) { - case ' ': - case '.': - case '*': - case 'AS': - case 'As': - case 'aS': - case 'as': - break; - default: - $parts[$i] = '"' . str_replace('"', '\\' . '"', $part) . '"'; - } - } - return implode('', $parts); + return parent::quoteTrustedValue($value); } } diff --git a/library/Zend/Db/Adapter/Profiler/ProfilerAwareInterface.php b/library/Zend/Db/Adapter/Profiler/ProfilerAwareInterface.php index d6473713c..a45e6fb76 100644 --- a/library/Zend/Db/Adapter/Profiler/ProfilerAwareInterface.php +++ b/library/Zend/Db/Adapter/Profiler/ProfilerAwareInterface.php @@ -11,5 +11,8 @@ namespace Zend\Db\Adapter\Profiler; interface ProfilerAwareInterface { + /** + * @param ProfilerInterface $profiler + */ public function setProfiler(ProfilerInterface $profiler); } diff --git a/library/Zend/Db/Metadata/Object/ColumnObject.php b/library/Zend/Db/Metadata/Object/ColumnObject.php index ef529b67e..a9b1288c1 100644 --- a/library/Zend/Db/Metadata/Object/ColumnObject.php +++ b/library/Zend/Db/Metadata/Object/ColumnObject.php @@ -372,7 +372,7 @@ class ColumnObject if (array_key_exists($errataName, $this->errata)) { return $this->errata[$errataName]; } - return null; + return; } /** diff --git a/library/Zend/Db/Metadata/Source/SqliteMetadata.php b/library/Zend/Db/Metadata/Source/SqliteMetadata.php index 0fc1e15bc..8006133d6 100644 --- a/library/Zend/Db/Metadata/Source/SqliteMetadata.php +++ b/library/Zend/Db/Metadata/Source/SqliteMetadata.php @@ -271,7 +271,7 @@ class SqliteMetadata extends AbstractSource } if (!preg_match($re, $sql, $matches)) { - return null; + return; } return array( 'view_definition' => $matches['view_definition'], @@ -291,7 +291,7 @@ class SqliteMetadata extends AbstractSource 'TRIGGER', array('IF', 'NOT', 'EXISTS'), $identifierChain, - array('(?BEFORE|AFTER|INSTEAD\\s+OF)',), + array('(?BEFORE|AFTER|INSTEAD\\s+OF)', ), '(?DELETE|INSERT|UPDATE)', array('OF', '(?' . $identifierList . ')'), 'ON', @@ -306,7 +306,7 @@ class SqliteMetadata extends AbstractSource } if (!preg_match($re, $sql, $matches)) { - return null; + return; } $data = array(); diff --git a/library/Zend/Db/ResultSet/AbstractResultSet.php b/library/Zend/Db/ResultSet/AbstractResultSet.php index a5cbb6822..7352e3b07 100644 --- a/library/Zend/Db/ResultSet/AbstractResultSet.php +++ b/library/Zend/Db/ResultSet/AbstractResultSet.php @@ -50,7 +50,7 @@ abstract class AbstractResultSet implements Iterator, ResultSetInterface /** * Set the data source for the result set * - * @param Iterator|IteratorAggregate|ResultInterface $dataSource + * @param array|Iterator|IteratorAggregate|ResultInterface $dataSource * @return ResultSet * @throws Exception\InvalidArgumentException */ diff --git a/library/Zend/Db/ResultSet/HydratingResultSet.php b/library/Zend/Db/ResultSet/HydratingResultSet.php index f7a44f13f..74b9c0b87 100644 --- a/library/Zend/Db/ResultSet/HydratingResultSet.php +++ b/library/Zend/Db/ResultSet/HydratingResultSet.php @@ -55,6 +55,16 @@ class HydratingResultSet extends AbstractResultSet return $this; } + /** + * Get the row object prototype + * + * @return object + */ + public function getObjectPrototype() + { + return $this->objectPrototype; + } + /** * Set the hydrator to use for each row object * diff --git a/library/Zend/Db/Sql/AbstractExpression.php b/library/Zend/Db/Sql/AbstractExpression.php new file mode 100644 index 000000000..de207ed5d --- /dev/null +++ b/library/Zend/Db/Sql/AbstractExpression.php @@ -0,0 +1,93 @@ +buildNormalizedArgument($argument, self::TYPE_VALUE); + } + + if (is_scalar($argument) || $argument === null) { + return $this->buildNormalizedArgument($argument, $defaultType); + } + + if (is_array($argument)) { + $value = current($argument); + + if ($value instanceof ExpressionInterface || $value instanceof SqlInterface) { + return $this->buildNormalizedArgument($value, self::TYPE_VALUE); + } + + $key = key($argument); + + if (is_integer($key) && ! in_array($value, $this->allowedTypes)) { + return $this->buildNormalizedArgument($value, $defaultType); + } + + return $this->buildNormalizedArgument($key, $value); + } + + throw new Exception\InvalidArgumentException(sprintf( + '$argument should be %s or %s or %s or %s or %s, "%s" given', + 'null', + 'scalar', + 'array', + 'Zend\Db\Sql\ExpressionInterface', + 'Zend\Db\Sql\SqlInterface', + is_object($argument) ? get_class($argument) : gettype($argument) + )); + } + + /** + * @param mixed $argument + * @param string $argumentType + * + * @return array + * + * @throws Exception\InvalidArgumentException + */ + private function buildNormalizedArgument($argument, $argumentType) + { + if (! in_array($argumentType, $this->allowedTypes)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Argument type should be in array(%s)', + implode(',', $this->allowedTypes) + )); + } + + return array( + $argument, + $argumentType, + ); + } +} diff --git a/library/Zend/Db/Sql/AbstractPreparableSql.php b/library/Zend/Db/Sql/AbstractPreparableSql.php new file mode 100644 index 000000000..0741f38f8 --- /dev/null +++ b/library/Zend/Db/Sql/AbstractPreparableSql.php @@ -0,0 +1,39 @@ +getParameterContainer(); + + if (! $parameterContainer instanceof ParameterContainer) { + $parameterContainer = new ParameterContainer(); + + $statementContainer->setParameterContainer($parameterContainer); + } + + $statementContainer->setSql( + $this->buildSqlString($adapter->getPlatform(), $adapter->getDriver(), $parameterContainer) + ); + + return $statementContainer; + } +} diff --git a/library/Zend/Db/Sql/AbstractSql.php b/library/Zend/Db/Sql/AbstractSql.php index 7726af427..1830f9037 100644 --- a/library/Zend/Db/Sql/AbstractSql.php +++ b/library/Zend/Db/Sql/AbstractSql.php @@ -9,17 +9,18 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\Adapter; use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\StatementContainer; use Zend\Db\Sql\Platform\PlatformDecoratorInterface; +use Zend\Db\Adapter\Platform\Sql92 as DefaultAdapterPlatform; -abstract class AbstractSql +abstract class AbstractSql implements SqlInterface { /** - * @var array + * Specifications for Sql String generation + * + * @var string[]|array[] */ protected $specifications = array(); @@ -33,23 +34,74 @@ abstract class AbstractSql */ protected $instanceParameterIndex = array(); - protected function processExpression(ExpressionInterface $expression, PlatformInterface $platform, DriverInterface $driver = null, $namedParameterPrefix = null) + /** + * {@inheritDoc} + */ + public function getSqlString(PlatformInterface $adapterPlatform = null) { + $adapterPlatform = ($adapterPlatform) ?: new DefaultAdapterPlatform; + return $this->buildSqlString($adapterPlatform); + } + + /** + * @param PlatformInterface $platform + * @param null|DriverInterface $driver + * @param null|ParameterContainer $parameterContainer + * + * @return string + */ + protected function buildSqlString(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) + { + $this->localizeVariables(); + + $sqls = array(); + $parameters = array(); + + foreach ($this->specifications as $name => $specification) { + $parameters[$name] = $this->{'process' . $name}($platform, $driver, $parameterContainer, $sqls, $parameters); + + if ($specification && is_array($parameters[$name])) { + $sqls[$name] = $this->createSqlFromSpecificationAndParameters($specification, $parameters[$name]); + + continue; + } + + if (is_string($parameters[$name])) { + $sqls[$name] = $parameters[$name]; + } + } + return rtrim(implode(' ', $sqls), "\n ,"); + } + + /** + * + * @staticvar int $runtimeExpressionPrefix + * @param ExpressionInterface $expression + * @param PlatformInterface $platform + * @param null|DriverInterface $driver + * @param null|ParameterContainer $parameterContainer + * @param null|string $namedParameterPrefix + * + * @return string + * + * @throws Exception\RuntimeException + */ + protected function processExpression(ExpressionInterface $expression, PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null, $namedParameterPrefix = null) + { + $namedParameterPrefix = !$namedParameterPrefix ? $namedParameterPrefix : $this->processInfo['paramPrefix'] . $namedParameterPrefix; // static counter for the number of times this method was invoked across the PHP runtime static $runtimeExpressionPrefix = 0; - if ($driver && ((!is_string($namedParameterPrefix) || $namedParameterPrefix == ''))) { + if ($parameterContainer && ((!is_string($namedParameterPrefix) || $namedParameterPrefix == ''))) { $namedParameterPrefix = sprintf('expr%04dParam', ++$runtimeExpressionPrefix); } $sql = ''; - $statementContainer = new StatementContainer; - $parameterContainer = $statementContainer->getParameterContainer(); // initialize variables $parts = $expression->getExpressionData(); - if (!isset($this->instanceParameterIndex[$namedParameterPrefix])) { + if (! isset($this->instanceParameterIndex[$namedParameterPrefix])) { $this->instanceParameterIndex[$namedParameterPrefix] = 1; } @@ -59,37 +111,36 @@ abstract class AbstractSql // if it is a string, simply tack it onto the return sql "specification" string if (is_string($part)) { $sql .= $part; + continue; } - if (!is_array($part)) { - throw new Exception\RuntimeException('Elements returned from getExpressionData() array must be a string or array.'); + if (! is_array($part)) { + throw new Exception\RuntimeException( + 'Elements returned from getExpressionData() array must be a string or array.' + ); } // process values and types (the middle and last position of the expression data) $values = $part[1]; - $types = (isset($part[2])) ? $part[2] : array(); + $types = isset($part[2]) ? $part[2] : array(); foreach ($values as $vIndex => $value) { - if (isset($types[$vIndex]) && $types[$vIndex] == ExpressionInterface::TYPE_IDENTIFIER) { - $values[$vIndex] = $platform->quoteIdentifierInFragment($value); - } elseif (isset($types[$vIndex]) && $types[$vIndex] == ExpressionInterface::TYPE_VALUE && $value instanceof Select) { + if (!isset($types[$vIndex])) { + continue; + } + $type = $types[$vIndex]; + if ($value instanceof Select) { // process sub-select - if ($driver) { - $values[$vIndex] = '(' . $this->processSubSelect($value, $platform, $driver, $parameterContainer) . ')'; - } else { - $values[$vIndex] = '(' . $this->processSubSelect($value, $platform) . ')'; - } - } elseif (isset($types[$vIndex]) && $types[$vIndex] == ExpressionInterface::TYPE_VALUE && $value instanceof ExpressionInterface) { + $values[$vIndex] = '(' . $this->processSubSelect($value, $platform, $driver, $parameterContainer) . ')'; + } elseif ($value instanceof ExpressionInterface) { // recursive call to satisfy nested expressions - $innerStatementContainer = $this->processExpression($value, $platform, $driver, $namedParameterPrefix . $vIndex . 'subpart'); - $values[$vIndex] = $innerStatementContainer->getSql(); - if ($driver) { - $parameterContainer->merge($innerStatementContainer->getParameterContainer()); - } - } elseif (isset($types[$vIndex]) && $types[$vIndex] == ExpressionInterface::TYPE_VALUE) { + $values[$vIndex] = $this->processExpression($value, $platform, $driver, $parameterContainer, $namedParameterPrefix . $vIndex . 'subpart'); + } elseif ($type == ExpressionInterface::TYPE_IDENTIFIER) { + $values[$vIndex] = $platform->quoteIdentifierInFragment($value); + } elseif ($type == ExpressionInterface::TYPE_VALUE) { // if prepareType is set, it means that this particular value must be // passed back to the statement in a way it can be used as a placeholder value - if ($driver) { + if ($parameterContainer) { $name = $namedParameterPrefix . $expressionParamIndex++; $parameterContainer->offsetSet($name, $value); $values[$vIndex] = $driver->formatParameterName($name); @@ -98,7 +149,7 @@ abstract class AbstractSql // if not a preparable statement, simply quote the value and move on $values[$vIndex] = $platform->quoteValue($value); - } elseif (isset($types[$vIndex]) && $types[$vIndex] == ExpressionInterface::TYPE_LITERAL) { + } elseif ($type == ExpressionInterface::TYPE_LITERAL) { $values[$vIndex] = $value; } } @@ -107,14 +158,15 @@ abstract class AbstractSql $sql .= vsprintf($part[0], $values); } - $statementContainer->setSql($sql); - return $statementContainer; + return $sql; } /** - * @param $specifications - * @param $parameters + * @param string|array $specifications + * @param string|array $parameters + * * @return string + * * @throws Exception\RuntimeException */ protected function createSqlFromSpecificationAndParameters($specifications, $parameters) @@ -124,10 +176,12 @@ abstract class AbstractSql } $parametersCount = count($parameters); + foreach ($specifications as $specificationString => $paramSpecs) { if ($parametersCount == count($paramSpecs)) { break; } + unset($specificationString, $paramSpecs); } @@ -162,40 +216,113 @@ abstract class AbstractSql return vsprintf($specificationString, $topParameters); } + /** + * @param Select $subselect + * @param PlatformInterface $platform + * @param null|DriverInterface $driver + * @param null|ParameterContainer $parameterContainer + * @return string + */ protected function processSubSelect(Select $subselect, PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - if ($driver) { - $stmtContainer = new StatementContainer; + if ($this instanceof PlatformDecoratorInterface) { + $decorator = clone $this; + $decorator->setSubject($subselect); + } else { + $decorator = $subselect; + } + if ($parameterContainer) { // Track subselect prefix and count for parameters + $processInfoContext = ($decorator instanceof PlatformDecoratorInterface) ? $subselect : $decorator; $this->processInfo['subselectCount']++; - $subselect->processInfo['subselectCount'] = $this->processInfo['subselectCount']; - $subselect->processInfo['paramPrefix'] = 'subselect' . $subselect->processInfo['subselectCount']; + $processInfoContext->processInfo['subselectCount'] = $this->processInfo['subselectCount']; + $processInfoContext->processInfo['paramPrefix'] = 'subselect' . $processInfoContext->processInfo['subselectCount']; - // call subselect - if ($this instanceof PlatformDecoratorInterface) { - /** @var Select|PlatformDecoratorInterface $subselectDecorator */ - $subselectDecorator = clone $this; - $subselectDecorator->setSubject($subselect); - $subselectDecorator->prepareStatement(new Adapter($driver, $platform), $stmtContainer); - } else { - $subselect->prepareStatement(new Adapter($driver, $platform), $stmtContainer); - } + $sql = $decorator->buildSqlString($platform, $driver, $parameterContainer); // copy count - $this->processInfo['subselectCount'] = $subselect->processInfo['subselectCount']; - - $parameterContainer->merge($stmtContainer->getParameterContainer()->getNamedArray()); - $sql = $stmtContainer->getSql(); - } else { - if ($this instanceof PlatformDecoratorInterface) { - $subselectDecorator = clone $this; - $subselectDecorator->setSubject($subselect); - $sql = $subselectDecorator->getSqlString($platform); - } else { - $sql = $subselect->getSqlString($platform); - } + $this->processInfo['subselectCount'] = $decorator->processInfo['subselectCount']; + return $sql; + } + + return $decorator->buildSqlString($platform, $driver, $parameterContainer); + } + + /** + * @param null|array|ExpressionInterface|Select $column + * @param PlatformInterface $platform + * @param null|DriverInterface $driver + * @param null|string $namedParameterPrefix + * @param null|ParameterContainer $parameterContainer + * @return string + */ + protected function resolveColumnValue($column, PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null, $namedParameterPrefix = null) + { + $namedParameterPrefix = !$namedParameterPrefix ? $namedParameterPrefix : $this->processInfo['paramPrefix'] . $namedParameterPrefix; + $isIdentifier = false; + $fromTable = ''; + if (is_array($column)) { + if (isset($column['isIdentifier'])) { + $isIdentifier = (bool) $column['isIdentifier']; + } + if (isset($column['fromTable']) && $column['fromTable'] !== null) { + $fromTable = $column['fromTable']; + } + $column = $column['column']; + } + + if ($column instanceof ExpressionInterface) { + return $this->processExpression($column, $platform, $driver, $parameterContainer, $namedParameterPrefix); + } + if ($column instanceof Select) { + return '(' . $this->processSubSelect($column, $platform, $driver, $parameterContainer) . ')'; + } + if ($column === null) { + return 'NULL'; + } + return $isIdentifier + ? $fromTable . $platform->quoteIdentifierInFragment($column) + : $platform->quoteValue($column); + } + + /** + * @param string|TableIdentifier|Select $table + * @param PlatformInterface $platform + * @param DriverInterface $driver + * @param ParameterContainer $parameterContainer + * @return string + */ + protected function resolveTable($table, PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) + { + $schema = null; + if ($table instanceof TableIdentifier) { + list($table, $schema) = $table->getTableAndSchema(); + } + + if ($table instanceof Select) { + $table = '(' . $this->processSubselect($table, $platform, $driver, $parameterContainer) . ')'; + } elseif ($table) { + $table = $platform->quoteIdentifier($table); + } + + if ($schema && $table) { + $table = $platform->quoteIdentifier($schema) . $platform->getIdentifierSeparator() . $table; + } + return $table; + } + + /** + * Copy variables from the subject into the local properties + */ + protected function localizeVariables() + { + if (! $this instanceof PlatformDecoratorInterface) { + return; + } + + foreach (get_object_vars($this->subject) as $name => $value) { + $this->{$name} = $value; } - return $sql; } } diff --git a/library/Zend/Db/Sql/Combine.php b/library/Zend/Db/Sql/Combine.php new file mode 100644 index 000000000..1b0ed0f4a --- /dev/null +++ b/library/Zend/Db/Sql/Combine.php @@ -0,0 +1,207 @@ + '%1$s (%2$s) ', + ); + + /** + * @var Select[][] + */ + private $combine = array(); + + /** + * @param Select|array|null $select + * @param string $type + * @param string $modifier + */ + public function __construct($select = null, $type = self::COMBINE_UNION, $modifier = '') + { + if ($select) { + $this->combine($select, $type, $modifier); + } + } + + /** + * Create combine clause + * + * @param Select|array $select + * @param string $type + * @param string $modifier + * + * @return self + */ + public function combine($select, $type = self::COMBINE_UNION, $modifier = '') + { + if (is_array($select)) { + foreach ($select as $combine) { + if ($combine instanceof Select) { + $combine = array($combine); + } + + $this->combine( + $combine[0], + isset($combine[1]) ? $combine[1] : $type, + isset($combine[2]) ? $combine[2] : $modifier + ); + } + return $this; + } + + if (! $select instanceof Select) { + throw new Exception\InvalidArgumentException(sprintf( + '$select must be a array or instance of Select, "%s" given', + is_object($select) ? get_class($select) : gettype($select) + )); + } + + $this->combine[] = array( + 'select' => $select, + 'type' => $type, + 'modifier' => $modifier + ); + return $this; + } + + /** + * Create union clause + * + * @param Select|array $select + * @param string $modifier + * + * @return self + */ + public function union($select, $modifier = '') + { + return $this->combine($select, self::COMBINE_UNION, $modifier); + } + + /** + * Create except clause + * + * @param Select|array $select + * @param string $modifier + * + * @return self + */ + public function except($select, $modifier = '') + { + return $this->combine($select, self::COMBINE_EXCEPT, $modifier); + } + + /** + * Create intersect clause + * + * @param Select|array $select + * @param string $modifier + * @return self + */ + public function intersect($select, $modifier = '') + { + return $this->combine($select, self::COMBINE_INTERSECT, $modifier); + } + + /** + * Build sql string + * + * @param PlatformInterface $platform + * @param DriverInterface $driver + * @param ParameterContainer $parameterContainer + * + * @return string + */ + protected function buildSqlString(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) + { + if (!$this->combine) { + return; + } + + $sql = ''; + foreach ($this->combine as $i => $combine) { + $type = $i == 0 + ? '' + : strtoupper($combine['type'] . ($combine['modifier'] ? ' ' . $combine['modifier'] : '')); + $select = $this->processSubSelect($combine['select'], $platform, $driver, $parameterContainer); + $sql .= sprintf( + $this->specifications[self::COMBINE], + $type, + $select + ); + } + return trim($sql, ' '); + } + + /** + * @return $this + */ + public function alignColumns() + { + if (!$this->combine) { + return $this; + } + + $allColumns = array(); + foreach ($this->combine as $combine) { + $allColumns = array_merge( + $allColumns, + $combine['select']->getRawState(self::COLUMNS) + ); + } + + foreach ($this->combine as $combine) { + $combineColumns = $combine['select']->getRawState(self::COLUMNS); + $aligned = array(); + foreach ($allColumns as $alias => $column) { + $aligned[$alias] = isset($combineColumns[$alias]) + ? $combineColumns[$alias] + : new Predicate\Expression('NULL'); + } + $combine['select']->columns($aligned, false); + } + return $this; + } + + /** + * Get raw state + * + * @param string $key + * + * @return array + */ + public function getRawState($key = null) + { + $rawState = array( + self::COMBINE => $this->combine, + self::COLUMNS => $this->combine + ? $this->combine[0]['select']->getRawState(self::COLUMNS) + : array(), + ); + return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; + } +} diff --git a/library/Zend/Db/Sql/Ddl/AlterTable.php b/library/Zend/Db/Sql/Ddl/AlterTable.php index 6ab95a02b..467bc2e2e 100644 --- a/library/Zend/Db/Sql/Ddl/AlterTable.php +++ b/library/Zend/Db/Sql/Ddl/AlterTable.php @@ -10,7 +10,6 @@ namespace Zend\Db\Sql\Ddl; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92 as AdapterSql92Platform; use Zend\Db\Sql\AbstractSql; class AlterTable extends AbstractSql implements SqlInterface @@ -55,27 +54,27 @@ class AlterTable extends AbstractSql implements SqlInterface self::TABLE => "ALTER TABLE %1\$s\n", self::ADD_COLUMNS => array( "%1\$s" => array( - array(1 => 'ADD COLUMN %1$s', 'combinedby' => ",\n") + array(1 => "ADD COLUMN %1\$s,\n", 'combinedby' => "") ) ), self::CHANGE_COLUMNS => array( "%1\$s" => array( - array(2 => 'CHANGE COLUMN %1$s %2$s', 'combinedby' => ",\n"), + array(2 => "CHANGE COLUMN %1\$s %2\$s,\n", 'combinedby' => ""), ) ), self::DROP_COLUMNS => array( "%1\$s" => array( - array(1 => 'DROP COLUMN %1$s', 'combinedby' => ",\n"), + array(1 => "DROP COLUMN %1\$s,\n", 'combinedby' => ""), ) ), self::ADD_CONSTRAINTS => array( "%1\$s" => array( - array(1 => 'ADD %1$s', 'combinedby' => ",\n"), + array(1 => "ADD %1\$s,\n", 'combinedby' => ""), ) ), self::DROP_CONSTRAINTS => array( "%1\$s" => array( - array(1 => 'DROP CONSTRAINT %1$s', 'combinedby' => ",\n"), + array(1 => "DROP CONSTRAINT %1\$s,\n", 'combinedby' => ""), ) ) ); @@ -178,36 +177,6 @@ class AlterTable extends AbstractSql implements SqlInterface return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; } - /** - * @param PlatformInterface $adapterPlatform - * @return string - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) - { - // get platform, or create default - $adapterPlatform = ($adapterPlatform) ?: new AdapterSql92Platform; - - $sqls = array(); - $parameters = array(); - - foreach ($this->specifications as $name => $specification) { - $parameters[$name] = $this->{'process' . $name}($adapterPlatform, null, null, $sqls, $parameters); - if ($specification && is_array($parameters[$name]) && ($parameters[$name] != array(array()))) { - $sqls[$name] = $this->createSqlFromSpecificationAndParameters($specification, $parameters[$name]); - } - if (stripos($name, 'table') === false && $parameters[$name] !== array(array())) { - $sqls[] = ",\n"; - } - } - - // remove last ,\n - array_pop($sqls); - - $sql = implode('', $sqls); - - return $sql; - } - protected function processTable(PlatformInterface $adapterPlatform = null) { return array($adapterPlatform->quoteIdentifier($this->table)); @@ -217,7 +186,7 @@ class AlterTable extends AbstractSql implements SqlInterface { $sqls = array(); foreach ($this->addColumns as $column) { - $sqls[] = $this->processExpression($column, $adapterPlatform)->getSql(); + $sqls[] = $this->processExpression($column, $adapterPlatform); } return array($sqls); @@ -229,7 +198,7 @@ class AlterTable extends AbstractSql implements SqlInterface foreach ($this->changeColumns as $name => $column) { $sqls[] = array( $adapterPlatform->quoteIdentifier($name), - $this->processExpression($column, $adapterPlatform)->getSql() + $this->processExpression($column, $adapterPlatform) ); } diff --git a/library/Zend/Db/Sql/Ddl/Column/AbstractLengthColumn.php b/library/Zend/Db/Sql/Ddl/Column/AbstractLengthColumn.php new file mode 100644 index 000000000..8bc507406 --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/AbstractLengthColumn.php @@ -0,0 +1,72 @@ +setLength($length); + + parent::__construct($name, $nullable, $default, $options); + } + + /** + * @param int $length + * + * @return self + */ + public function setLength($length) + { + $this->length = (int) $length; + + return $this; + } + + /** + * @return int + */ + public function getLength() + { + return $this->length; + } + + /** + * @return string + */ + protected function getLengthExpression() + { + return (string) $this->length; + } + + /** + * @return array + */ + public function getExpressionData() + { + $data = parent::getExpressionData(); + + if ($this->getLengthExpression()) { + $data[0][1][1] .= '(' . $this->getLengthExpression() . ')'; + } + + return $data; + } +} diff --git a/library/Zend/Db/Sql/Ddl/Column/AbstractPrecisionColumn.php b/library/Zend/Db/Sql/Ddl/Column/AbstractPrecisionColumn.php new file mode 100644 index 000000000..d148367d5 --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/AbstractPrecisionColumn.php @@ -0,0 +1,80 @@ +setDecimal($decimal); + + parent::__construct($name, $digits, $nullable, $default, $options); + } + + /** + * @param int $digits + * + * @return self + */ + public function setDigits($digits) + { + return $this->setLength($digits); + } + + /** + * @return int + */ + public function getDigits() + { + return $this->getLength(); + } + + /** + * @param int|null $decimal + * @return self + */ + public function setDecimal($decimal) + { + $this->decimal = null === $decimal ? null : (int) $decimal; + + return $this; + } + + /** + * @return int|null + */ + public function getDecimal() + { + return $this->decimal; + } + + /** + * {@inheritDoc} + */ + protected function getLengthExpression() + { + if ($this->decimal !== null) { + return $this->length . ',' . $this->decimal; + } + + return $this->length; + } +} diff --git a/library/Zend/Db/Sql/Ddl/Column/AbstractTimestampColumn.php b/library/Zend/Db/Sql/Ddl/Column/AbstractTimestampColumn.php new file mode 100644 index 000000000..933c84557 --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/AbstractTimestampColumn.php @@ -0,0 +1,63 @@ +specification; + + $params = array(); + $params[] = $this->name; + $params[] = $this->type; + + $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); + + if (!$this->isNullable) { + $spec .= ' NOT NULL'; + } + + if ($this->default !== null) { + $spec .= ' DEFAULT %s'; + $params[] = $this->default; + $types[] = self::TYPE_VALUE; + } + + $options = $this->getOptions(); + + if (isset($options['on_update'])) { + $spec .= ' %s'; + $params[] = 'ON UPDATE CURRENT_TIMESTAMP'; + $types[] = self::TYPE_LITERAL; + } + + $data = array(array( + $spec, + $params, + $types, + )); + + foreach ($this->constraints as $constraint) { + $data[] = ' '; + $data = array_merge($data, $constraint->getExpressionData()); + } + + return $data; + } +} diff --git a/library/Zend/Db/Sql/Ddl/Column/Binary.php b/library/Zend/Db/Sql/Ddl/Column/Binary.php new file mode 100644 index 000000000..d56a2833f --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/Binary.php @@ -0,0 +1,18 @@ +setName($name); - $this->setLength($length); - $this->setNullable($nullable); - $this->setDefault($default); - $this->setOptions($options); - } - - /** - * @param int $length - * @return self - */ - public function setLength($length) - { - $this->length = $length; - return $this; - } - - /** - * @return int - */ - public function getLength() - { - return $this->length; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - - $params = array(); - $params[] = $this->name; - $params[] = $this->type; - - if ($this->length) { - $params[1] .= ' ' . $this->length; - } - - $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); - - if (!$this->isNullable) { - $params[1] .= ' NOT NULL'; - } - - if ($this->default !== null) { - $spec .= ' DEFAULT %s'; - $params[] = $this->default; - $types[] = self::TYPE_VALUE; - } - - return array(array( - $spec, - $params, - $types, - )); - } } diff --git a/library/Zend/Db/Sql/Ddl/Column/Boolean.php b/library/Zend/Db/Sql/Ddl/Column/Boolean.php index 26f83f825..61008dc50 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Boolean.php +++ b/library/Zend/Db/Sql/Ddl/Column/Boolean.php @@ -12,31 +12,20 @@ namespace Zend\Db\Sql\Ddl\Column; class Boolean extends Column { /** - * @var string specification + * @var string */ - protected $specification = '%s TINYINT NOT NULL'; + protected $type = 'BOOLEAN'; /** - * @param string $name + * {@inheritDoc} */ - public function __construct($name) - { - $this->name = $name; - } + protected $isNullable = false; /** - * @return array + * {@inheritDoc} */ - public function getExpressionData() + public function setNullable($nullable) { - $spec = $this->specification; - $params = array($this->name); - $types = array(self::TYPE_IDENTIFIER); - - return array(array( - $spec, - $params, - $types, - )); + return parent::setNullable(false); } } diff --git a/library/Zend/Db/Sql/Ddl/Column/Char.php b/library/Zend/Db/Sql/Ddl/Column/Char.php index 8fb6552df..c1b2a78d0 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Char.php +++ b/library/Zend/Db/Sql/Ddl/Column/Char.php @@ -9,50 +9,10 @@ namespace Zend\Db\Sql\Ddl\Column; -class Char extends Column +class Char extends AbstractLengthColumn { /** * @var string */ - protected $specification = '%s CHAR(%s) %s %s'; - - /** - * @var int - */ - protected $length; - - /** - * @param string $name - * @param int $length - */ - public function __construct($name, $length) - { - $this->name = $name; - $this->length = $length; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); - $params[] = $this->name; - $params[] = $this->length; - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); - } + protected $type = 'CHAR'; } diff --git a/library/Zend/Db/Sql/Ddl/Column/Column.php b/library/Zend/Db/Sql/Ddl/Column/Column.php index f24b3ab88..32366fa3e 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Column.php +++ b/library/Zend/Db/Sql/Ddl/Column/Column.php @@ -9,12 +9,14 @@ namespace Zend\Db\Sql\Ddl\Column; +use Zend\Db\Sql\Ddl\Constraint\ConstraintInterface; + class Column implements ColumnInterface { /** * @var null|string|int */ - protected $default = null; + protected $default; /** * @var bool @@ -24,13 +26,18 @@ class Column implements ColumnInterface /** * @var string */ - protected $name = null; + protected $name = ''; /** * @var array */ protected $options = array(); + /** + * @var ConstraintInterface[] + */ + protected $constraints = array(); + /** * @var string */ @@ -43,10 +50,16 @@ class Column implements ColumnInterface /** * @param null|string $name + * @param bool $nullable + * @param mixed|null $default + * @param mixed[] $options */ - public function __construct($name = null) + public function __construct($name = null, $nullable = false, $default = null, array $options = array()) { - (!$name) ?: $this->setName($name); + $this->setName($name); + $this->setNullable($nullable); + $this->setDefault($default); + $this->setOptions($options); } /** @@ -55,7 +68,7 @@ class Column implements ColumnInterface */ public function setName($name) { - $this->name = $name; + $this->name = (string) $name; return $this; } @@ -132,6 +145,18 @@ class Column implements ColumnInterface return $this->options; } + /** + * @param ConstraintInterface $constraint + * + * @return self + */ + public function addConstraint(ConstraintInterface $constraint) + { + $this->constraints[] = $constraint; + + return $this; + } + /** * @return array */ @@ -146,7 +171,7 @@ class Column implements ColumnInterface $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); if (!$this->isNullable) { - $params[1] .= ' NOT NULL'; + $spec .= ' NOT NULL'; } if ($this->default !== null) { @@ -155,10 +180,17 @@ class Column implements ColumnInterface $types[] = self::TYPE_VALUE; } - return array(array( + $data = array(array( $spec, $params, $types, )); + + foreach ($this->constraints as $constraint) { + $data[] = ' '; + $data = array_merge($data, $constraint->getExpressionData()); + } + + return $data; } } diff --git a/library/Zend/Db/Sql/Ddl/Column/Date.php b/library/Zend/Db/Sql/Ddl/Column/Date.php index 266e0699c..527b64c59 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Date.php +++ b/library/Zend/Db/Sql/Ddl/Column/Date.php @@ -14,37 +14,5 @@ class Date extends Column /** * @var string */ - protected $specification = '%s DATE %s %s'; - - /** - * @param string $name - */ - public function __construct($name) - { - $this->name = $name; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER); - $params[] = $this->name; - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); - } + protected $type = 'DATE'; } diff --git a/library/Zend/Db/Sql/Ddl/Column/Datetime.php b/library/Zend/Db/Sql/Ddl/Column/Datetime.php new file mode 100644 index 000000000..5b3207380 --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/Datetime.php @@ -0,0 +1,18 @@ +name = $name; - $this->precision = $precision; - $this->scale = $scale; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); - $params[] = $this->name; - $params[] = $this->precision; - - if ($this->scale !== null) { - $params[1] .= ', ' . $this->scale; - } - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); - } + protected $type = 'DECIMAL'; } diff --git a/library/Zend/Db/Sql/Ddl/Column/Float.php b/library/Zend/Db/Sql/Ddl/Column/Float.php index 5111b9902..c04e70078 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Float.php +++ b/library/Zend/Db/Sql/Ddl/Column/Float.php @@ -9,58 +9,40 @@ namespace Zend\Db\Sql\Ddl\Column; -class Float extends Column +/** + * Stub class for backwards compatibility. + * + * Since PHP 7 adds "float" as a reserved keyword, we can no longer have a class + * named that and retain PHP 7 compatibility. The original class has been + * renamed to "Floating", and this class is now an extension of it. It raises an + * E_USER_DEPRECATED to warn users to migrate. + * + * @deprecated + */ +class Float extends Floating { /** - * @var int + * {@inheritDoc} + * + * Raises a deprecation notice. */ - protected $decimal; + public function __construct( + $name, + $digits = null, + $decimal = null, + $nullable = false, + $default = null, + array $options = array() + ) { + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\Floating', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); - /** - * @var int - */ - protected $digits; - - /** - * @var string - */ - protected $specification = '%s DECIMAL(%s) %s %s'; - - /** - * @param null|string $name - * @param int $digits - * @param int $decimal - */ - public function __construct($name, $digits, $decimal) - { - $this->name = $name; - $this->digits = $digits; - $this->decimal = $decimal; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); - $params[] = $this->name; - $params[] = $this->digits; - $params[1] .= ', ' . $this->decimal; - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); + parent::__construct($name, $digits, $decimal, $nullable, $default, $options); } } diff --git a/library/Zend/Db/Sql/Ddl/Column/Floating.php b/library/Zend/Db/Sql/Ddl/Column/Floating.php new file mode 100644 index 000000000..85343cef4 --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/Floating.php @@ -0,0 +1,24 @@ +setName($name); - $this->setNullable($nullable); - $this->setDefault($default); - $this->setOptions($options); + $data = parent::getExpressionData(); + $options = $this->getOptions(); + + if (isset($options['length'])) { + $data[0][1][1] .= '(' . $options['length'] . ')'; + } + + return $data; } } diff --git a/library/Zend/Db/Sql/Ddl/Column/Text.php b/library/Zend/Db/Sql/Ddl/Column/Text.php index ea63af907..60e059e0d 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Text.php +++ b/library/Zend/Db/Sql/Ddl/Column/Text.php @@ -9,43 +9,10 @@ namespace Zend\Db\Sql\Ddl\Column; - -class Text extends Column +class Text extends AbstractLengthColumn { /** * @var string */ - protected $specification = '%s TEXT %s %s'; - - /** - * @param null|string $name - */ - public function __construct($name) - { - $this->name = $name; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); - $params[] = $this->name; - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); - } + protected $type = 'TEXT'; } diff --git a/library/Zend/Db/Sql/Ddl/Column/Time.php b/library/Zend/Db/Sql/Ddl/Column/Time.php index d7e85404c..03008e311 100644 --- a/library/Zend/Db/Sql/Ddl/Column/Time.php +++ b/library/Zend/Db/Sql/Ddl/Column/Time.php @@ -14,37 +14,5 @@ class Time extends Column /** * @var string */ - protected $specification = '%s TIME %s %s'; - - /** - * @param string $name - */ - public function __construct($name) - { - $this->name = $name; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER); - $params[] = $this->name; - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); - } + protected $type = 'TIME'; } diff --git a/library/Zend/Db/Sql/Ddl/Column/Timestamp.php b/library/Zend/Db/Sql/Ddl/Column/Timestamp.php new file mode 100644 index 000000000..ae98a262e --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Column/Timestamp.php @@ -0,0 +1,18 @@ +name = $name; - $this->length = $length; - } - - /** - * @return array - */ - public function getExpressionData() - { - $spec = $this->specification; - $params = array(); - - $types = array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL); - $params[] = $this->name; - $params[] = $this->length; - - $types[] = self::TYPE_LITERAL; - $params[] = (!$this->isNullable) ? 'NOT NULL' : ''; - - $types[] = ($this->default !== null) ? self::TYPE_VALUE : self::TYPE_LITERAL; - $params[] = ($this->default !== null) ? $this->default : ''; - - return array(array( - $spec, - $params, - $types, - )); - } + protected $type = 'VARCHAR'; } diff --git a/library/Zend/Db/Sql/Ddl/Constraint/AbstractConstraint.php b/library/Zend/Db/Sql/Ddl/Constraint/AbstractConstraint.php index d83e31230..57c00fc15 100644 --- a/library/Zend/Db/Sql/Ddl/Constraint/AbstractConstraint.php +++ b/library/Zend/Db/Sql/Ddl/Constraint/AbstractConstraint.php @@ -11,6 +11,26 @@ namespace Zend\Db\Sql\Ddl\Constraint; abstract class AbstractConstraint implements ConstraintInterface { + /** + * @var string + */ + protected $columnSpecification = ' (%s)'; + + /** + * @var string + */ + protected $namedSpecification = 'CONSTRAINT %s '; + + /** + * @var string + */ + protected $specification = ''; + + /** + * @var string + */ + protected $name = ''; + /** * @var array */ @@ -18,10 +38,33 @@ abstract class AbstractConstraint implements ConstraintInterface /** * @param null|string|array $columns + * @param null|string $name */ - public function __construct($columns = null) + public function __construct($columns = null, $name = null) { - (!$columns) ?: $this->setColumns($columns); + if ($columns) { + $this->setColumns($columns); + } + + $this->setName($name); + } + + /** + * @param string $name + * @return self + */ + public function setName($name) + { + $this->name = (string) $name; + return $this; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; } /** @@ -30,11 +73,8 @@ abstract class AbstractConstraint implements ConstraintInterface */ public function setColumns($columns) { - if (!is_array($columns)) { - $columns = array($columns); - } + $this->columns = (array) $columns; - $this->columns = $columns; return $this; } @@ -49,10 +89,42 @@ abstract class AbstractConstraint implements ConstraintInterface } /** - * @return array + * {@inheritDoc} */ public function getColumns() { return $this->columns; } + + /** + * {@inheritDoc} + */ + public function getExpressionData() + { + $colCount = count($this->columns); + $newSpecTypes = array(); + $values = array(); + $newSpec = ''; + + if ($this->name) { + $newSpec .= $this->namedSpecification; + $values[] = $this->name; + $newSpecTypes[] = self::TYPE_IDENTIFIER; + } + + $newSpec .= $this->specification; + + if ($colCount) { + $values = array_merge($values, $this->columns); + $newSpecParts = array_fill(0, $colCount, '%s'); + $newSpecTypes = array_merge($newSpecTypes, array_fill(0, $colCount, self::TYPE_IDENTIFIER)); + $newSpec .= sprintf($this->columnSpecification, implode(', ', $newSpecParts)); + } + + return array(array( + $newSpec, + $values, + $newSpecTypes, + )); + } } diff --git a/library/Zend/Db/Sql/Ddl/Constraint/Check.php b/library/Zend/Db/Sql/Ddl/Constraint/Check.php index a739b9afc..cc4e2a817 100644 --- a/library/Zend/Db/Sql/Ddl/Constraint/Check.php +++ b/library/Zend/Db/Sql/Ddl/Constraint/Check.php @@ -17,9 +17,9 @@ class Check extends AbstractConstraint protected $expression; /** - * @var string + * {@inheritDoc} */ - protected $specification = 'CONSTRAINT %s CHECK (%s)'; + protected $specification = 'CHECK (%s)'; /** * @param string|\Zend\Db\Sql\ExpressionInterface $expression @@ -32,14 +32,25 @@ class Check extends AbstractConstraint } /** - * @return array + * {@inheritDoc} */ public function getExpressionData() { + $newSpecTypes = array(self::TYPE_LITERAL); + $values = array($this->expression); + $newSpec = ''; + + if ($this->name) { + $newSpec .= $this->namedSpecification; + + array_unshift($values, $this->name); + array_unshift($newSpecTypes, self::TYPE_IDENTIFIER); + } + return array(array( - $this->specification, - array($this->name, $this->expression), - array(self::TYPE_IDENTIFIER, self::TYPE_LITERAL), + $newSpec . $this->specification, + $values, + $newSpecTypes, )); } } diff --git a/library/Zend/Db/Sql/Ddl/Constraint/ForeignKey.php b/library/Zend/Db/Sql/Ddl/Constraint/ForeignKey.php index e974e1f73..c8189aaa3 100644 --- a/library/Zend/Db/Sql/Ddl/Constraint/ForeignKey.php +++ b/library/Zend/Db/Sql/Ddl/Constraint/ForeignKey.php @@ -11,11 +11,6 @@ namespace Zend\Db\Sql\Ddl\Constraint; class ForeignKey extends AbstractConstraint { - /** - * @var string - */ - protected $name; - /** * @var string */ @@ -27,54 +22,50 @@ class ForeignKey extends AbstractConstraint protected $onUpdateRule = 'NO ACTION'; /** - * @var string + * @var string[] */ - protected $referenceColumn; + protected $referenceColumn = array(); /** * @var string */ - protected $referenceTable; + protected $referenceTable = ''; /** - * @var string + * {@inheritDoc} */ - protected $specification = 'CONSTRAINT %1$s FOREIGN KEY (%2$s) REFERENCES %3$s (%4$s) ON DELETE %5$s ON UPDATE %6$s'; + protected $columnSpecification = 'FOREIGN KEY (%s) '; /** - * @param array|null|string $name - * @param string $column + * @var string[] + */ + protected $referenceSpecification = array( + 'REFERENCES %s ', + 'ON DELETE %s ON UPDATE %s' + ); + + /** + * @param null|string $name + * @param null|string|array $columns * @param string $referenceTable - * @param string $referenceColumn + * @param null|string|array $referenceColumn * @param null|string $onDeleteRule * @param null|string $onUpdateRule */ - public function __construct($name, $column, $referenceTable, $referenceColumn, $onDeleteRule = null, $onUpdateRule = null) + public function __construct($name, $columns, $referenceTable, $referenceColumn, $onDeleteRule = null, $onUpdateRule = null) { $this->setName($name); - $this->setColumns($column); + $this->setColumns($columns); $this->setReferenceTable($referenceTable); $this->setReferenceColumn($referenceColumn); - (!$onDeleteRule) ?: $this->setOnDeleteRule($onDeleteRule); - (!$onUpdateRule) ?: $this->setOnUpdateRule($onUpdateRule); - } - /** - * @param string $name - * @return self - */ - public function setName($name) - { - $this->name = $name; - return $this; - } + if ($onDeleteRule) { + $this->setOnDeleteRule($onDeleteRule); + } - /** - * @return string - */ - public function getName() - { - return $this->name; + if ($onUpdateRule) { + $this->setOnUpdateRule($onUpdateRule); + } } /** @@ -83,7 +74,7 @@ class ForeignKey extends AbstractConstraint */ public function setReferenceTable($referenceTable) { - $this->referenceTable = $referenceTable; + $this->referenceTable = (string) $referenceTable; return $this; } @@ -96,17 +87,18 @@ class ForeignKey extends AbstractConstraint } /** - * @param string $referenceColumn + * @param null|string|array $referenceColumn * @return self */ public function setReferenceColumn($referenceColumn) { - $this->referenceColumn = $referenceColumn; + $this->referenceColumn = (array) $referenceColumn; + return $this; } /** - * @return string + * @return array */ public function getReferenceColumn() { @@ -119,7 +111,8 @@ class ForeignKey extends AbstractConstraint */ public function setOnDeleteRule($onDeleteRule) { - $this->onDeleteRule = $onDeleteRule; + $this->onDeleteRule = (string) $onDeleteRule; + return $this; } @@ -137,7 +130,8 @@ class ForeignKey extends AbstractConstraint */ public function setOnUpdateRule($onUpdateRule) { - $this->onUpdateRule = $onUpdateRule; + $this->onUpdateRule = (string) $onUpdateRule; + return $this; } @@ -154,24 +148,31 @@ class ForeignKey extends AbstractConstraint */ public function getExpressionData() { - return array(array( - $this->specification, - array( - $this->name, - $this->columns[0], - $this->referenceTable, - $this->referenceColumn, - $this->onDeleteRule, - $this->onUpdateRule, - ), - array( - self::TYPE_IDENTIFIER, - self::TYPE_IDENTIFIER, - self::TYPE_IDENTIFIER, - self::TYPE_IDENTIFIER, - self::TYPE_LITERAL, - self::TYPE_LITERAL, - ), - )); + $data = parent::getExpressionData(); + $colCount = count($this->referenceColumn); + $newSpecTypes = array(self::TYPE_IDENTIFIER); + $values = array($this->referenceTable); + + $data[0][0] .= $this->referenceSpecification[0]; + + if ($colCount) { + $values = array_merge($values, $this->referenceColumn); + $newSpecParts = array_fill(0, $colCount, '%s'); + $newSpecTypes = array_merge($newSpecTypes, array_fill(0, $colCount, self::TYPE_IDENTIFIER)); + + $data[0][0] .= sprintf('(%s) ', implode(', ', $newSpecParts)); + } + + $data[0][0] .= $this->referenceSpecification[1]; + + $values[] = $this->onDeleteRule; + $values[] = $this->onUpdateRule; + $newSpecTypes[] = self::TYPE_LITERAL; + $newSpecTypes[] = self::TYPE_LITERAL; + + $data[0][1] = array_merge($data[0][1], $values); + $data[0][2] = array_merge($data[0][2], $newSpecTypes); + + return $data; } } diff --git a/library/Zend/Db/Sql/Ddl/Constraint/PrimaryKey.php b/library/Zend/Db/Sql/Ddl/Constraint/PrimaryKey.php index b2501e0b9..064b1e048 100644 --- a/library/Zend/Db/Sql/Ddl/Constraint/PrimaryKey.php +++ b/library/Zend/Db/Sql/Ddl/Constraint/PrimaryKey.php @@ -14,23 +14,5 @@ class PrimaryKey extends AbstractConstraint /** * @var string */ - protected $specification = 'PRIMARY KEY (%s)'; - - /** - * @return array - */ - public function getExpressionData() - { - $colCount = count($this->columns); - $newSpecParts = array_fill(0, $colCount, '%s'); - $newSpecTypes = array_fill(0, $colCount, self::TYPE_IDENTIFIER); - - $newSpec = sprintf($this->specification, implode(', ', $newSpecParts)); - - return array(array( - $newSpec, - $this->columns, - $newSpecTypes, - )); - } + protected $specification = 'PRIMARY KEY'; } diff --git a/library/Zend/Db/Sql/Ddl/Constraint/UniqueKey.php b/library/Zend/Db/Sql/Ddl/Constraint/UniqueKey.php index b983f2fb8..ffca8156a 100644 --- a/library/Zend/Db/Sql/Ddl/Constraint/UniqueKey.php +++ b/library/Zend/Db/Sql/Ddl/Constraint/UniqueKey.php @@ -14,42 +14,5 @@ class UniqueKey extends AbstractConstraint /** * @var string */ - protected $specification = 'CONSTRAINT UNIQUE KEY %s(...)'; - - /** - * @param array $columns - * @param null|string $name - */ - public function __construct($columns, $name = null) - { - $this->setColumns($columns); - $this->name = $name; - } - - /** - * @return array - */ - public function getExpressionData() - { - $colCount = count($this->columns); - - $values = array(); - $values[] = ($this->name) ? $this->name : ''; - - $newSpecTypes = array(self::TYPE_IDENTIFIER); - $newSpecParts = array(); - - for ($i = 0; $i < $colCount; $i++) { - $newSpecParts[] = '%s'; - $newSpecTypes[] = self::TYPE_IDENTIFIER; - } - - $newSpec = str_replace('...', implode(', ', $newSpecParts), $this->specification); - - return array(array( - $newSpec, - array_merge($values, $this->columns), - $newSpecTypes, - )); - } + protected $specification = 'UNIQUE'; } diff --git a/library/Zend/Db/Sql/Ddl/CreateTable.php b/library/Zend/Db/Sql/Ddl/CreateTable.php index f331b232f..31aa4cc26 100644 --- a/library/Zend/Db/Sql/Ddl/CreateTable.php +++ b/library/Zend/Db/Sql/Ddl/CreateTable.php @@ -10,7 +10,6 @@ namespace Zend\Db\Sql\Ddl; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92 as AdapterSql92Platform; use Zend\Db\Sql\AbstractSql; class CreateTable extends AbstractSql implements SqlInterface @@ -20,12 +19,12 @@ class CreateTable extends AbstractSql implements SqlInterface const TABLE = 'table'; /** - * @var array + * @var Column\ColumnInterface[] */ protected $columns = array(); /** - * @var array + * @var string[] */ protected $constraints = array(); @@ -35,8 +34,7 @@ class CreateTable extends AbstractSql implements SqlInterface protected $isTemporary = false; /** - * Specifications for Sql String generation - * @var array + * {@inheritDoc} */ protected $specifications = array( self::TABLE => 'CREATE %1$sTABLE %2$s (', @@ -45,11 +43,13 @@ class CreateTable extends AbstractSql implements SqlInterface array(1 => '%1$s', 'combinedby' => ",\n ") ) ), + 'combinedBy' => ",", self::CONSTRAINTS => array( "\n %1\$s" => array( array(1 => '%1$s', 'combinedby' => ",\n ") ) ), + 'statementEnd' => '%1$s', ); /** @@ -131,88 +131,77 @@ class CreateTable extends AbstractSql implements SqlInterface } /** - * @param PlatformInterface $adapterPlatform - * @return string + * @param PlatformInterface $adapterPlatform + * + * @return string[] */ - public function getSqlString(PlatformInterface $adapterPlatform = null) - { - // get platform, or create default - $adapterPlatform = ($adapterPlatform) ?: new AdapterSql92Platform; - - $sqls = array(); - $parameters = array(); - - foreach ($this->specifications as $name => $specification) { - if (is_int($name)) { - $sqls[] = $specification; - continue; - } - - $parameters[$name] = $this->{'process' . $name}( - $adapterPlatform, - null, - null, - $sqls, - $parameters - ); - - - if ($specification - && is_array($parameters[$name]) - && ($parameters[$name] != array(array())) - ) { - $sqls[$name] = $this->createSqlFromSpecificationAndParameters( - $specification, - $parameters[$name] - ); - } - - if (stripos($name, 'table') === false - && $parameters[$name] !== array(array()) - ) { - $sqls[] = ",\n"; - } - } - - - // remove last , - if (count($sqls) > 2) { - array_pop($sqls); - } - - $sql = implode('', $sqls) . "\n)"; - - return $sql; - } - protected function processTable(PlatformInterface $adapterPlatform = null) { - $ret = array(); - if ($this->isTemporary) { - $ret[] = 'TEMPORARY '; - } else { - $ret[] = ''; - } - - $ret[] = $adapterPlatform->quoteIdentifier($this->table); - return $ret; + return array( + $this->isTemporary ? 'TEMPORARY ' : '', + $adapterPlatform->quoteIdentifier($this->table), + ); } + /** + * @param PlatformInterface $adapterPlatform + * + * @return string[][]|null + */ protected function processColumns(PlatformInterface $adapterPlatform = null) { - $sqls = array(); - foreach ($this->columns as $column) { - $sqls[] = $this->processExpression($column, $adapterPlatform)->getSql(); + if (! $this->columns) { + return; } + + $sqls = array(); + + foreach ($this->columns as $column) { + $sqls[] = $this->processExpression($column, $adapterPlatform); + } + return array($sqls); } + /** + * @param PlatformInterface $adapterPlatform + * + * @return array|string + */ + protected function processCombinedby(PlatformInterface $adapterPlatform = null) + { + if ($this->constraints && $this->columns) { + return $this->specifications['combinedBy']; + } + } + + /** + * @param PlatformInterface $adapterPlatform + * + * @return string[][]|null + */ protected function processConstraints(PlatformInterface $adapterPlatform = null) { - $sqls = array(); - foreach ($this->constraints as $constraint) { - $sqls[] = $this->processExpression($constraint, $adapterPlatform)->getSql(); + if (!$this->constraints) { + return; } + + $sqls = array(); + + foreach ($this->constraints as $constraint) { + $sqls[] = $this->processExpression($constraint, $adapterPlatform); + } + return array($sqls); } + + /** + * @param PlatformInterface $adapterPlatform + * + * @return string[] + */ + protected function processStatementEnd(PlatformInterface $adapterPlatform = null) + { + return array("\n)"); + } } diff --git a/library/Zend/Db/Sql/Ddl/DropTable.php b/library/Zend/Db/Sql/Ddl/DropTable.php index bf3556883..6f5646ef0 100644 --- a/library/Zend/Db/Sql/Ddl/DropTable.php +++ b/library/Zend/Db/Sql/Ddl/DropTable.php @@ -10,7 +10,6 @@ namespace Zend\Db\Sql\Ddl; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92 as AdapterSql92Platform; use Zend\Db\Sql\AbstractSql; class DropTable extends AbstractSql implements SqlInterface @@ -37,39 +36,6 @@ class DropTable extends AbstractSql implements SqlInterface $this->table = $table; } - /** - * @param null|PlatformInterface $adapterPlatform - * @return string - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) - { - // get platform, or create default - $adapterPlatform = ($adapterPlatform) ?: new AdapterSql92Platform; - - $sqls = array(); - $parameters = array(); - - foreach ($this->specifications as $name => $specification) { - $parameters[$name] = $this->{'process' . $name}( - $adapterPlatform, - null, - null, - $sqls, - $parameters - ); - - if ($specification && is_array($parameters[$name])) { - $sqls[$name] = $this->createSqlFromSpecificationAndParameters( - $specification, - $parameters[$name] - ); - } - } - - $sql = implode(' ', $sqls); - return $sql; - } - protected function processTable(PlatformInterface $adapterPlatform = null) { return array($adapterPlatform->quoteIdentifier($this->table)); diff --git a/library/Zend/Db/Sql/Ddl/Index/AbstractIndex.php b/library/Zend/Db/Sql/Ddl/Index/AbstractIndex.php new file mode 100644 index 000000000..a9e1e4cfe --- /dev/null +++ b/library/Zend/Db/Sql/Ddl/Index/AbstractIndex.php @@ -0,0 +1,16 @@ +setColumns($column); + + $this->name = null === $name ? null : (string) $name; + $this->lengths = $lengths; + } + + /** + * + * @return array of array|string should return an array in the format: + * + * array ( + * // a sprintf formatted string + * string $specification, + * + * // the values for the above sprintf formatted string + * array $values, + * + * // an array of equal length of the $values array, with either TYPE_IDENTIFIER or TYPE_VALUE for each value + * array $types, + * ) + * + */ + public function getExpressionData() + { + $colCount = count($this->columns); + $values = array(); + $values[] = $this->name ?: ''; + $newSpecTypes = array(self::TYPE_IDENTIFIER); + $newSpecParts = array(); + + for ($i = 0; $i < $colCount; $i++) { + $specPart = '%s'; + + if (isset($this->lengths[$i])) { + $specPart .= "({$this->lengths[$i]})"; + } + + $newSpecParts[] = $specPart; + $newSpecTypes[] = self::TYPE_IDENTIFIER; + } + + $newSpec = str_replace('...', implode(', ', $newSpecParts), $this->specification); + + return array(array( + $newSpec, + array_merge($values, $this->columns), + $newSpecTypes, + )); + } +} diff --git a/library/Zend/Db/Sql/Delete.php b/library/Zend/Db/Sql/Delete.php index c9a387add..10ada94ab 100644 --- a/library/Zend/Db/Sql/Delete.php +++ b/library/Zend/Db/Sql/Delete.php @@ -9,17 +9,15 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92; -use Zend\Db\Adapter\StatementContainerInterface; +use Zend\Db\Adapter\Driver\DriverInterface; /** * * @property Where $where */ -class Delete extends AbstractSql implements SqlInterface, PreparableSqlInterface +class Delete extends AbstractPreparableSql { /**@#+ * @const @@ -29,7 +27,7 @@ class Delete extends AbstractSql implements SqlInterface, PreparableSqlInterface /**@#-*/ /** - * @var array Specifications + * {@inheritDoc} */ protected $specifications = array( self::SPECIFICATION_DELETE => 'DELETE FROM %1$s', @@ -81,6 +79,11 @@ class Delete extends AbstractSql implements SqlInterface, PreparableSqlInterface return $this; } + /** + * @param null $key + * + * @return mixed + */ public function getRawState($key = null) { $rawState = array( @@ -97,6 +100,7 @@ class Delete extends AbstractSql implements SqlInterface, PreparableSqlInterface * * @param Where|\Closure|string|array $predicate * @param string $combination One of the OP_* constants from Predicate\PredicateSet + * * @return Delete */ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) @@ -110,81 +114,37 @@ class Delete extends AbstractSql implements SqlInterface, PreparableSqlInterface } /** - * Prepare the delete statement + * @param PlatformInterface $platform + * @param DriverInterface|null $driver + * @param ParameterContainer|null $parameterContainer * - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - * @return void + * @return string */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function processDelete(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - $driver = $adapter->getDriver(); - $platform = $adapter->getPlatform(); - $parameterContainer = $statementContainer->getParameterContainer(); - - if (!$parameterContainer instanceof ParameterContainer) { - $parameterContainer = new ParameterContainer(); - $statementContainer->setParameterContainer($parameterContainer); - } - - $table = $this->table; - $schema = null; - - // create quoted table name to use in delete processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); - } - - $table = $platform->quoteIdentifier($table); - - if ($schema) { - $table = $platform->quoteIdentifier($schema) . $platform->getIdentifierSeparator() . $table; - } - - $sql = sprintf($this->specifications[static::SPECIFICATION_DELETE], $table); - - // process where - if ($this->where->count() > 0) { - $whereParts = $this->processExpression($this->where, $platform, $driver, 'where'); - $parameterContainer->merge($whereParts->getParameterContainer()); - $sql .= ' ' . sprintf($this->specifications[static::SPECIFICATION_WHERE], $whereParts->getSql()); - } - $statementContainer->setSql($sql); + return sprintf( + $this->specifications[static::SPECIFICATION_DELETE], + $this->resolveTable($this->table, $platform, $driver, $parameterContainer) + ); } /** - * Get the SQL string, based on the platform + * @param PlatformInterface $platform + * @param DriverInterface|null $driver + * @param ParameterContainer|null $parameterContainer * - * Platform defaults to Sql92 if none provided - * - * @param null|PlatformInterface $adapterPlatform - * @return string + * @return null|string */ - public function getSqlString(PlatformInterface $adapterPlatform = null) + protected function processWhere(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - $adapterPlatform = ($adapterPlatform) ?: new Sql92; - $table = $this->table; - $schema = null; - - // create quoted table name to use in delete processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); + if ($this->where->count() == 0) { + return; } - $table = $adapterPlatform->quoteIdentifier($table); - - if ($schema) { - $table = $adapterPlatform->quoteIdentifier($schema) . $adapterPlatform->getIdentifierSeparator() . $table; - } - - $sql = sprintf($this->specifications[static::SPECIFICATION_DELETE], $table); - - if ($this->where->count() > 0) { - $whereParts = $this->processExpression($this->where, $adapterPlatform, null, 'where'); - $sql .= ' ' . sprintf($this->specifications[static::SPECIFICATION_WHERE], $whereParts->getSql()); - } - - return $sql; + return sprintf( + $this->specifications[static::SPECIFICATION_WHERE], + $this->processExpression($this->where, $platform, $driver, $parameterContainer, 'where') + ); } /** @@ -193,7 +153,8 @@ class Delete extends AbstractSql implements SqlInterface, PreparableSqlInterface * Overloads "where" only. * * @param string $name - * @return mixed + * + * @return Where|null */ public function __get($name) { diff --git a/library/Zend/Db/Sql/Expression.php b/library/Zend/Db/Sql/Expression.php index 21b2649e5..04fb789e7 100644 --- a/library/Zend/Db/Sql/Expression.php +++ b/library/Zend/Db/Sql/Expression.php @@ -9,7 +9,7 @@ namespace Zend\Db\Sql; -class Expression implements ExpressionInterface +class Expression extends AbstractExpression { /** * @const @@ -34,19 +34,31 @@ class Expression implements ExpressionInterface /** * @param string $expression * @param string|array $parameters - * @param array $types + * @param array $types @deprecated will be dropped in version 3.0.0 */ public function __construct($expression = '', $parameters = null, array $types = array()) { - if ($expression) { + if ($expression !== '') { $this->setExpression($expression); } + + if ($types) { // should be deprecated and removed version 3.0.0 + if (is_array($parameters)) { + foreach ($parameters as $i=>$parameter) { + $parameters[$i] = array( + $parameter => isset($types[$i]) ? $types[$i] : self::TYPE_VALUE, + ); + } + } elseif (is_scalar($parameters)) { + $parameters = array( + $parameters => $types[0], + ); + } + } + if ($parameters) { $this->setParameters($parameters); } - if ($types) { - $this->setTypes($types); - } } /** @@ -94,6 +106,7 @@ class Expression implements ExpressionInterface } /** + * @deprecated * @param array $types * @return Expression */ @@ -104,6 +117,7 @@ class Expression implements ExpressionInterface } /** + * @deprecated * @return array */ public function getTypes() @@ -118,35 +132,26 @@ class Expression implements ExpressionInterface public function getExpressionData() { $parameters = (is_scalar($this->parameters)) ? array($this->parameters) : $this->parameters; - - $types = array(); $parametersCount = count($parameters); + $expression = str_replace('%', '%%', $this->expression); - if ($parametersCount == 0 && strpos($this->expression, self::PLACEHOLDER) !== false) { - // if there are no parameters, but there is a placeholder - $parametersCount = substr_count($this->expression, self::PLACEHOLDER); - $parameters = array_fill(0, $parametersCount, null); - } - - for ($i = 0; $i < $parametersCount; $i++) { - $types[$i] = (isset($this->types[$i]) && ($this->types[$i] == self::TYPE_IDENTIFIER || $this->types[$i] == self::TYPE_LITERAL)) - ? $this->types[$i] : self::TYPE_VALUE; + if ($parametersCount == 0) { + return array( + str_ireplace(self::PLACEHOLDER, '', $expression) + ); } // assign locally, escaping % signs - $expression = str_replace('%', '%%', $this->expression); - - if ($parametersCount > 0) { - $count = 0; - $expression = str_replace(self::PLACEHOLDER, '%s', $expression, $count); - if ($count !== $parametersCount) { - throw new Exception\RuntimeException('The number of replacements in the expression does not match the number of parameters'); - } + $expression = str_replace(self::PLACEHOLDER, '%s', $expression, $count); + if ($count !== $parametersCount) { + throw new Exception\RuntimeException('The number of replacements in the expression does not match the number of parameters'); + } + foreach ($parameters as $parameter) { + list($values[], $types[]) = $this->normalizeArgument($parameter, self::TYPE_VALUE); } - return array(array( $expression, - $parameters, + $values, $types )); } diff --git a/library/Zend/Db/Sql/ExpressionInterface.php b/library/Zend/Db/Sql/ExpressionInterface.php index 4781dad06..71286e491 100644 --- a/library/Zend/Db/Sql/ExpressionInterface.php +++ b/library/Zend/Db/Sql/ExpressionInterface.php @@ -14,6 +14,7 @@ interface ExpressionInterface const TYPE_IDENTIFIER = 'identifier'; const TYPE_VALUE = 'value'; const TYPE_LITERAL = 'literal'; + const TYPE_SELECT = 'select'; /** * @abstract diff --git a/library/Zend/Db/Sql/Insert.php b/library/Zend/Db/Sql/Insert.php index 944a369ab..b319616dc 100644 --- a/library/Zend/Db/Sql/Insert.php +++ b/library/Zend/Db/Sql/Insert.php @@ -9,13 +9,11 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92; -use Zend\Db\Adapter\StatementContainerInterface; +use Zend\Db\Adapter\Driver\DriverInterface; -class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface +class Insert extends AbstractPreparableSql { /**#@+ * Constants @@ -45,7 +43,7 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface /** * @var array|Select */ - protected $values = null; + protected $select = null; /** * Constructor @@ -79,7 +77,7 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function columns(array $columns) { - $this->columns = $columns; + $this->columns = array_flip($columns); return $this; } @@ -93,48 +91,34 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function values($values, $flag = self::VALUES_SET) { - if (!is_array($values) && !$values instanceof Select) { - throw new Exception\InvalidArgumentException('values() expects an array of values or Zend\Db\Sql\Select instance'); - } - if ($values instanceof Select) { - if ($flag == self::VALUES_MERGE && (is_array($this->values) && !empty($this->values))) { + if ($flag == self::VALUES_MERGE) { throw new Exception\InvalidArgumentException( - 'A Zend\Db\Sql\Select instance cannot be provided with the merge flag when values already exist.' + 'A Zend\Db\Sql\Select instance cannot be provided with the merge flag' ); } - $this->values = $values; + $this->select = $values; return $this; } - // determine if this is assoc or a set of values - $keys = array_keys($values); - $firstKey = current($keys); - - if ($flag == self::VALUES_SET) { - $this->columns = array(); - $this->values = array(); - } elseif ($this->values instanceof Select) { + if (!is_array($values)) { throw new Exception\InvalidArgumentException( - 'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\Select' - . ' instance already exists as the value source.' + 'values() expects an array of values or Zend\Db\Sql\Select instance' + ); + } + if ($this->select && $flag == self::VALUES_MERGE) { + throw new Exception\InvalidArgumentException( + 'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\Select instance already exists as the value source' ); } - if (is_string($firstKey)) { - foreach ($keys as $key) { - if (($index = array_search($key, $this->columns)) !== false) { - $this->values[$index] = $values[$key]; - } else { - $this->columns[] = $key; - $this->values[] = $values[$key]; - } + if ($flag == self::VALUES_SET) { + $this->columns = $values; + } else { + foreach ($values as $column=>$value) { + $this->columns[$column] = $value; } - } elseif (is_int($firstKey)) { - // determine if count of columns should match count of values - $this->values = array_merge($this->values, array_values($values)); } - return $this; } @@ -159,145 +143,61 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface { $rawState = array( 'table' => $this->table, - 'columns' => $this->columns, - 'values' => $this->values + 'columns' => array_keys($this->columns), + 'values' => array_values($this->columns) ); return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; } - /** - * Prepare statement - * - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - * @return void - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function processInsert(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - $driver = $adapter->getDriver(); - $platform = $adapter->getPlatform(); - $parameterContainer = $statementContainer->getParameterContainer(); - - if (!$parameterContainer instanceof ParameterContainer) { - $parameterContainer = new ParameterContainer(); - $statementContainer->setParameterContainer($parameterContainer); + if ($this->select) { + return; } - - $table = $this->table; - $schema = null; - - // create quoted table name to use in insert processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); - } - - $table = $platform->quoteIdentifier($table); - - if ($schema) { - $table = $platform->quoteIdentifier($schema) . $platform->getIdentifierSeparator() . $table; + if (!$this->columns) { + throw new Exception\InvalidArgumentException('values or select should be present'); } $columns = array(); $values = array(); - - if (is_array($this->values)) { - foreach ($this->columns as $cIndex => $column) { - $columns[$cIndex] = $platform->quoteIdentifier($column); - if (isset($this->values[$cIndex]) && $this->values[$cIndex] instanceof Expression) { - $exprData = $this->processExpression($this->values[$cIndex], $platform, $driver); - $values[$cIndex] = $exprData->getSql(); - $parameterContainer->merge($exprData->getParameterContainer()); - } else { - $values[$cIndex] = $driver->formatParameterName($column); - if (isset($this->values[$cIndex])) { - $parameterContainer->offsetSet($column, $this->values[$cIndex]); - } else { - $parameterContainer->offsetSet($column, null); - } - } + foreach ($this->columns as $column=>$value) { + $columns[] = $platform->quoteIdentifier($column); + if (is_scalar($value) && $parameterContainer) { + $values[] = $driver->formatParameterName($column); + $parameterContainer->offsetSet($column, $value); + } else { + $values[] = $this->resolveColumnValue( + $value, + $platform, + $driver, + $parameterContainer + ); } - $sql = sprintf( - $this->specifications[static::SPECIFICATION_INSERT], - $table, - implode(', ', $columns), - implode(', ', $values) - ); - } elseif ($this->values instanceof Select) { - $this->values->prepareStatement($adapter, $statementContainer); - - $columns = array_map(array($platform, 'quoteIdentifier'), $this->columns); - $columns = implode(', ', $columns); - - $sql = sprintf( - $this->specifications[static::SPECIFICATION_SELECT], - $table, - $columns ? "($columns)" : "", - $statementContainer->getSql() - ); - } else { - throw new Exception\InvalidArgumentException('values or select should be present'); } - $statementContainer->setSql($sql); + return sprintf( + $this->specifications[static::SPECIFICATION_INSERT], + $this->resolveTable($this->table, $platform, $driver, $parameterContainer), + implode(', ', $columns), + implode(', ', $values) + ); } - /** - * Get SQL string for this statement - * - * @param null|PlatformInterface $adapterPlatform Defaults to Sql92 if none provided - * @return string - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) + protected function processSelect(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - $adapterPlatform = ($adapterPlatform) ?: new Sql92; - $table = $this->table; - $schema = null; - - // create quoted table name to use in insert processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); + if (!$this->select) { + return; } + $selectSql = $this->processSubSelect($this->select, $platform, $driver, $parameterContainer); - $table = $adapterPlatform->quoteIdentifier($table); - - if ($schema) { - $table = $adapterPlatform->quoteIdentifier($schema) . $adapterPlatform->getIdentifierSeparator() . $table; - } - - $columns = array_map(array($adapterPlatform, 'quoteIdentifier'), $this->columns); + $columns = array_map(array($platform, 'quoteIdentifier'), array_keys($this->columns)); $columns = implode(', ', $columns); - if (is_array($this->values)) { - $values = array(); - foreach ($this->values as $value) { - if ($value instanceof Expression) { - $exprData = $this->processExpression($value, $adapterPlatform); - $values[] = $exprData->getSql(); - } elseif ($value === null) { - $values[] = 'NULL'; - } else { - $values[] = $adapterPlatform->quoteValue($value); - } - } - return sprintf( - $this->specifications[static::SPECIFICATION_INSERT], - $table, - $columns, - implode(', ', $values) - ); - } elseif ($this->values instanceof Select) { - $selectString = $this->values->getSqlString($adapterPlatform); - if ($columns) { - $columns = "($columns)"; - } - return sprintf( - $this->specifications[static::SPECIFICATION_SELECT], - $table, - $columns, - $selectString - ); - } else { - throw new Exception\InvalidArgumentException('values or select should be present'); - } + return sprintf( + $this->specifications[static::SPECIFICATION_SELECT], + $this->resolveTable($this->table, $platform, $driver, $parameterContainer), + $columns ? "($columns)" : "", + $selectSql + ); } /** @@ -311,8 +211,7 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function __set($name, $value) { - $values = array($name => $value); - $this->values($values, self::VALUES_MERGE); + $this->columns[$name] = $value; return $this; } @@ -327,14 +226,11 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function __unset($name) { - if (($position = array_search($name, $this->columns)) === false) { + if (!isset($this->columns[$name])) { throw new Exception\InvalidArgumentException('The key ' . $name . ' was not found in this objects column list'); } - unset($this->columns[$position]); - if (is_array($this->values)) { - unset($this->values[$position]); - } + unset($this->columns[$name]); } /** @@ -347,7 +243,7 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function __isset($name) { - return in_array($name, $this->columns); + return isset($this->columns[$name]); } /** @@ -361,12 +257,9 @@ class Insert extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function __get($name) { - if (!is_array($this->values)) { - return null; - } - if (($position = array_search($name, $this->columns)) === false) { + if (!isset($this->columns[$name])) { throw new Exception\InvalidArgumentException('The key ' . $name . ' was not found in this objects column list'); } - return $this->values[$position]; + return $this->columns[$name]; } } diff --git a/library/Zend/Db/Sql/Platform/AbstractPlatform.php b/library/Zend/Db/Sql/Platform/AbstractPlatform.php index 1eec50e34..32d5bd1f2 100644 --- a/library/Zend/Db/Sql/Platform/AbstractPlatform.php +++ b/library/Zend/Db/Sql/Platform/AbstractPlatform.php @@ -19,9 +19,9 @@ use Zend\Db\Sql\SqlInterface; class AbstractPlatform implements PlatformDecoratorInterface, PreparableSqlInterface, SqlInterface { /** - * @var object + * @var object|null */ - protected $subject = null; + protected $subject; /** * @var PlatformDecoratorInterface[] @@ -29,22 +29,43 @@ class AbstractPlatform implements PlatformDecoratorInterface, PreparableSqlInter protected $decorators = array(); /** - * @param $subject + * {@inheritDoc} */ public function setSubject($subject) { $this->subject = $subject; + + return $this; } /** - * @param $type + * @param string $type * @param PlatformDecoratorInterface $decorator + * + * @return void */ public function setTypeDecorator($type, PlatformDecoratorInterface $decorator) { $this->decorators[$type] = $decorator; } + /** + * @param PreparableSqlInterface|SqlInterface $subject + * @return PlatformDecoratorInterface|PreparableSqlInterface|SqlInterface + */ + public function getTypeDecorator($subject) + { + foreach ($this->decorators as $type => $decorator) { + if ($subject instanceof $type) { + $decorator->setSubject($subject); + + return $decorator; + } + } + + return $subject; + } + /** * @return array|PlatformDecoratorInterface[] */ @@ -54,57 +75,32 @@ class AbstractPlatform implements PlatformDecoratorInterface, PreparableSqlInter } /** - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer + * {@inheritDoc} + * * @throws Exception\RuntimeException - * @return void */ public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) { - if (!$this->subject instanceof PreparableSqlInterface) { + if (! $this->subject instanceof PreparableSqlInterface) { throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\PreparableSqlInterface, thus calling prepareStatement() has no effect'); } - $decoratorForType = false; - foreach ($this->decorators as $type => $decorator) { - if ($this->subject instanceof $type && $decorator instanceof PreparableSqlInterface) { - /** @var $decoratorForType PreparableSqlInterface|PlatformDecoratorInterface */ - $decoratorForType = $decorator; - break; - } - } - if ($decoratorForType) { - $decoratorForType->setSubject($this->subject); - $decoratorForType->prepareStatement($adapter, $statementContainer); - } else { - $this->subject->prepareStatement($adapter, $statementContainer); - } + $this->getTypeDecorator($this->subject)->prepareStatement($adapter, $statementContainer); + + return $statementContainer; } /** - * @param null|\Zend\Db\Adapter\Platform\PlatformInterface $adapterPlatform - * @return mixed + * {@inheritDoc} + * * @throws Exception\RuntimeException */ public function getSqlString(PlatformInterface $adapterPlatform = null) { - if (!$this->subject instanceof SqlInterface) { - throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\PreparableSqlInterface, thus calling prepareStatement() has no effect'); + if (! $this->subject instanceof SqlInterface) { + throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\SqlInterface, thus calling prepareStatement() has no effect'); } - $decoratorForType = false; - foreach ($this->decorators as $type => $decorator) { - if ($this->subject instanceof $type && $decorator instanceof SqlInterface) { - /** @var $decoratorForType SqlInterface|PlatformDecoratorInterface */ - $decoratorForType = $decorator; - break; - } - } - if ($decoratorForType) { - $decoratorForType->setSubject($this->subject); - return $decoratorForType->getSqlString($adapterPlatform); - } - - return $this->subject->getSqlString($adapterPlatform); + return $this->getTypeDecorator($this->subject)->getSqlString($adapterPlatform); } } diff --git a/library/Zend/Db/Sql/Platform/IbmDb2/SelectDecorator.php b/library/Zend/Db/Sql/Platform/IbmDb2/SelectDecorator.php index 47c15ee36..9df9398c8 100644 --- a/library/Zend/Db/Sql/Platform/IbmDb2/SelectDecorator.php +++ b/library/Zend/Db/Sql/Platform/IbmDb2/SelectDecorator.php @@ -9,11 +9,9 @@ namespace Zend\Db\Sql\Platform\IbmDb2; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\StatementContainerInterface; use Zend\Db\Sql\Platform\PlatformDecoratorInterface; use Zend\Db\Sql\Select; @@ -27,7 +25,7 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface /** * @var Select */ - protected $select = null; + protected $subject = null; /** * @return bool @@ -50,7 +48,7 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface */ public function setSubject($select) { - $this->select = $select; + $this->subject = $select; } /** @@ -61,40 +59,14 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface return $table . ' ' . $alias; } - /** - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function localizeVariables() { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } + parent::localizeVariables(); // set specifications unset($this->specifications[self::LIMIT]); unset($this->specifications[self::OFFSET]); $this->specifications['LIMITOFFSET'] = null; - parent::prepareStatement($adapter, $statementContainer); - } - - /** - * @param PlatformInterface $platform - * @return string - */ - public function getSqlString(PlatformInterface $platform = null) - { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } - - unset($this->specifications[self::LIMIT]); - unset($this->specifications[self::OFFSET]); - $this->specifications['LIMITOFFSET'] = null; - - return parent::getSqlString($platform); } /** diff --git a/library/Zend/Db/Sql/Platform/Mysql/Ddl/AlterTableDecorator.php b/library/Zend/Db/Sql/Platform/Mysql/Ddl/AlterTableDecorator.php new file mode 100644 index 000000000..34eadf4ec --- /dev/null +++ b/library/Zend/Db/Sql/Platform/Mysql/Ddl/AlterTableDecorator.php @@ -0,0 +1,246 @@ + 0, + 'zerofill' => 1, + 'identity' => 2, + 'serial' => 2, + 'autoincrement' => 2, + 'comment' => 3, + 'columnformat' => 4, + 'format' => 4, + 'storage' => 5, + ); + + /** + * @param AlterTable $subject + * @return \Zend\Db\Sql\Platform\PlatformDecoratorInterface + */ + public function setSubject($subject) + { + $this->subject = $subject; + + return $this; + } + + /** + * @param string $sql + * @return array + */ + protected function getSqlInsertOffsets($sql) + { + $sqlLength = strlen($sql); + $insertStart = array(); + + foreach (array('NOT NULL', 'NULL', 'DEFAULT', 'UNIQUE', 'PRIMARY', 'REFERENCES') as $needle) { + $insertPos = strpos($sql, ' ' . $needle); + + if ($insertPos !== false) { + switch ($needle) { + case 'REFERENCES': + $insertStart[2] = !isset($insertStart[2]) ? $insertPos : $insertStart[2]; + // no break + case 'PRIMARY': + case 'UNIQUE': + $insertStart[1] = !isset($insertStart[1]) ? $insertPos : $insertStart[1]; + // no break + default: + $insertStart[0] = !isset($insertStart[0]) ? $insertPos : $insertStart[0]; + } + } + } + + foreach (range(0, 3) as $i) { + $insertStart[$i] = isset($insertStart[$i]) ? $insertStart[$i] : $sqlLength; + } + + return $insertStart; + } + + /** + * @param PlatformInterface $adapterPlatform + * @return array + */ + protected function processAddColumns(PlatformInterface $adapterPlatform = null) + { + $sqls = array(); + + foreach ($this->addColumns as $i => $column) { + $sql = $this->processExpression($column, $adapterPlatform); + $insertStart = $this->getSqlInsertOffsets($sql); + $columnOptions = $column->getOptions(); + + uksort($columnOptions, array($this, 'compareColumnOptions')); + + foreach ($columnOptions as $coName => $coValue) { + $insert = ''; + + if (! $coValue) { + continue; + } + + switch ($this->normalizeColumnOption($coName)) { + case 'unsigned': + $insert = ' UNSIGNED'; + $j = 0; + break; + case 'zerofill': + $insert = ' ZEROFILL'; + $j = 0; + break; + case 'identity': + case 'serial': + case 'autoincrement': + $insert = ' AUTO_INCREMENT'; + $j = 1; + break; + case 'comment': + $insert = ' COMMENT ' . $adapterPlatform->quoteValue($coValue); + $j = 2; + break; + case 'columnformat': + case 'format': + $insert = ' COLUMN_FORMAT ' . strtoupper($coValue); + $j = 2; + break; + case 'storage': + $insert = ' STORAGE ' . strtoupper($coValue); + $j = 2; + break; + } + + if ($insert) { + $j = isset($j) ? $j : 0; + $sql = substr_replace($sql, $insert, $insertStart[$j], 0); + for (; $j < count($insertStart); ++$j) { + $insertStart[$j] += strlen($insert); + } + } + } + $sqls[$i] = $sql; + } + return array($sqls); + } + + /** + * @param PlatformInterface $adapterPlatform + * @return array + */ + protected function processChangeColumns(PlatformInterface $adapterPlatform = null) + { + $sqls = array(); + foreach ($this->changeColumns as $name => $column) { + $sql = $this->processExpression($column, $adapterPlatform); + $insertStart = $this->getSqlInsertOffsets($sql); + $columnOptions = $column->getOptions(); + + uksort($columnOptions, array($this, 'compareColumnOptions')); + + foreach ($columnOptions as $coName => $coValue) { + $insert = ''; + + if (! $coValue) { + continue; + } + + switch ($this->normalizeColumnOption($coName)) { + case 'unsigned': + $insert = ' UNSIGNED'; + $j = 0; + break; + case 'zerofill': + $insert = ' ZEROFILL'; + $j = 0; + break; + case 'identity': + case 'serial': + case 'autoincrement': + $insert = ' AUTO_INCREMENT'; + $j = 1; + break; + case 'comment': + $insert = ' COMMENT ' . $adapterPlatform->quoteValue($coValue); + $j = 2; + break; + case 'columnformat': + case 'format': + $insert = ' COLUMN_FORMAT ' . strtoupper($coValue); + $j = 2; + break; + case 'storage': + $insert = ' STORAGE ' . strtoupper($coValue); + $j = 2; + break; + } + + if ($insert) { + $j = isset($j) ? $j : 0; + $sql = substr_replace($sql, $insert, $insertStart[$j], 0); + for (; $j < count($insertStart); ++$j) { + $insertStart[$j] += strlen($insert); + } + } + } + $sqls[] = array( + $adapterPlatform->quoteIdentifier($name), + $sql + ); + } + + return array($sqls); + } + + /** + * @param string $name + * + * @return string + */ + private function normalizeColumnOption($name) + { + return strtolower(str_replace(array('-', '_', ' '), '', $name)); + } + + /** + * @internal @private this method is only public for PHP 5.3 compatibility purposes. + * + * @param string $columnA + * @param string $columnB + * + * @return int + */ + public function compareColumnOptions($columnA, $columnB) + { + $columnA = $this->normalizeColumnOption($columnA); + $columnA = isset($this->columnOptionSortOrder[$columnA]) + ? $this->columnOptionSortOrder[$columnA] : count($this->columnOptionSortOrder); + + $columnB = $this->normalizeColumnOption($columnB); + $columnB = isset($this->columnOptionSortOrder[$columnB]) + ? $this->columnOptionSortOrder[$columnB] : count($this->columnOptionSortOrder); + + return $columnA - $columnB; + } +} diff --git a/library/Zend/Db/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php b/library/Zend/Db/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php index 4206c8736..c24cdbad3 100644 --- a/library/Zend/Db/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php +++ b/library/Zend/Db/Sql/Platform/Mysql/Ddl/CreateTableDecorator.php @@ -18,69 +18,167 @@ class CreateTableDecorator extends CreateTable implements PlatformDecoratorInter /** * @var CreateTable */ - protected $createTable; + protected $subject; + + /** + * @var int[] + */ + protected $columnOptionSortOrder = array( + 'unsigned' => 0, + 'zerofill' => 1, + 'identity' => 2, + 'serial' => 2, + 'autoincrement' => 2, + 'comment' => 3, + 'columnformat' => 4, + 'format' => 4, + 'storage' => 5, + ); /** * @param CreateTable $subject + * + * @return self */ public function setSubject($subject) { - $this->createTable = $subject; + $this->subject = $subject; + + return $this; } /** - * @param null|PlatformInterface $platform - * @return string + * @param string $sql + * @return array */ - public function getSqlString(PlatformInterface $platform = null) + protected function getSqlInsertOffsets($sql) { - // localize variables - foreach (get_object_vars($this->createTable) as $name => $value) { - $this->{$name} = $value; + $sqlLength = strlen($sql); + $insertStart = array(); + + foreach (array('NOT NULL', 'NULL', 'DEFAULT', 'UNIQUE', 'PRIMARY', 'REFERENCES') as $needle) { + $insertPos = strpos($sql, ' ' . $needle); + + if ($insertPos !== false) { + switch ($needle) { + case 'REFERENCES': + $insertStart[2] = !isset($insertStart[2]) ? $insertPos : $insertStart[2]; + // no break + case 'PRIMARY': + case 'UNIQUE': + $insertStart[1] = !isset($insertStart[1]) ? $insertPos : $insertStart[1]; + // no break + default: + $insertStart[0] = !isset($insertStart[0]) ? $insertPos : $insertStart[0]; + } + } } - return parent::getSqlString($platform); + + foreach (range(0, 3) as $i) { + $insertStart[$i] = isset($insertStart[$i]) ? $insertStart[$i] : $sqlLength; + } + + return $insertStart; } + /** + * {@inheritDoc} + */ protected function processColumns(PlatformInterface $platform = null) { + if (! $this->columns) { + return; + } + $sqls = array(); + foreach ($this->columns as $i => $column) { - $stmtContainer = $this->processExpression($column, $platform); - $sql = $stmtContainer->getSql(); + $sql = $this->processExpression($column, $platform); + $insertStart = $this->getSqlInsertOffsets($sql); $columnOptions = $column->getOptions(); + uksort($columnOptions, array($this, 'compareColumnOptions')); + foreach ($columnOptions as $coName => $coValue) { - switch (strtolower(str_replace(array('-', '_', ' '), '', $coName))) { + $insert = ''; + + if (! $coValue) { + continue; + } + + switch ($this->normalizeColumnOption($coName)) { + case 'unsigned': + $insert = ' UNSIGNED'; + $j = 0; + break; + case 'zerofill': + $insert = ' ZEROFILL'; + $j = 0; + break; case 'identity': case 'serial': case 'autoincrement': - $sql .= ' AUTO_INCREMENT'; + $insert = ' AUTO_INCREMENT'; + $j = 1; break; - /* - case 'primary': - case 'primarykey': - $sql .= ' PRIMARY KEY'; - break; - case 'unique': - case 'uniquekey': - $sql .= ' UNIQUE KEY'; - break; - */ case 'comment': - $sql .= ' COMMENT \'' . $coValue . '\''; + $insert = ' COMMENT ' . $platform->quoteValue($coValue); + $j = 2; break; case 'columnformat': case 'format': - $sql .= ' COLUMN_FORMAT ' . strtoupper($coValue); + $insert = ' COLUMN_FORMAT ' . strtoupper($coValue); + $j = 2; break; case 'storage': - $sql .= ' STORAGE ' . strtoupper($coValue); + $insert = ' STORAGE ' . strtoupper($coValue); + $j = 2; break; } + + if ($insert) { + $j = isset($j) ? $j : 0; + $sql = substr_replace($sql, $insert, $insertStart[$j], 0); + for (; $j < count($insertStart); ++$j) { + $insertStart[$j] += strlen($insert); + } + } } - $stmtContainer->setSql($sql); - $sqls[$i] = $stmtContainer; + + $sqls[$i] = $sql; } + return array($sqls); } + + /** + * @param string $name + * + * @return string + */ + private function normalizeColumnOption($name) + { + return strtolower(str_replace(array('-', '_', ' '), '', $name)); + } + + /** + * @internal @private this method is only public for PHP 5.3 compatibility purposes. + * + * @param string $columnA + * @param string $columnB + * + * @return int + */ + public function compareColumnOptions($columnA, $columnB) + { + $columnA = $this->normalizeColumnOption($columnA); + $columnA = isset($this->columnOptionSortOrder[$columnA]) + ? $this->columnOptionSortOrder[$columnA] : count($this->columnOptionSortOrder); + + $columnB = $this->normalizeColumnOption($columnB); + $columnB = isset($this->columnOptionSortOrder[$columnB]) + ? $this->columnOptionSortOrder[$columnB] : count($this->columnOptionSortOrder); + + return $columnA - $columnB; + } } diff --git a/library/Zend/Db/Sql/Platform/Mysql/Mysql.php b/library/Zend/Db/Sql/Platform/Mysql/Mysql.php index 5b3f2deec..43873257b 100644 --- a/library/Zend/Db/Sql/Platform/Mysql/Mysql.php +++ b/library/Zend/Db/Sql/Platform/Mysql/Mysql.php @@ -17,5 +17,6 @@ class Mysql extends AbstractPlatform { $this->setTypeDecorator('Zend\Db\Sql\Select', new SelectDecorator()); $this->setTypeDecorator('Zend\Db\Sql\Ddl\CreateTable', new Ddl\CreateTableDecorator()); + $this->setTypeDecorator('Zend\Db\Sql\Ddl\AlterTable', new Ddl\AlterTableDecorator()); } } diff --git a/library/Zend/Db/Sql/Platform/Mysql/SelectDecorator.php b/library/Zend/Db/Sql/Platform/Mysql/SelectDecorator.php index 797be2c13..decf90910 100644 --- a/library/Zend/Db/Sql/Platform/Mysql/SelectDecorator.php +++ b/library/Zend/Db/Sql/Platform/Mysql/SelectDecorator.php @@ -9,11 +9,9 @@ namespace Zend\Db\Sql\Platform\Mysql; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\StatementContainerInterface; use Zend\Db\Sql\Platform\PlatformDecoratorInterface; use Zend\Db\Sql\Select; @@ -22,46 +20,22 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface /** * @var Select */ - protected $select = null; + protected $subject = null; /** * @param Select $select */ public function setSubject($select) { - $this->select = $select; + $this->subject = $select; } - /** - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function localizeVariables() { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } + parent::localizeVariables(); if ($this->limit === null && $this->offset !== null) { $this->specifications[self::LIMIT] = 'LIMIT 18446744073709551615'; } - parent::prepareStatement($adapter, $statementContainer); - } - - /** - * @param PlatformInterface $platform - * @return string - */ - public function getSqlString(PlatformInterface $platform = null) - { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } - if ($this->limit === null && $this->offset !== null) { - $this->specifications[self::LIMIT] = 'LIMIT 18446744073709551615'; - } - return parent::getSqlString($platform); } protected function processLimit(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) @@ -70,24 +44,22 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface return array(''); } if ($this->limit === null) { - return null; + return; } - if ($driver) { - $sql = $driver->formatParameterName('limit'); + if ($parameterContainer) { $parameterContainer->offsetSet('limit', $this->limit, ParameterContainer::TYPE_INTEGER); - } else { - $sql = $this->limit; + return array($driver->formatParameterName('limit')); } - return array($sql); + return array($this->limit); } protected function processOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->offset === null) { - return null; + return; } - if ($driver) { + if ($parameterContainer) { $parameterContainer->offsetSet('offset', $this->offset, ParameterContainer::TYPE_INTEGER); return array($driver->formatParameterName('offset')); } diff --git a/library/Zend/Db/Sql/Platform/Oracle/Oracle.php b/library/Zend/Db/Sql/Platform/Oracle/Oracle.php old mode 100755 new mode 100644 diff --git a/library/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php b/library/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php old mode 100755 new mode 100644 index 0fa9e4f1f..389d3b2ac --- a/library/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php +++ b/library/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php @@ -9,12 +9,9 @@ namespace Zend\Db\Sql\Platform\Oracle; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\StatementContainerInterface; -use Zend\Db\Sql\ExpressionInterface; use Zend\Db\Sql\Platform\PlatformDecoratorInterface; use Zend\Db\Sql\Select; @@ -23,14 +20,14 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface /** * @var Select */ - protected $select = null; + protected $subject = null; /** * @param Select $select */ public function setSubject($select) { - $this->select = $select; + $this->subject = $select; } /** @@ -38,44 +35,16 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface */ protected function renderTable($table, $alias = null) { - return $table . ' ' . $alias; + return $table . ($alias ? ' ' . $alias : ''); } - /** - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function localizeVariables() { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } - // set specifications + parent::localizeVariables(); unset($this->specifications[self::LIMIT]); unset($this->specifications[self::OFFSET]); $this->specifications['LIMITOFFSET'] = null; - parent::prepareStatement($adapter, $statementContainer); - } - - /** - * @param PlatformInterface $platform - * @return string - */ - public function getSqlString(PlatformInterface $platform = null) - { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } - - // set specifications - unset($this->specifications[self::LIMIT]); - unset($this->specifications[self::OFFSET]); - - $this->specifications['LIMITOFFSET'] = null; - return parent::getSqlString($platform); } /** @@ -89,7 +58,7 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface protected function processLimitOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null, &$sqls, &$parameters) { if ($this->limit === null && $this->offset === null) { - return null; + return; } $selectParameters = $parameters[self::SELECT]; @@ -145,36 +114,4 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface $this->specifications[self::SELECT], $parameters[self::SELECT] ); } - - - protected function processJoins(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) - { - if (!$this->joins) { - return null; - } - - // process joins - $joinSpecArgArray = array(); - foreach ($this->joins as $j => $join) { - $joinSpecArgArray[$j] = array(); - // type - $joinSpecArgArray[$j][] = strtoupper($join['type']); - // table name - $joinSpecArgArray[$j][] = (is_array($join['name'])) - ? $platform->quoteIdentifier(current($join['name'])) . ' ' . $platform->quoteIdentifier(key($join['name'])) - : $platform->quoteIdentifier($join['name']); - // on expression - $joinSpecArgArray[$j][] = ($join['on'] instanceof ExpressionInterface) - ? $this->processExpression($join['on'], $platform, $driver, $this->processInfo['paramPrefix'] . 'join') - : $platform->quoteIdentifierInFragment($join['on'], array('=', 'AND', 'OR', '(', ')', 'BETWEEN')); // on - if ($joinSpecArgArray[$j][2] instanceof StatementContainerInterface) { - if ($parameterContainer) { - $parameterContainer->merge($joinSpecArgArray[$j][2]->getParameterContainer()); - } - $joinSpecArgArray[$j][2] = $joinSpecArgArray[$j][2]->getSql(); - } - } - - return array($joinSpecArgArray); - } } diff --git a/library/Zend/Db/Sql/Platform/Platform.php b/library/Zend/Db/Sql/Platform/Platform.php index 381325377..886ed1933 100644 --- a/library/Zend/Db/Sql/Platform/Platform.php +++ b/library/Zend/Db/Sql/Platform/Platform.php @@ -10,6 +10,11 @@ namespace Zend\Db\Sql\Platform; use Zend\Db\Adapter\AdapterInterface; +use Zend\Db\Adapter\Platform\PlatformInterface; +use Zend\Db\Adapter\StatementContainerInterface; +use Zend\Db\Sql\Exception; +use Zend\Db\Sql\PreparableSqlInterface; +use Zend\Db\Sql\SqlInterface; class Platform extends AbstractPlatform { @@ -18,29 +23,143 @@ class Platform extends AbstractPlatform */ protected $adapter = null; + /** + * @var PlatformInterface|null + */ + protected $defaultPlatform; + public function __construct(AdapterInterface $adapter) { - $this->adapter = $adapter; - $platform = $adapter->getPlatform(); - switch (strtolower($platform->getName())) { - case 'mysql': - $platform = new Mysql\Mysql(); - $this->decorators = $platform->decorators; - break; - case 'sqlserver': - $platform = new SqlServer\SqlServer(); - $this->decorators = $platform->decorators; - break; - case 'oracle': - $platform = new Oracle\Oracle(); - $this->decorators = $platform->decorators; - break; - case 'ibm db2': - case 'ibm_db2': - case 'ibmdb2': - $platform = new IbmDb2\IbmDb2(); - $this->decorators = $platform->decorators; - default: + $this->defaultPlatform = $adapter->getPlatform(); + + $mySqlPlatform = new Mysql\Mysql(); + $sqlServerPlatform = new SqlServer\SqlServer(); + $oraclePlatform = new Oracle\Oracle(); + $ibmDb2Platform = new IbmDb2\IbmDb2(); + + $this->decorators['mysql'] = $mySqlPlatform->getDecorators(); + $this->decorators['sqlserver'] = $sqlServerPlatform->getDecorators(); + $this->decorators['oracle'] = $oraclePlatform->getDecorators(); + $this->decorators['ibmdb2'] = $ibmDb2Platform->getDecorators(); + } + + /** + * @param string $type + * @param PlatformDecoratorInterface $decorator + * @param AdapterInterface|PlatformInterface $adapterOrPlatform + */ + public function setTypeDecorator($type, PlatformDecoratorInterface $decorator, $adapterOrPlatform = null) + { + $platformName = $this->resolvePlatformName($adapterOrPlatform); + $this->decorators[$platformName][$type] = $decorator; + } + + /** + * @param PreparableSqlInterface|SqlInterface $subject + * @param AdapterInterface|PlatformInterface|null $adapterOrPlatform + * @return PlatformDecoratorInterface|PreparableSqlInterface|SqlInterface + */ + public function getTypeDecorator($subject, $adapterOrPlatform = null) + { + $platformName = $this->resolvePlatformName($adapterOrPlatform); + + if (isset($this->decorators[$platformName])) { + foreach ($this->decorators[$platformName] as $type => $decorator) { + if ($subject instanceof $type && is_a($decorator, $type, true)) { + $decorator->setSubject($subject); + return $decorator; + } + } } + + return $subject; + } + + /** + * @return array|PlatformDecoratorInterface[] + */ + public function getDecorators() + { + $platformName = $this->resolvePlatformName($this->getDefaultPlatform()); + return $this->decorators[$platformName]; + } + + /** + * {@inheritDoc} + * + * @throws Exception\RuntimeException + */ + public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + { + if (! $this->subject instanceof PreparableSqlInterface) { + throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\PreparableSqlInterface, thus calling prepareStatement() has no effect'); + } + + $this->getTypeDecorator($this->subject, $adapter)->prepareStatement($adapter, $statementContainer); + + return $statementContainer; + } + + /** + * {@inheritDoc} + * + * @throws Exception\RuntimeException + */ + public function getSqlString(PlatformInterface $adapterPlatform = null) + { + if (! $this->subject instanceof SqlInterface) { + throw new Exception\RuntimeException('The subject does not appear to implement Zend\Db\Sql\SqlInterface, thus calling prepareStatement() has no effect'); + } + + $adapterPlatform = $this->resolvePlatform($adapterPlatform); + + return $this->getTypeDecorator($this->subject, $adapterPlatform)->getSqlString($adapterPlatform); + } + + protected function resolvePlatformName($adapterOrPlatform) + { + $platformName = $this->resolvePlatform($adapterOrPlatform)->getName(); + return str_replace(array(' ', '_'), '', strtolower($platformName)); + } + /** + * @param null|PlatformInterface|AdapterInterface $adapterOrPlatform + * + * @return PlatformInterface + * + * @throws Exception\InvalidArgumentException + */ + protected function resolvePlatform($adapterOrPlatform) + { + if (! $adapterOrPlatform) { + return $this->getDefaultPlatform(); + } + + if ($adapterOrPlatform instanceof AdapterInterface) { + return $adapterOrPlatform->getPlatform(); + } + + if ($adapterOrPlatform instanceof PlatformInterface) { + return $adapterOrPlatform; + } + + throw new Exception\InvalidArgumentException(sprintf( + '$adapterOrPlatform should be null, %s, or %s', + 'Zend\Db\Adapter\AdapterInterface', + 'Zend\Db\Adapter\Platform\PlatformInterface' + )); + } + + /** + * @return PlatformInterface + * + * @throws Exception\RuntimeException + */ + protected function getDefaultPlatform() + { + if (! $this->defaultPlatform) { + throw new Exception\RuntimeException('$this->defaultPlatform was not set'); + } + + return $this->defaultPlatform; } } diff --git a/library/Zend/Db/Sql/Platform/PlatformDecoratorInterface.php b/library/Zend/Db/Sql/Platform/PlatformDecoratorInterface.php index d4384abae..6cda120d3 100644 --- a/library/Zend/Db/Sql/Platform/PlatformDecoratorInterface.php +++ b/library/Zend/Db/Sql/Platform/PlatformDecoratorInterface.php @@ -11,5 +11,10 @@ namespace Zend\Db\Sql\Platform; interface PlatformDecoratorInterface { + /** + * @param $subject + * + * @return self + */ public function setSubject($subject); } diff --git a/library/Zend/Db/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php b/library/Zend/Db/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php index c05a18f64..0a8ea8c37 100644 --- a/library/Zend/Db/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php +++ b/library/Zend/Db/Sql/Platform/SqlServer/Ddl/CreateTableDecorator.php @@ -18,7 +18,7 @@ class CreateTableDecorator extends CreateTable implements PlatformDecoratorInter /** * @var CreateTable */ - protected $createTable; + protected $subject; /** * @param CreateTable $subject @@ -26,36 +26,20 @@ class CreateTableDecorator extends CreateTable implements PlatformDecoratorInter */ public function setSubject($subject) { - $this->createTable = $subject; + $this->subject = $subject; return $this; } - /** - * @param null|PlatformInterface $platform - * @return string - */ - public function getSqlString(PlatformInterface $platform = null) - { - // localize variables - foreach (get_object_vars($this->createTable) as $name => $value) { - $this->{$name} = $value; - } - return parent::getSqlString($platform); - } - /** * @param PlatformInterface $adapterPlatform * @return array */ protected function processTable(PlatformInterface $adapterPlatform = null) { - $ret = array(''); - if ($this->isTemporary) { - $table = '#'; - } else { - $table = ''; - } - $ret[] = $adapterPlatform->quoteIdentifier($table . ltrim($this->table, '#')); - return $ret; + $table = ($this->isTemporary ? '#' : '') . ltrim($this->table, '#'); + return array( + '', + $adapterPlatform->quoteIdentifier($table), + ); } } diff --git a/library/Zend/Db/Sql/Platform/SqlServer/SelectDecorator.php b/library/Zend/Db/Sql/Platform/SqlServer/SelectDecorator.php index 3b085c183..e1da3f229 100644 --- a/library/Zend/Db/Sql/Platform/SqlServer/SelectDecorator.php +++ b/library/Zend/Db/Sql/Platform/SqlServer/SelectDecorator.php @@ -9,12 +9,9 @@ namespace Zend\Db\Sql\Platform\SqlServer; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Driver\Sqlsrv\Statement; -use Zend\Db\Adapter\StatementContainerInterface; use Zend\Db\Sql\Platform\PlatformDecoratorInterface; use Zend\Db\Sql\Select; @@ -23,57 +20,24 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface /** * @var Select */ - protected $select = null; + protected $subject = null; /** * @param Select $select */ public function setSubject($select) { - $this->select = $select; + $this->subject = $select; } - /** - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function localizeVariables() { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } - + parent::localizeVariables(); // set specifications unset($this->specifications[self::LIMIT]); unset($this->specifications[self::OFFSET]); $this->specifications['LIMITOFFSET'] = null; - parent::prepareStatement($adapter, $statementContainer); - - //set statement cursor type - if ($statementContainer instanceof Statement) { - $statementContainer->setPrepareOptions(array('Scrollable'=>\SQLSRV_CURSOR_STATIC)); - } - } - - /** - * @param PlatformInterface $platform - * @return string - */ - public function getSqlString(PlatformInterface $platform = null) - { - // localize variables - foreach (get_object_vars($this->select) as $name => $value) { - $this->{$name} = $value; - } - - // set specifications - unset($this->specifications[self::LIMIT]); - unset($this->specifications[self::OFFSET]); - - $this->specifications['LIMITOFFSET'] = null; - return parent::getSqlString($platform); } /** @@ -87,7 +51,7 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface protected function processLimitOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null, &$sqls, &$parameters) { if ($this->limit === null && $this->offset === null) { - return null; + return; } $selectParameters = $parameters[self::SELECT]; diff --git a/library/Zend/Db/Sql/Predicate/Between.php b/library/Zend/Db/Sql/Predicate/Between.php index 6c81b58ba..b927cdf4e 100644 --- a/library/Zend/Db/Sql/Predicate/Between.php +++ b/library/Zend/Db/Sql/Predicate/Between.php @@ -9,7 +9,9 @@ namespace Zend\Db\Sql\Predicate; -class Between implements PredicateInterface +use Zend\Db\Sql\AbstractExpression; + +class Between extends AbstractExpression implements PredicateInterface { protected $specification = '%1$s BETWEEN %2$s AND %3$s'; protected $identifier = null; @@ -131,11 +133,14 @@ class Between implements PredicateInterface */ public function getExpressionData() { + list($values[], $types[]) = $this->normalizeArgument($this->identifier, self::TYPE_IDENTIFIER); + list($values[], $types[]) = $this->normalizeArgument($this->minValue, self::TYPE_VALUE); + list($values[], $types[]) = $this->normalizeArgument($this->maxValue, self::TYPE_VALUE); return array( array( $this->getSpecification(), - array($this->identifier, $this->minValue, $this->maxValue), - array(self::TYPE_IDENTIFIER, self::TYPE_VALUE, self::TYPE_VALUE), + $values, + $types, ), ); } diff --git a/library/Zend/Db/Sql/Predicate/In.php b/library/Zend/Db/Sql/Predicate/In.php index b6697f598..7fcefcde6 100644 --- a/library/Zend/Db/Sql/Predicate/In.php +++ b/library/Zend/Db/Sql/Predicate/In.php @@ -11,14 +11,17 @@ namespace Zend\Db\Sql\Predicate; use Zend\Db\Sql\Exception; use Zend\Db\Sql\Select; +use Zend\Db\Sql\AbstractExpression; -class In implements PredicateInterface +class In extends AbstractExpression implements PredicateInterface { protected $identifier; protected $valueSet; protected $specification = '%s IN %s'; + protected $valueSpecSpecification = '%%s IN (%s)'; + /** * Constructor * @@ -116,12 +119,13 @@ class In implements PredicateInterface $replacements[] = $values; $types[] = self::TYPE_VALUE; } else { + foreach ($values as $argument) { + list($replacements[], $types[]) = $this->normalizeArgument($argument, self::TYPE_VALUE); + } $specification = vsprintf( $this->specification, array($identifierSpecFragment, '(' . implode(', ', array_fill(0, count($values), '%s')) . ')') ); - $replacements = array_merge($replacements, $values); - $types = array_merge($types, array_fill(0, count($values), self::TYPE_VALUE)); } return array(array( diff --git a/library/Zend/Db/Sql/Predicate/IsNull.php b/library/Zend/Db/Sql/Predicate/IsNull.php index 83931ba73..3ae953e5b 100644 --- a/library/Zend/Db/Sql/Predicate/IsNull.php +++ b/library/Zend/Db/Sql/Predicate/IsNull.php @@ -9,7 +9,9 @@ namespace Zend\Db\Sql\Predicate; -class IsNull implements PredicateInterface +use Zend\Db\Sql\AbstractExpression; + +class IsNull extends AbstractExpression implements PredicateInterface { /** * @var string @@ -84,10 +86,11 @@ class IsNull implements PredicateInterface */ public function getExpressionData() { + $identifier = $this->normalizeArgument($this->identifier, self::TYPE_IDENTIFIER); return array(array( $this->getSpecification(), - array($this->identifier), - array(self::TYPE_IDENTIFIER), + array($identifier[0]), + array($identifier[1]), )); } } diff --git a/library/Zend/Db/Sql/Predicate/Like.php b/library/Zend/Db/Sql/Predicate/Like.php index f4b143ab0..301340c6c 100644 --- a/library/Zend/Db/Sql/Predicate/Like.php +++ b/library/Zend/Db/Sql/Predicate/Like.php @@ -9,7 +9,9 @@ namespace Zend\Db\Sql\Predicate; -class Like implements PredicateInterface +use Zend\Db\Sql\AbstractExpression; + +class Like extends AbstractExpression implements PredicateInterface { /** * @var string @@ -99,8 +101,14 @@ class Like implements PredicateInterface */ public function getExpressionData() { + list($values[], $types[]) = $this->normalizeArgument($this->identifier, self::TYPE_IDENTIFIER); + list($values[], $types[]) = $this->normalizeArgument($this->like, self::TYPE_VALUE); return array( - array($this->specification, array($this->identifier, $this->like), array(self::TYPE_IDENTIFIER, self::TYPE_VALUE)) + array( + $this->specification, + $values, + $types, + ) ); } } diff --git a/library/Zend/Db/Sql/Predicate/NotLike.php b/library/Zend/Db/Sql/Predicate/NotLike.php index 8f4726993..0cd1afafe 100644 --- a/library/Zend/Db/Sql/Predicate/NotLike.php +++ b/library/Zend/Db/Sql/Predicate/NotLike.php @@ -9,7 +9,6 @@ namespace Zend\Db\Sql\Predicate; - class NotLike extends Like { protected $specification = '%1$s NOT LIKE %2$s'; diff --git a/library/Zend/Db/Sql/Predicate/Operator.php b/library/Zend/Db/Sql/Predicate/Operator.php index 7efb89942..2de5dfd35 100644 --- a/library/Zend/Db/Sql/Predicate/Operator.php +++ b/library/Zend/Db/Sql/Predicate/Operator.php @@ -10,8 +10,9 @@ namespace Zend\Db\Sql\Predicate; use Zend\Db\Sql\Exception; +use Zend\Db\Sql\AbstractExpression; -class Operator implements PredicateInterface +class Operator extends AbstractExpression implements PredicateInterface { const OPERATOR_EQUAL_TO = '='; const OP_EQ = '='; @@ -31,28 +32,55 @@ class Operator implements PredicateInterface const OPERATOR_GREATER_THAN_OR_EQUAL_TO = '>='; const OP_GTE = '>='; + /** + * {@inheritDoc} + */ protected $allowedTypes = array( self::TYPE_IDENTIFIER, self::TYPE_VALUE, ); - protected $left = null; - protected $leftType = self::TYPE_IDENTIFIER; - protected $operator = self::OPERATOR_EQUAL_TO; - protected $right = null; - protected $rightType = self::TYPE_VALUE; + /** + * @var int|float|bool|string + */ + protected $left; + + /** + * @var int|float|bool|string + */ + protected $right; + + /** + * @var string + */ + protected $leftType = self::TYPE_IDENTIFIER; + + /** + * @var string + */ + protected $rightType = self::TYPE_VALUE; + + /** + * @var string + */ + protected $operator = self::OPERATOR_EQUAL_TO; /** * Constructor * - * @param int|float|bool|string $left - * @param string $operator - * @param int|float|bool|string $right - * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} - * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} + * @param int|float|bool|string $left + * @param string $operator + * @param int|float|bool|string $right + * @param string $leftType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_IDENTIFIER {@see allowedTypes} + * @param string $rightType TYPE_IDENTIFIER or TYPE_VALUE by default TYPE_VALUE {@see allowedTypes} */ - public function __construct($left = null, $operator = self::OPERATOR_EQUAL_TO, $right = null, $leftType = self::TYPE_IDENTIFIER, $rightType = self::TYPE_VALUE) - { + public function __construct( + $left = null, + $operator = self::OPERATOR_EQUAL_TO, + $right = null, + $leftType = self::TYPE_IDENTIFIER, + $rightType = self::TYPE_VALUE + ) { if ($left !== null) { $this->setLeft($left); } @@ -78,11 +106,18 @@ class Operator implements PredicateInterface * Set left side of operator * * @param int|float|bool|string $left + * * @return Operator */ public function setLeft($left) { $this->left = $left; + + if (is_array($left)) { + $left = $this->normalizeArgument($left, $this->leftType); + $this->leftType = $left[1]; + } + return $this; } @@ -100,8 +135,10 @@ class Operator implements PredicateInterface * Set parameter type for left side of operator * * @param string $type TYPE_IDENTIFIER or TYPE_VALUE {@see allowedTypes} - * @throws Exception\InvalidArgumentException + * * @return Operator + * + * @throws Exception\InvalidArgumentException */ public function setLeftType($type) { @@ -113,7 +150,9 @@ class Operator implements PredicateInterface __CLASS__ . '::TYPE_VALUE' )); } + $this->leftType = $type; + return $this; } @@ -136,6 +175,7 @@ class Operator implements PredicateInterface public function setOperator($operator) { $this->operator = $operator; + return $this; } @@ -152,12 +192,19 @@ class Operator implements PredicateInterface /** * Set right side of operator * - * @param int|float|bool|string $value + * @param int|float|bool|string $right + * * @return Operator */ - public function setRight($value) + public function setRight($right) { - $this->right = $value; + $this->right = $right; + + if (is_array($right)) { + $right = $this->normalizeArgument($right, $this->rightType); + $this->rightType = $right[1]; + } + return $this; } @@ -188,7 +235,9 @@ class Operator implements PredicateInterface __CLASS__ . '::TYPE_VALUE' )); } + $this->rightType = $type; + return $this; } @@ -209,10 +258,13 @@ class Operator implements PredicateInterface */ public function getExpressionData() { + list($values[], $types[]) = $this->normalizeArgument($this->left, $this->leftType); + list($values[], $types[]) = $this->normalizeArgument($this->right, $this->rightType); + return array(array( '%s ' . $this->operator . ' %s', - array($this->left, $this->right), - array($this->leftType, $this->rightType) + $values, + $types )); } } diff --git a/library/Zend/Db/Sql/Predicate/Predicate.php b/library/Zend/Db/Sql/Predicate/Predicate.php index d650938dc..825bf1ca3 100644 --- a/library/Zend/Db/Sql/Predicate/Predicate.php +++ b/library/Zend/Db/Sql/Predicate/Predicate.php @@ -382,6 +382,27 @@ class Predicate extends PredicateSet return $this; } + /** + * Use given predicate directly + * + * Contrary to {@link addPredicate()} this method respects formerly set + * AND / OR combination operator, thus allowing generic predicates to be + * used fluently within where chains as any other concrete predicate. + * + * @param PredicateInterface $predicate + * @return Predicate + */ + public function predicate(PredicateInterface $predicate) + { + $this->addPredicate( + $predicate, + $this->nextPredicateCombineOperator ?: $this->defaultCombination + ); + $this->nextPredicateCombineOperator = null; + + return $this; + } + /** * Overloading * diff --git a/library/Zend/Db/Sql/Predicate/PredicateSet.php b/library/Zend/Db/Sql/Predicate/PredicateSet.php index bf62e8d4c..921d8fcb4 100644 --- a/library/Zend/Db/Sql/Predicate/PredicateSet.php +++ b/library/Zend/Db/Sql/Predicate/PredicateSet.php @@ -61,6 +61,13 @@ class PredicateSet implements PredicateInterface, Countable return $this; } + /** + * Add predicates to set + * + * @param PredicateInterface|\Closure|string|array $predicates + * @param string $combination + * @return PredicateSet + */ public function addPredicates($predicates, $combination = self::OP_AND) { if ($predicates === null) { @@ -91,7 +98,7 @@ class PredicateSet implements PredicateInterface, Countable $predicates = new Expression($pkey, $pvalue); } elseif ($pvalue === null) { // Otherwise, if still a string, do something intelligent with the PHP type provided // map PHP null to SQL IS NULL expression - $predicates = new IsNull($pkey, $pvalue); + $predicates = new IsNull($pkey); } elseif (is_array($pvalue)) { // if the value is an array, assume IN() is desired $predicates = new In($pkey, $pvalue); diff --git a/library/Zend/Db/Sql/PreparableSqlInterface.php b/library/Zend/Db/Sql/PreparableSqlInterface.php index dc66082cb..f5dc28514 100644 --- a/library/Zend/Db/Sql/PreparableSqlInterface.php +++ b/library/Zend/Db/Sql/PreparableSqlInterface.php @@ -15,8 +15,9 @@ use Zend\Db\Adapter\StatementContainerInterface; interface PreparableSqlInterface { /** - * @param AdapterInterface $adapter + * @param AdapterInterface $adapter * @param StatementContainerInterface $statementContainer + * * @return void */ public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer); diff --git a/library/Zend/Db/Sql/Select.php b/library/Zend/Db/Sql/Select.php index ccf1e4146..2596eb2cc 100644 --- a/library/Zend/Db/Sql/Select.php +++ b/library/Zend/Db/Sql/Select.php @@ -9,19 +9,16 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\DriverInterface; -use Zend\Db\Adapter\StatementContainerInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92 as AdapterSql92Platform; /** * * @property Where $where * @property Having $having */ -class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface +class Select extends AbstractPreparableSql { /**#@+ * Constant @@ -44,6 +41,8 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface const JOIN_OUTER = 'outer'; const JOIN_LEFT = 'left'; const JOIN_RIGHT = 'right'; + const JOIN_OUTER_RIGHT = 'outer right'; + const JOIN_OUTER_LEFT = 'outer left'; const SQL_STAR = '*'; const ORDER_ASCENDING = 'ASC'; const ORDER_DESCENDING = 'DESC'; @@ -475,65 +474,6 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; } - /** - * Prepare statement - * - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - * @return void - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) - { - // ensure statement has a ParameterContainer - $parameterContainer = $statementContainer->getParameterContainer(); - if (!$parameterContainer instanceof ParameterContainer) { - $parameterContainer = new ParameterContainer(); - $statementContainer->setParameterContainer($parameterContainer); - } - - $sqls = array(); - $parameters = array(); - $platform = $adapter->getPlatform(); - $driver = $adapter->getDriver(); - - foreach ($this->specifications as $name => $specification) { - $parameters[$name] = $this->{'process' . $name}($platform, $driver, $parameterContainer, $sqls, $parameters); - if ($specification && is_array($parameters[$name])) { - $sqls[$name] = $this->createSqlFromSpecificationAndParameters($specification, $parameters[$name]); - } - } - - $sql = implode(' ', $sqls); - - $statementContainer->setSql($sql); - return; - } - - /** - * Get SQL string for statement - * - * @param null|PlatformInterface $adapterPlatform If null, defaults to Sql92 - * @return string - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) - { - // get platform, or create default - $adapterPlatform = ($adapterPlatform) ?: new AdapterSql92Platform; - - $sqls = array(); - $parameters = array(); - - foreach ($this->specifications as $name => $specification) { - $parameters[$name] = $this->{'process' . $name}($adapterPlatform, null, null, $sqls, $parameters); - if ($specification && is_array($parameters[$name])) { - $sqls[$name] = $this->createSqlFromSpecificationAndParameters($specification, $parameters[$name]); - } - } - - $sql = implode(' ', $sqls); - return $sql; - } - /** * Returns whether the table is read only or not. * @@ -554,11 +494,7 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface */ protected function renderTable($table, $alias = null) { - $sql = $table; - if ($alias) { - $sql .= ' AS ' . $alias; - } - return $sql; + return $table . ($alias ? ' AS ' . $alias : ''); } protected function processStatementStart(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) @@ -587,70 +523,26 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface { $expr = 1; - if ($this->table) { - $table = $this->table; - $schema = $alias = null; - - if (is_array($table)) { - $alias = key($this->table); - $table = current($this->table); - } - - // create quoted table name to use in columns processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); - } - - if ($table instanceof Select) { - $table = '(' . $this->processSubselect($table, $platform, $driver, $parameterContainer) . ')'; - } else { - $table = $platform->quoteIdentifier($table); - } - - if ($schema) { - $table = $platform->quoteIdentifier($schema) . $platform->getIdentifierSeparator() . $table; - } - - if ($alias) { - $fromTable = $platform->quoteIdentifier($alias); - $table = $this->renderTable($table, $fromTable); - } else { - $fromTable = $table; - } - } else { - $fromTable = ''; - } - - if ($this->prefixColumnsWithTable) { - $fromTable .= $platform->getIdentifierSeparator(); - } else { - $fromTable = ''; - } - + list($table, $fromTable) = $this->resolveTable($this->table, $platform, $driver, $parameterContainer); // process table columns $columns = array(); foreach ($this->columns as $columnIndexOrAs => $column) { - $columnName = ''; if ($column === self::SQL_STAR) { $columns[] = array($fromTable . self::SQL_STAR); continue; } - if ($column instanceof ExpressionInterface) { - $columnParts = $this->processExpression( - $column, - $platform, - $driver, - $this->processInfo['paramPrefix'] . ((is_string($columnIndexOrAs)) ? $columnIndexOrAs : 'column') - ); - if ($parameterContainer) { - $parameterContainer->merge($columnParts->getParameterContainer()); - } - $columnName .= $columnParts->getSql(); - } else { - $columnName .= $fromTable . $platform->quoteIdentifier($column); - } - + $columnName = $this->resolveColumnValue( + array( + 'column' => $column, + 'fromTable' => $fromTable, + 'isIdentifier' => true, + ), + $platform, + $driver, + $parameterContainer, + (is_string($columnIndexOrAs) ? $columnIndexOrAs : 'column') + ); // process As portion if (is_string($columnIndexOrAs)) { $columnAs = $platform->quoteIdentifier($columnIndexOrAs); @@ -660,32 +552,27 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface $columns[] = (isset($columnAs)) ? array($columnName, $columnAs) : array($columnName); } - $separator = $platform->getIdentifierSeparator(); - // process join columns foreach ($this->joins as $join) { + $joinName = (is_array($join['name'])) ? key($join['name']) : $join['name']; + $joinName = parent::resolveTable($joinName, $platform, $driver, $parameterContainer); + foreach ($join['columns'] as $jKey => $jColumn) { $jColumns = array(); - if ($jColumn instanceof ExpressionInterface) { - $jColumnParts = $this->processExpression( - $jColumn, - $platform, - $driver, - $this->processInfo['paramPrefix'] . ((is_string($jKey)) ? $jKey : 'column') - ); - if ($parameterContainer) { - $parameterContainer->merge($jColumnParts->getParameterContainer()); - } - $jColumns[] = $jColumnParts->getSql(); - } else { - $name = (is_array($join['name'])) ? key($join['name']) : $name = $join['name']; - if ($name instanceof TableIdentifier) { - $name = ($name->hasSchema() ? $platform->quoteIdentifier($name->getSchema()) . $separator : '') . $platform->quoteIdentifier($name->getTable()); - } else { - $name = $platform->quoteIdentifier($name); - } - $jColumns[] = $name . $separator . $platform->quoteIdentifierInFragment($jColumn); - } + $jFromTable = is_scalar($jColumn) + ? $joinName . $platform->getIdentifierSeparator() + : ''; + $jColumns[] = $this->resolveColumnValue( + array( + 'column' => $jColumn, + 'fromTable' => $jFromTable, + 'isIdentifier' => true, + ), + $platform, + $driver, + $parameterContainer, + (is_string($jKey) ? $jKey : 'column') + ); if (is_string($jKey)) { $jColumns[] = $platform->quoteIdentifier($jKey); } elseif ($jColumn !== self::SQL_STAR) { @@ -696,15 +583,9 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface } if ($this->quantifier) { - if ($this->quantifier instanceof ExpressionInterface) { - $quantifierParts = $this->processExpression($this->quantifier, $platform, $driver, 'quantifier'); - if ($parameterContainer) { - $parameterContainer->merge($quantifierParts->getParameterContainer()); - } - $quantifier = $quantifierParts->getSql(); - } else { - $quantifier = $this->quantifier; - } + $quantifier = ($this->quantifier instanceof ExpressionInterface) + ? $this->processExpression($this->quantifier, $platform, $driver, $parameterContainer, 'quantifier') + : $this->quantifier; } if (!isset($table)) { @@ -719,19 +600,15 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface protected function processJoins(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if (!$this->joins) { - return null; + return; } // process joins $joinSpecArgArray = array(); foreach ($this->joins as $j => $join) { - $joinSpecArgArray[$j] = array(); $joinName = null; $joinAs = null; - // type - $joinSpecArgArray[$j][] = strtoupper($join['type']); - // table name if (is_array($join['name'])) { $joinName = current($join['name']); @@ -739,31 +616,30 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface } else { $joinName = $join['name']; } - if ($joinName instanceof ExpressionInterface) { + + if ($joinName instanceof Expression) { $joinName = $joinName->getExpression(); } elseif ($joinName instanceof TableIdentifier) { $joinName = $joinName->getTableAndSchema(); $joinName = ($joinName[1] ? $platform->quoteIdentifier($joinName[1]) . $platform->getIdentifierSeparator() : '') . $platform->quoteIdentifier($joinName[0]); + } elseif ($joinName instanceof Select) { + $joinName = '(' . $this->processSubSelect($joinName, $platform, $driver, $parameterContainer) . ')'; + } elseif (is_string($joinName) || (is_object($joinName) && is_callable(array($joinName, '__toString')))) { + $joinName = $platform->quoteIdentifier($joinName); } else { - if ($joinName instanceof Select) { - $joinName = '(' . $this->processSubSelect($joinName, $platform, $driver, $parameterContainer) . ')'; - } else { - $joinName = $platform->quoteIdentifier($joinName); - } + throw new Exception\InvalidArgumentException(sprintf('Join name expected to be Expression|TableIdentifier|Select|string, "%s" given', gettype($joinName))); } - $joinSpecArgArray[$j][] = (isset($joinAs)) ? $joinName . ' AS ' . $joinAs : $joinName; + + $joinSpecArgArray[$j] = array( + strtoupper($join['type']), + $this->renderTable($joinName, $joinAs), + ); // on expression // note: for Expression objects, pass them to processExpression with a prefix specific to each join (used for named parameters) $joinSpecArgArray[$j][] = ($join['on'] instanceof ExpressionInterface) - ? $this->processExpression($join['on'], $platform, $driver, $this->processInfo['paramPrefix'] . 'join' . ($j+1) . 'part') + ? $this->processExpression($join['on'], $platform, $driver, $parameterContainer, 'join' . ($j+1) . 'part') : $platform->quoteIdentifierInFragment($join['on'], array('=', 'AND', 'OR', '(', ')', 'BETWEEN', '<', '>')); // on - if ($joinSpecArgArray[$j][2] instanceof StatementContainerInterface) { - if ($parameterContainer) { - $parameterContainer->merge($joinSpecArgArray[$j][2]->getParameterContainer()); - } - $joinSpecArgArray[$j][2] = $joinSpecArgArray[$j][2]->getSql(); - } } return array($joinSpecArgArray); @@ -772,34 +648,31 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface protected function processWhere(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->where->count() == 0) { - return null; + return; } - $whereParts = $this->processExpression($this->where, $platform, $driver, $this->processInfo['paramPrefix'] . 'where'); - if ($parameterContainer) { - $parameterContainer->merge($whereParts->getParameterContainer()); - } - return array($whereParts->getSql()); + return array( + $this->processExpression($this->where, $platform, $driver, $parameterContainer, 'where') + ); } protected function processGroup(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->group === null) { - return null; + return; } // process table columns $groups = array(); foreach ($this->group as $column) { - $columnSql = ''; - if ($column instanceof Expression) { - $columnParts = $this->processExpression($column, $platform, $driver, $this->processInfo['paramPrefix'] . 'group'); - if ($parameterContainer) { - $parameterContainer->merge($columnParts->getParameterContainer()); - } - $columnSql .= $columnParts->getSql(); - } else { - $columnSql .= $platform->quoteIdentifierInFragment($column); - } - $groups[] = $columnSql; + $groups[] = $this->resolveColumnValue( + array( + 'column' => $column, + 'isIdentifier' => true, + ), + $platform, + $driver, + $parameterContainer, + 'group' + ); } return array($groups); } @@ -807,29 +680,24 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface protected function processHaving(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->having->count() == 0) { - return null; + return; } - $whereParts = $this->processExpression($this->having, $platform, $driver, $this->processInfo['paramPrefix'] . 'having'); - if ($parameterContainer) { - $parameterContainer->merge($whereParts->getParameterContainer()); - } - return array($whereParts->getSql()); + return array( + $this->processExpression($this->having, $platform, $driver, $parameterContainer, 'having') + ); } protected function processOrder(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if (empty($this->order)) { - return null; + return; } $orders = array(); foreach ($this->order as $k => $v) { if ($v instanceof ExpressionInterface) { - /** @var $orderParts \Zend\Db\Adapter\StatementContainer */ - $orderParts = $this->processExpression($v, $platform, $driver); - if ($parameterContainer) { - $parameterContainer->merge($orderParts->getParameterContainer()); - } - $orders[] = array($orderParts->getSql()); + $orders[] = array( + $this->processExpression($v, $platform, $driver, $parameterContainer) + ); continue; } if (is_int($k)) { @@ -852,56 +720,42 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface protected function processLimit(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->limit === null) { - return null; + return; } - - $limit = $this->limit; - - if ($driver) { - $sql = $driver->formatParameterName('limit'); - $parameterContainer->offsetSet('limit', $limit, ParameterContainer::TYPE_INTEGER); - } else { - $sql = $platform->quoteValue($limit); + if ($parameterContainer) { + $parameterContainer->offsetSet('limit', $this->limit, ParameterContainer::TYPE_INTEGER); + return array($driver->formatParameterName('limit')); } - - return array($sql); + return array($platform->quoteValue($this->limit)); } protected function processOffset(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->offset === null) { - return null; + return; } - - $offset = $this->offset; - - if ($driver) { - $parameterContainer->offsetSet('offset', $offset, ParameterContainer::TYPE_INTEGER); + if ($parameterContainer) { + $parameterContainer->offsetSet('offset', $this->offset, ParameterContainer::TYPE_INTEGER); return array($driver->formatParameterName('offset')); } - return array($platform->quoteValue($offset)); + return array($platform->quoteValue($this->offset)); } protected function processCombine(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { if ($this->combine == array()) { - return null; + return; } $type = $this->combine['type']; if ($this->combine['modifier']) { $type .= ' ' . $this->combine['modifier']; } - $type = strtoupper($type); - if ($driver) { - $sql = $this->processSubSelect($this->combine['select'], $platform, $driver, $parameterContainer); - return array($type, $sql); - } return array( - $type, - $this->processSubSelect($this->combine['select'], $platform) + strtoupper($type), + $this->processSubSelect($this->combine['select'], $platform, $driver, $parameterContainer), ); } @@ -936,4 +790,41 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface $this->where = clone $this->where; $this->having = clone $this->having; } + + /** + * @param string|TableIdentifier|Select $table + * @param PlatformInterface $platform + * @param DriverInterface $driver + * @param ParameterContainer $parameterContainer + * @return string + */ + protected function resolveTable($table, PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) + { + $alias = null; + + if (is_array($table)) { + $alias = key($table); + $table = current($table); + } + + $table = parent::resolveTable($table, $platform, $driver, $parameterContainer); + + if ($alias) { + $fromTable = $platform->quoteIdentifier($alias); + $table = $this->renderTable($table, $fromTable); + } else { + $fromTable = $table; + } + + if ($this->prefixColumnsWithTable && $fromTable) { + $fromTable .= $platform->getIdentifierSeparator(); + } else { + $fromTable = ''; + } + + return array( + $table, + $fromTable + ); + } } diff --git a/library/Zend/Db/Sql/Sql.php b/library/Zend/Db/Sql/Sql.php index e67ab3ff3..be46488a1 100644 --- a/library/Zend/Db/Sql/Sql.php +++ b/library/Zend/Db/Sql/Sql.php @@ -24,13 +24,18 @@ class Sql /** @var Platform\Platform */ protected $sqlPlatform = null; + /** + * @param AdapterInterface $adapter + * @param null|string|array|TableIdentifier $table + * @param null|Platform\AbstractPlatform $sqlPlatform @deprecated since version 3.0 + */ public function __construct(AdapterInterface $adapter, $table = null, Platform\AbstractPlatform $sqlPlatform = null) { $this->adapter = $adapter; if ($table) { $this->setTable($table); } - $this->sqlPlatform = ($sqlPlatform) ?: new Platform\Platform($adapter); + $this->sqlPlatform = $sqlPlatform ?: new Platform\Platform($adapter); } /** @@ -112,40 +117,48 @@ class Sql /** * @param PreparableSqlInterface $sqlObject - * @param StatementInterface|null $statement + * @param StatementInterface $statement + * @param AdapterInterface $adapter + * * @return StatementInterface */ - public function prepareStatementForSqlObject(PreparableSqlInterface $sqlObject, StatementInterface $statement = null) + public function prepareStatementForSqlObject(PreparableSqlInterface $sqlObject, StatementInterface $statement = null, AdapterInterface $adapter = null) { - $statement = ($statement) ?: $this->adapter->getDriver()->createStatement(); + $adapter = $adapter ?: $this->adapter; + $statement = $statement ?: $adapter->getDriver()->createStatement(); - if ($this->sqlPlatform) { - $this->sqlPlatform->setSubject($sqlObject); - $this->sqlPlatform->prepareStatement($this->adapter, $statement); - } else { - $sqlObject->prepareStatement($this->adapter, $statement); - } - - return $statement; + return $this->sqlPlatform->setSubject($sqlObject)->prepareStatement($adapter, $statement); } /** * Get sql string using platform or sql object * - * @param SqlInterface $sqlObject - * @param PlatformInterface $platform + * @param SqlInterface $sqlObject + * @param PlatformInterface|null $platform * * @return string + * + * @deprecated Deprecated in 2.4. Use buildSqlString() instead */ public function getSqlStringForSqlObject(SqlInterface $sqlObject, PlatformInterface $platform = null) { $platform = ($platform) ?: $this->adapter->getPlatform(); + return $this->sqlPlatform->setSubject($sqlObject)->getSqlString($platform); + } - if ($this->sqlPlatform) { - $this->sqlPlatform->setSubject($sqlObject); - return $this->sqlPlatform->getSqlString($platform); - } - - return $sqlObject->getSqlString($platform); + /** + * @param SqlInterface $sqlObject + * @param AdapterInterface $adapter + * + * @return string + * + * @throws Exception\InvalidArgumentException + */ + public function buildSqlString(SqlInterface $sqlObject, AdapterInterface $adapter = null) + { + return $this + ->sqlPlatform + ->setSubject($sqlObject) + ->getSqlString($adapter ? $adapter->getPlatform() : $this->adapter->getPlatform()); } } diff --git a/library/Zend/Db/Sql/SqlInterface.php b/library/Zend/Db/Sql/SqlInterface.php index 2e26eb315..81c1d03b4 100644 --- a/library/Zend/Db/Sql/SqlInterface.php +++ b/library/Zend/Db/Sql/SqlInterface.php @@ -14,7 +14,9 @@ use Zend\Db\Adapter\Platform\PlatformInterface; interface SqlInterface { /** - * @param PlatformInterface $adapterPlatform + * Get SQL string for statement + * + * @param null|PlatformInterface $adapterPlatform * * @return string */ diff --git a/library/Zend/Db/Sql/TableIdentifier.php b/library/Zend/Db/Sql/TableIdentifier.php index 79f20699f..c671d3e8e 100644 --- a/library/Zend/Db/Sql/TableIdentifier.php +++ b/library/Zend/Db/Sql/TableIdentifier.php @@ -19,22 +19,53 @@ class TableIdentifier protected $table; /** - * @var string + * @var null|string */ protected $schema; /** - * @param string $table - * @param string $schema + * @param string $table + * @param null|string $schema */ public function __construct($table, $schema = null) { - $this->table = $table; - $this->schema = $schema; + if (! (is_string($table) || is_callable(array($table, '__toString')))) { + throw new Exception\InvalidArgumentException(sprintf( + '$table must be a valid table name, parameter of type %s given', + is_object($table) ? get_class($table) : gettype($table) + )); + } + + $this->table = (string) $table; + + if ('' === $this->table) { + throw new Exception\InvalidArgumentException('$table must be a valid table name, empty string given'); + } + + if (null === $schema) { + $this->schema = null; + } else { + if (! (is_string($schema) || is_callable(array($schema, '__toString')))) { + throw new Exception\InvalidArgumentException(sprintf( + '$schema must be a valid schema name, parameter of type %s given', + is_object($schema) ? get_class($schema) : gettype($schema) + )); + } + + $this->schema = (string) $schema; + + if ('' === $this->schema) { + throw new Exception\InvalidArgumentException( + '$schema must be a valid schema name or null, empty string given' + ); + } + } } /** * @param string $table + * + * @deprecated please use the constructor and build a new {@see TableIdentifier} instead */ public function setTable($table) { @@ -59,6 +90,8 @@ class TableIdentifier /** * @param $schema + * + * @deprecated please use the constructor and build a new {@see TableIdentifier} instead */ public function setSchema($schema) { diff --git a/library/Zend/Db/Sql/Update.php b/library/Zend/Db/Sql/Update.php index 33fbcac09..8c27a1de0 100644 --- a/library/Zend/Db/Sql/Update.php +++ b/library/Zend/Db/Sql/Update.php @@ -9,18 +9,16 @@ namespace Zend\Db\Sql; -use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\ParameterContainer; use Zend\Db\Adapter\Platform\PlatformInterface; -use Zend\Db\Adapter\Platform\Sql92; -use Zend\Db\Adapter\StatementContainerInterface; +use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Stdlib\PriorityList; /** * * @property Where $where */ -class Update extends AbstractSql implements SqlInterface, PreparableSqlInterface +class Update extends AbstractPreparableSql { /**@#++ * @const @@ -117,7 +115,7 @@ class Update extends AbstractSql implements SqlInterface, PreparableSqlInterface * @param Where|\Closure|string|array $predicate * @param string $combination One of the OP_* constants from Predicate\PredicateSet * @throws Exception\InvalidArgumentException - * @return Select + * @return Update */ public function where($predicate, $combination = Predicate\PredicateSet::OP_AND) { @@ -140,104 +138,40 @@ class Update extends AbstractSql implements SqlInterface, PreparableSqlInterface return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState; } - /** - * Prepare statement - * - * @param AdapterInterface $adapter - * @param StatementContainerInterface $statementContainer - * @return void - */ - public function prepareStatement(AdapterInterface $adapter, StatementContainerInterface $statementContainer) + protected function processUpdate(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - $driver = $adapter->getDriver(); - $platform = $adapter->getPlatform(); - $parameterContainer = $statementContainer->getParameterContainer(); - - if (!$parameterContainer instanceof ParameterContainer) { - $parameterContainer = new ParameterContainer(); - $statementContainer->setParameterContainer($parameterContainer); - } - - $table = $this->table; - $schema = null; - - // create quoted table name to use in update processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); - } - - $table = $platform->quoteIdentifier($table); - - if ($schema) { - $table = $platform->quoteIdentifier($schema) . $platform->getIdentifierSeparator() . $table; - } - $setSql = array(); foreach ($this->set as $column => $value) { - if ($value instanceof Expression) { - $exprData = $this->processExpression($value, $platform, $driver); - $setSql[] = $platform->quoteIdentifier($column) . ' = ' . $exprData->getSql(); - $parameterContainer->merge($exprData->getParameterContainer()); - } else { - $setSql[] = $platform->quoteIdentifier($column) . ' = ' . $driver->formatParameterName($column); + $prefix = $platform->quoteIdentifier($column) . ' = '; + if (is_scalar($value) && $parameterContainer) { + $setSql[] = $prefix . $driver->formatParameterName($column); $parameterContainer->offsetSet($column, $value); + } else { + $setSql[] = $prefix . $this->resolveColumnValue( + $value, + $platform, + $driver, + $parameterContainer + ); } } - $set = implode(', ', $setSql); - $sql = sprintf($this->specifications[static::SPECIFICATION_UPDATE], $table, $set); - - // process where - if ($this->where->count() > 0) { - $whereParts = $this->processExpression($this->where, $platform, $driver, 'where'); - $parameterContainer->merge($whereParts->getParameterContainer()); - $sql .= ' ' . sprintf($this->specifications[static::SPECIFICATION_WHERE], $whereParts->getSql()); - } - $statementContainer->setSql($sql); + return sprintf( + $this->specifications[static::SPECIFICATION_UPDATE], + $this->resolveTable($this->table, $platform, $driver, $parameterContainer), + implode(', ', $setSql) + ); } - /** - * Get SQL string for statement - * - * @param null|PlatformInterface $adapterPlatform If null, defaults to Sql92 - * @return string - */ - public function getSqlString(PlatformInterface $adapterPlatform = null) + protected function processWhere(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { - $adapterPlatform = ($adapterPlatform) ?: new Sql92; - $table = $this->table; - $schema = null; - - // create quoted table name to use in update processing - if ($table instanceof TableIdentifier) { - list($table, $schema) = $table->getTableAndSchema(); + if ($this->where->count() == 0) { + return; } - - $table = $adapterPlatform->quoteIdentifier($table); - - if ($schema) { - $table = $adapterPlatform->quoteIdentifier($schema) . $adapterPlatform->getIdentifierSeparator() . $table; - } - - $setSql = array(); - foreach ($this->set as $column => $value) { - if ($value instanceof ExpressionInterface) { - $exprData = $this->processExpression($value, $adapterPlatform); - $setSql[] = $adapterPlatform->quoteIdentifier($column) . ' = ' . $exprData->getSql(); - } elseif ($value === null) { - $setSql[] = $adapterPlatform->quoteIdentifier($column) . ' = NULL'; - } else { - $setSql[] = $adapterPlatform->quoteIdentifier($column) . ' = ' . $adapterPlatform->quoteValue($value); - } - } - $set = implode(', ', $setSql); - - $sql = sprintf($this->specifications[static::SPECIFICATION_UPDATE], $table, $set); - if ($this->where->count() > 0) { - $whereParts = $this->processExpression($this->where, $adapterPlatform, null, 'where'); - $sql .= ' ' . sprintf($this->specifications[static::SPECIFICATION_WHERE], $whereParts->getSql()); - } - return $sql; + return sprintf( + $this->specifications[static::SPECIFICATION_WHERE], + $this->processExpression($this->where, $platform, $driver, $parameterContainer, 'where') + ); } /** @@ -250,9 +184,8 @@ class Update extends AbstractSql implements SqlInterface, PreparableSqlInterface */ public function __get($name) { - switch (strtolower($name)) { - case 'where': - return $this->where; + if (strtolower($name) == 'where') { + return $this->where; } } diff --git a/library/Zend/Db/TableGateway/AbstractTableGateway.php b/library/Zend/Db/TableGateway/AbstractTableGateway.php index a98d19301..43037259d 100644 --- a/library/Zend/Db/TableGateway/AbstractTableGateway.php +++ b/library/Zend/Db/TableGateway/AbstractTableGateway.php @@ -40,7 +40,7 @@ abstract class AbstractTableGateway implements TableGatewayInterface protected $adapter = null; /** - * @var string + * @var string|array|TableIdentifier */ protected $table = null; @@ -216,8 +216,13 @@ abstract class AbstractTableGateway implements TableGatewayInterface protected function executeSelect(Select $select) { $selectState = $select->getRawState(); - if ($selectState['table'] != $this->table && (is_array($selectState['table']) && end($selectState['table']) != $this->table)) { - throw new Exception\RuntimeException('The table name of the provided select object must match that of the table'); + if ($selectState['table'] != $this->table + && (is_array($selectState['table']) + && end($selectState['table']) != $this->table) + ) { + throw new Exception\RuntimeException( + 'The table name of the provided select object must match that of the table' + ); } if ($selectState['columns'] == array(Select::SQL_STAR) @@ -281,12 +286,23 @@ abstract class AbstractTableGateway implements TableGatewayInterface { $insertState = $insert->getRawState(); if ($insertState['table'] != $this->table) { - throw new Exception\RuntimeException('The table name of the provided Insert object must match that of the table'); + throw new Exception\RuntimeException( + 'The table name of the provided Insert object must match that of the table' + ); } // apply preInsert features $this->featureSet->apply(EventFeature::EVENT_PRE_INSERT, array($insert)); + // Most RDBMS solutions do not allow using table aliases in INSERTs + // See https://github.com/zendframework/zf2/issues/7311 + $unaliasedTable = false; + if (is_array($insertState['table'])) { + $tableData = array_values($insertState['table']); + $unaliasedTable = array_shift($tableData); + $insert->into($unaliasedTable); + } + $statement = $this->sql->prepareStatementForSqlObject($insert); $result = $statement->execute(); $this->lastInsertValue = $this->adapter->getDriver()->getConnection()->getLastGeneratedValue(); @@ -294,7 +310,13 @@ abstract class AbstractTableGateway implements TableGatewayInterface // apply postInsert features $this->featureSet->apply(EventFeature::EVENT_POST_INSERT, array($statement, $result)); - return $result->getAffectedRows(); + // Reset original table information in Insert instance, if necessary + if ($unaliasedTable) { + $insert->into($insertState['table']); + } + + $return = $result->getAffectedRows(); + return $return; } /** @@ -341,7 +363,9 @@ abstract class AbstractTableGateway implements TableGatewayInterface { $updateState = $update->getRawState(); if ($updateState['table'] != $this->table) { - throw new Exception\RuntimeException('The table name of the provided Update object must match that of the table'); + throw new Exception\RuntimeException( + 'The table name of the provided Update object must match that of the table' + ); } // apply preUpdate features @@ -397,7 +421,9 @@ abstract class AbstractTableGateway implements TableGatewayInterface { $deleteState = $delete->getRawState(); if ($deleteState['table'] != $this->table) { - throw new Exception\RuntimeException('The table name of the provided Update object must match that of the table'); + throw new Exception\RuntimeException( + 'The table name of the provided Update object must match that of the table' + ); } // pre delete update @@ -470,7 +496,11 @@ abstract class AbstractTableGateway implements TableGatewayInterface if ($this->featureSet->canCallMagicCall($method)) { return $this->featureSet->callMagicCall($method, $arguments); } - throw new Exception\InvalidArgumentException('Invalid method (' . $method . ') called, caught by ' . __CLASS__ . '::__call()'); + throw new Exception\InvalidArgumentException(sprintf( + 'Invalid method (%s) called, caught by %s::__call()', + $method, + __CLASS__ + )); } /** diff --git a/library/Zend/Db/TableGateway/Feature/RowGatewayFeature.php b/library/Zend/Db/TableGateway/Feature/RowGatewayFeature.php index 1bae69e81..88f07097b 100644 --- a/library/Zend/Db/TableGateway/Feature/RowGatewayFeature.php +++ b/library/Zend/Db/TableGateway/Feature/RowGatewayFeature.php @@ -45,7 +45,7 @@ class RowGatewayFeature extends AbstractFeature if (isset($args[0])) { if (is_string($args[0])) { $primaryKey = $args[0]; - $rowGatewayPrototype = new RowGateway($primaryKey, $this->tableGateway->table, $this->tableGateway->adapter, $this->tableGateway->sql); + $rowGatewayPrototype = new RowGateway($primaryKey, $this->tableGateway->table, $this->tableGateway->adapter); $resultSetPrototype->setArrayObjectPrototype($rowGatewayPrototype); } elseif ($args[0] instanceof RowGatewayInterface) { $rowGatewayPrototype = $args[0]; @@ -60,7 +60,7 @@ class RowGatewayFeature extends AbstractFeature ); } $primaryKey = $metadata->sharedData['metadata']['primaryKey']; - $rowGatewayPrototype = new RowGateway($primaryKey, $this->tableGateway->table, $this->tableGateway->adapter, $this->tableGateway->sql); + $rowGatewayPrototype = new RowGateway($primaryKey, $this->tableGateway->table, $this->tableGateway->adapter); $resultSetPrototype->setArrayObjectPrototype($rowGatewayPrototype); } } diff --git a/library/Zend/Db/TableGateway/Feature/SequenceFeature.php b/library/Zend/Db/TableGateway/Feature/SequenceFeature.php index b9f1dd484..fa34068ae 100644 --- a/library/Zend/Db/TableGateway/Feature/SequenceFeature.php +++ b/library/Zend/Db/TableGateway/Feature/SequenceFeature.php @@ -92,7 +92,7 @@ class SequenceFeature extends AbstractFeature $sql = 'SELECT NEXTVAL(\'"' . $this->sequenceName . '"\')'; break; default : - return null; + return; } $statement = $this->tableGateway->adapter->createStatement(); @@ -120,7 +120,7 @@ class SequenceFeature extends AbstractFeature $sql = 'SELECT CURRVAL(\'' . $this->sequenceName . '\')'; break; default : - return null; + return; } $statement = $this->tableGateway->adapter->createStatement(); diff --git a/library/Zend/Db/TableGateway/TableGateway.php b/library/Zend/Db/TableGateway/TableGateway.php index 79c989bf0..62604f6a2 100644 --- a/library/Zend/Db/TableGateway/TableGateway.php +++ b/library/Zend/Db/TableGateway/TableGateway.php @@ -20,11 +20,12 @@ class TableGateway extends AbstractTableGateway /** * Constructor * - * @param string $table - * @param AdapterInterface $adapter - * @param Feature\AbstractFeature|Feature\FeatureSet|Feature\AbstractFeature[] $features - * @param ResultSetInterface $resultSetPrototype - * @param Sql $sql + * @param string|TableIdentifier|array $table + * @param AdapterInterface $adapter + * @param Feature\AbstractFeature|Feature\FeatureSet|Feature\AbstractFeature[]|null $features + * @param ResultSetInterface|null $resultSetPrototype + * @param Sql|null $sql + * * @throws Exception\InvalidArgumentException */ public function __construct($table, AdapterInterface $adapter, $features = null, ResultSetInterface $resultSetPrototype = null, Sql $sql = null) diff --git a/library/Zend/Db/composer.json b/library/Zend/Db/composer.json old mode 100755 new mode 100644 index c80e3344a..31596ab59 --- a/library/Zend/Db/composer.json +++ b/library/Zend/Db/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Db\\": "" } }, - "target-dir": "Zend/Db", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Debug/composer.json b/library/Zend/Debug/composer.json index 8846ed728..9a419f454 100644 --- a/library/Zend/Debug/composer.json +++ b/library/Zend/Debug/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Debug\\": "" } }, - "target-dir": "Zend/Debug", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Di/Definition/ArrayDefinition.php b/library/Zend/Di/Definition/ArrayDefinition.php index c089962e8..6415f8a3c 100644 --- a/library/Zend/Di/Definition/ArrayDefinition.php +++ b/library/Zend/Di/Definition/ArrayDefinition.php @@ -80,7 +80,7 @@ class ArrayDefinition implements DefinitionInterface public function getInstantiator($class) { if (!isset($this->dataArray[$class])) { - return null; + return; } if (!isset($this->dataArray[$class]['instantiator'])) { diff --git a/library/Zend/Di/Definition/Builder/InjectionMethod.php b/library/Zend/Di/Definition/Builder/InjectionMethod.php index 9160aacd8..b411504d4 100644 --- a/library/Zend/Di/Definition/Builder/InjectionMethod.php +++ b/library/Zend/Di/Definition/Builder/InjectionMethod.php @@ -98,22 +98,16 @@ class InjectionMethod case "require": case "required": return Di::METHOD_IS_REQUIRED; - break; case "aware": return Di::METHOD_IS_AWARE; - break; case "optional": return Di::METHOD_IS_OPTIONAL; - break; case "constructor": return Di::METHOD_IS_CONSTRUCTOR; - break; case "instantiator": return Di::METHOD_IS_INSTANTIATOR; - break; case "eager": return Di::METHOD_IS_EAGER; - break; } } return 0; diff --git a/library/Zend/Di/Definition/ClassDefinition.php b/library/Zend/Di/Definition/ClassDefinition.php index 42b1ab0ba..764cfff81 100644 --- a/library/Zend/Di/Definition/ClassDefinition.php +++ b/library/Zend/Di/Definition/ClassDefinition.php @@ -162,7 +162,7 @@ class ClassDefinition implements DefinitionInterface, PartialMarker public function getInstantiator($class) { if ($this->class !== $class) { - return null; + return; } return $this->instantiator; } @@ -192,14 +192,14 @@ class ClassDefinition implements DefinitionInterface, PartialMarker public function hasMethod($class, $method) { if ($this->class !== $class) { - return null; + return; } if (is_array($this->methods)) { return array_key_exists($method, $this->methods); } - return null; + return; } /** @@ -219,13 +219,13 @@ class ClassDefinition implements DefinitionInterface, PartialMarker public function getMethodParameters($class, $method) { if ($this->class !== $class) { - return null; + return; } if (array_key_exists($method, $this->methodParameters)) { return $this->methodParameters[$method]; } - return null; + return; } } diff --git a/library/Zend/Di/Definition/RuntimeDefinition.php b/library/Zend/Di/Definition/RuntimeDefinition.php index 66fbaedf5..45ab6bfd5 100644 --- a/library/Zend/Di/Definition/RuntimeDefinition.php +++ b/library/Zend/Di/Definition/RuntimeDefinition.php @@ -38,6 +38,11 @@ class RuntimeDefinition implements DefinitionInterface */ protected $injectionMethods = array(); + /** + * @var array + */ + protected $processedClass = array(); + /** * Constructor * @@ -174,25 +179,20 @@ class RuntimeDefinition implements DefinitionInterface return $this->classes[$class]['parameters'][$method]; } - /** - * @param string $class - * - * @return bool - */ - protected function hasProcessedClass($class) - { - return array_key_exists($class, $this->classes) && is_array($this->classes[$class]); - } - /** * @param string $class * @param bool $forceLoad */ protected function processClass($class, $forceLoad = false) { - if (!$forceLoad && $this->hasProcessedClass($class)) { + if (!isset($this->processedClass[$class]) || $this->processedClass[$class] === false) { + $this->processedClass[$class] = (array_key_exists($class, $this->classes) && is_array($this->classes[$class])); + } + + if (!$forceLoad && $this->processedClass[$class]) { return; } + $strategy = $this->introspectionStrategy; // localize for readability /** @var $rClass \Zend\Code\Reflection\ClassReflection */ @@ -231,7 +231,7 @@ class RuntimeDefinition implements DefinitionInterface $rTarget = $rTargetParent; } while (true); - $def['supertypes'] = $supertypes; + $def['supertypes'] = array_keys(array_flip($supertypes)); if ($def['instantiator'] == null) { if ($rClass->isInstantiable()) { diff --git a/library/Zend/Di/DefinitionList.php b/library/Zend/Di/DefinitionList.php index 0f0c3c7cb..43f03717d 100644 --- a/library/Zend/Di/DefinitionList.php +++ b/library/Zend/Di/DefinitionList.php @@ -10,22 +10,27 @@ namespace Zend\Di; use SplDoublyLinkedList; +use Zend\Di\Definition\RuntimeDefinition; /** * Class definition based on multiple definitions */ class DefinitionList extends SplDoublyLinkedList implements Definition\DefinitionInterface { + protected $classes = array(); + protected $runtimeDefinitions; + /** * @param Definition\DefinitionInterface|Definition\DefinitionInterface[] $definitions */ public function __construct($definitions) { + $this->runtimeDefinitions = new SplDoublyLinkedList(); if (!is_array($definitions)) { $definitions = array($definitions); } foreach ($definitions as $definition) { - $this->push($definition); + $this->addDefinition($definition, true); } } @@ -45,6 +50,35 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio } } + protected function getDefinitionClassMap(Definition\DefinitionInterface $definition) + { + $definitionClasses = $definition->getClasses(); + if (empty($definitionClasses)) { + return array(); + } + return array_combine(array_values($definitionClasses), array_fill(0, count($definitionClasses), $definition)); + } + + public function unshift($definition) + { + $result = parent::unshift($definition); + if ($definition instanceof RuntimeDefinition) { + $this->runtimeDefinitions->unshift($definition); + } + $this->classes = array_merge($this->classes, $this->getDefinitionClassMap($definition)); + return $result; + } + + public function push($definition) + { + $result = parent::push($definition); + if ($definition instanceof RuntimeDefinition) { + $this->runtimeDefinitions->push($definition); + } + $this->classes = array_merge($this->getDefinitionClassMap($definition), $this->classes); + return $result; + } + /** * @param string $type * @return Definition\DefinitionInterface[] @@ -84,8 +118,11 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function getDefinitionForClass($class) { + if (array_key_exists($class, $this->classes)) { + return $this->classes[$class]; + } /** @var $definition Definition\DefinitionInterface */ - foreach ($this as $definition) { + foreach ($this->runtimeDefinitions as $definition) { if ($definition->hasClass($class)) { return $definition; } @@ -108,13 +145,7 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function getClasses() { - $classes = array(); - /** @var $definition Definition\DefinitionInterface */ - foreach ($this as $definition) { - $classes = array_merge($classes, $definition->getClasses()); - } - - return $classes; + return array_keys($this->classes); } /** @@ -122,8 +153,11 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function hasClass($class) { + if (array_key_exists($class, $this->classes)) { + return true; + } /** @var $definition Definition\DefinitionInterface */ - foreach ($this as $definition) { + foreach ($this->runtimeDefinitions as $definition) { if ($definition->hasClass($class)) { return true; } @@ -137,9 +171,18 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function getClassSupertypes($class) { - $supertypes = array(); + if (false === ($classDefinition = $this->getDefinitionForClass($class))) { + return array(); + } + $supertypes = $classDefinition->getClassSupertypes($class); + if (! $classDefinition instanceof Definition\PartialMarker) { + return $supertypes; + } /** @var $definition Definition\DefinitionInterface */ foreach ($this as $definition) { + if ($definition === $classDefinition) { + continue; + } if ($definition->hasClass($class)) { $supertypes = array_merge($supertypes, $definition->getClassSupertypes($class)); if ($definition instanceof Definition\PartialMarker) { @@ -157,8 +200,21 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function getInstantiator($class) { + if (! $classDefinition = $this->getDefinitionForClass($class)) { + return false; + } + $value = $classDefinition->getInstantiator($class); + if (!is_null($value)) { + return $value; + } + if (! $classDefinition instanceof Definition\PartialMarker) { + return false; + } /** @var $definition Definition\DefinitionInterface */ foreach ($this as $definition) { + if ($definition === $classDefinition) { + continue; + } if ($definition->hasClass($class)) { $value = $definition->getInstantiator($class); if ($value === null && $definition instanceof Definition\PartialMarker) { @@ -177,8 +233,20 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function hasMethods($class) { + if (! $classDefinition = $this->getDefinitionForClass($class)) { + return false; + } + if (false !== ($methods = $classDefinition->hasMethods($class))) { + return $methods; + } + if (! $classDefinition instanceof Definition\PartialMarker) { + return false; + } /** @var $definition Definition\DefinitionInterface */ foreach ($this as $definition) { + if ($definition === $classDefinition) { + continue; + } if ($definition->hasClass($class)) { if ($definition->hasMethods($class) === false && $definition instanceof Definition\PartialMarker) { continue; @@ -199,9 +267,15 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio if (!$this->hasMethods($class)) { return false; } - + $classDefinition = $this->getDefinitionForClass($class); + if ($classDefinition->hasMethod($class, $method)) { + return true; + } /** @var $definition Definition\DefinitionInterface */ - foreach ($this as $definition) { + foreach ($this->runtimeDefinitions as $definition) { + if ($definition === $classDefinition) { + continue; + } if ($definition->hasClass($class) && $definition->hasMethod($class, $method)) { return true; } @@ -215,9 +289,18 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function getMethods($class) { + if (false === ($classDefinition = $this->getDefinitionForClass($class))) { + return array(); + } + $methods = $classDefinition->getMethods($class); + if (! $classDefinition instanceof Definition\PartialMarker) { + return $methods; + } /** @var $definition Definition\DefinitionInterface */ - $methods = array(); foreach ($this as $definition) { + if ($definition === $classDefinition) { + continue; + } if ($definition->hasClass($class)) { if (!$definition instanceof Definition\PartialMarker) { return array_merge($definition->getMethods($class), $methods); @@ -245,9 +328,21 @@ class DefinitionList extends SplDoublyLinkedList implements Definition\Definitio */ public function getMethodParameters($class, $method) { + if (false === ($classDefinition = $this->getDefinitionForClass($class))) { + return array(); + } + if ($classDefinition->hasMethod($class, $method) && $classDefinition->hasMethodParameters($class, $method)) { + return $classDefinition->getMethodParameters($class, $method); + } /** @var $definition Definition\DefinitionInterface */ foreach ($this as $definition) { - if ($definition->hasClass($class) && $definition->hasMethod($class, $method) && $definition->hasMethodParameters($class, $method)) { + if ($definition === $classDefinition) { + continue; + } + if ($definition->hasClass($class) + && $definition->hasMethod($class, $method) + && $definition->hasMethodParameters($class, $method) + ) { return $definition->getMethodParameters($class, $method); } } diff --git a/library/Zend/Di/Di.php b/library/Zend/Di/Di.php index 6141df08c..bee8ceeba 100644 --- a/library/Zend/Di/Di.php +++ b/library/Zend/Di/Di.php @@ -869,7 +869,7 @@ class Di implements DependencyInjectionInterface // plus it cannot be resolve, and no value exist, bail out throw new Exception\MissingPropertyException(sprintf( 'Missing %s for parameter ' . $name . ' for ' . $class . '::' . $method, - (($value[0] === null) ? 'value' : 'instance/object' ) + (($value[0] === null) ? 'value' : 'instance/object') )); } else { return false; diff --git a/library/Zend/Di/Display/Console.php b/library/Zend/Di/Display/Console.php index 9c375389c..a0e2fcd03 100644 --- a/library/Zend/Di/Display/Console.php +++ b/library/Zend/Di/Display/Console.php @@ -164,8 +164,8 @@ class Console foreach ($definition->getMethods($class) as $methodName => $methodIsRequired) { foreach ($definition->getMethodParameters($class, $methodName) as $fqName => $pData) { echo ' ' . $pData[0] . ' [type: '; - echo ($pData[1]) ? $pData[1] : 'scalar'; - echo ($pData[2] === true && $methodIsRequired) ? ', required' : ', not required'; + echo($pData[1]) ? $pData[1] : 'scalar'; + echo($pData[2] === true && $methodIsRequired) ? ', required' : ', not required'; echo ', injection-method: ' . $methodName; echo ' fq-name: ' . $fqName; echo ']' . PHP_EOL; diff --git a/library/Zend/Di/ServiceLocator.php b/library/Zend/Di/ServiceLocator.php index 60c509cc3..5c011a8fd 100644 --- a/library/Zend/Di/ServiceLocator.php +++ b/library/Zend/Di/ServiceLocator.php @@ -74,7 +74,7 @@ class ServiceLocator implements ServiceLocatorInterface { if (!isset($this->services[$name])) { if (!isset($this->map[$name])) { - return null; + return; } $method = $this->map[$name]; diff --git a/library/Zend/Di/composer.json b/library/Zend/Di/composer.json index 81f6cb781..a6272b437 100644 --- a/library/Zend/Di/composer.json +++ b/library/Zend/Di/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Di\\": "" } }, - "target-dir": "Zend/Di", "require": { "php": ">=5.3.23", "zendframework/zend-code": "self.version", diff --git a/library/Zend/Dom/composer.json b/library/Zend/Dom/composer.json index 94433c52a..acf8896f9 100644 --- a/library/Zend/Dom/composer.json +++ b/library/Zend/Dom/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Dom\\": "" } }, - "target-dir": "Zend/Dom", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Escaper/Escaper.php b/library/Zend/Escaper/Escaper.php index ac6fbb8fa..072d543f7 100644 --- a/library/Zend/Escaper/Escaper.php +++ b/library/Zend/Escaper/Escaper.php @@ -9,7 +9,6 @@ namespace Zend\Escaper; - /** * Context specific methods for use in secure output escaping */ @@ -321,9 +320,9 @@ class Escaper } if (!$this->isUtf8($result)) { - throw new Exception\RuntimeException(sprintf( - 'String to be escaped was not valid UTF-8 or could not be converted: %s', $result - )); + throw new Exception\RuntimeException( + sprintf('String to be escaped was not valid UTF-8 or could not be converted: %s', $result) + ); } return $result; diff --git a/library/Zend/Escaper/composer.json b/library/Zend/Escaper/composer.json index 5f81793f3..958f14a82 100644 --- a/library/Zend/Escaper/composer.json +++ b/library/Zend/Escaper/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Escaper\\": "" } }, - "target-dir": "Zend/Escaper", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/EventManager/EventManager.php b/library/Zend/EventManager/EventManager.php index 261957c10..aab67eefb 100644 --- a/library/Zend/EventManager/EventManager.php +++ b/library/Zend/EventManager/EventManager.php @@ -167,12 +167,10 @@ class EventManager implements EventManagerInterface /** * Trigger all listeners for a given event * - * Can emulate triggerUntil() if the last argument provided is a callback. - * - * @param string $event - * @param string|object $target Object calling emit, or symbol describing target (such as static method name) - * @param array|ArrayAccess $argv Array of arguments; typically, should be associative - * @param null|callable $callback + * @param string|EventInterface $event + * @param string|object $target Object calling emit, or symbol describing target (such as static method name) + * @param array|ArrayAccess $argv Array of arguments; typically, should be associative + * @param null|callable $callback Trigger listeners until return value of this callback evaluate to true * @return ResponseCollection All listener return values * @throws Exception\InvalidCallbackException */ @@ -214,42 +212,21 @@ class EventManager implements EventManagerInterface * Triggers listeners until the provided callback evaluates the return * value of one as true, or until all listeners have been executed. * - * @param string $event + * @param string|EventInterface $event * @param string|object $target Object calling emit, or symbol describing target (such as static method name) * @param array|ArrayAccess $argv Array of arguments; typically, should be associative * @param callable $callback * @return ResponseCollection + * @deprecated Please use trigger() * @throws Exception\InvalidCallbackException if invalid callable provided */ public function triggerUntil($event, $target, $argv = null, $callback = null) { - if ($event instanceof EventInterface) { - $e = $event; - $event = $e->getName(); - $callback = $target; - } elseif ($target instanceof EventInterface) { - $e = $target; - $e->setName($event); - $callback = $argv; - } elseif ($argv instanceof EventInterface) { - $e = $argv; - $e->setName($event); - $e->setTarget($target); - } else { - $e = new $this->eventClass(); - $e->setName($event); - $e->setTarget($target); - $e->setParams($argv); - } - - if (!is_callable($callback)) { - throw new Exception\InvalidCallbackException('Invalid callback provided'); - } - - // Initial value of stop propagation flag should be false - $e->stopPropagation(false); - - return $this->triggerListeners($event, $e, $callback); + trigger_error( + 'This method is deprecated and will be removed in the future. Please use trigger() instead.', + E_USER_DEPRECATED + ); + return $this->trigger($event, $target, $argv, $callback); } /** @@ -416,7 +393,7 @@ class EventManager implements EventManagerInterface * * Use this method if you want to be able to modify arguments from within a * listener. It returns an ArrayObject of the arguments, which may then be - * passed to trigger() or triggerUntil(). + * passed to trigger(). * * @param array $args * @return ArrayObject @@ -429,8 +406,7 @@ class EventManager implements EventManagerInterface /** * Trigger listeners * - * Actual functionality for triggering listeners, to which both trigger() and triggerUntil() - * delegate. + * Actual functionality for triggering listeners, to which trigger() delegate. * * @param string $event Event name * @param EventInterface $e diff --git a/library/Zend/EventManager/EventManagerInterface.php b/library/Zend/EventManager/EventManagerInterface.php index 7e619707b..c33bfb69d 100644 --- a/library/Zend/EventManager/EventManagerInterface.php +++ b/library/Zend/EventManager/EventManagerInterface.php @@ -25,10 +25,9 @@ interface EventManagerInterface extends SharedEventManagerAwareInterface * - Passing event name and Event object only * - Passing event name, target, and Event object * - Passing event name, target, and array|ArrayAccess of arguments + * - Passing event name, target, array|ArrayAccess of arguments, and callback * - * Can emulate triggerUntil() if the last argument provided is a callback. - * - * @param string $event + * @param string|EventInterface $event * @param object|string $target * @param array|object $argv * @param null|callable $callback @@ -45,11 +44,12 @@ interface EventManagerInterface extends SharedEventManagerAwareInterface * - Passing event name, target, Event object, and callback * - Passing event name, target, array|ArrayAccess of arguments, and callback * - * @param string $event + * @param string|EventInterface $event * @param object|string $target * @param array|object $argv * @param callable $callback * @return ResponseCollection + * @deprecated Please use trigger() */ public function triggerUntil($event, $target, $argv = null, $callback = null); diff --git a/library/Zend/EventManager/FilterChain.php b/library/Zend/EventManager/FilterChain.php index 9618600f7..f657a35d3 100644 --- a/library/Zend/EventManager/FilterChain.php +++ b/library/Zend/EventManager/FilterChain.php @@ -115,6 +115,6 @@ class FilterChain implements Filter\FilterInterface */ public function getResponses() { - return null; + return; } } diff --git a/library/Zend/EventManager/GlobalEventManager.php b/library/Zend/EventManager/GlobalEventManager.php index 5615cb420..336b69cdb 100644 --- a/library/Zend/EventManager/GlobalEventManager.php +++ b/library/Zend/EventManager/GlobalEventManager.php @@ -52,14 +52,15 @@ class GlobalEventManager /** * Trigger an event * - * @param string $event + * @param string $event * @param object|string $context - * @param array|object $argv + * @param array|object $argv + * @param null|callable $callback * @return ResponseCollection */ - public static function trigger($event, $context, $argv = array()) + public static function trigger($event, $context, $argv = array(), $callback = null) { - return static::getEventCollection()->trigger($event, $context, $argv); + return static::getEventCollection()->trigger($event, $context, $argv, $callback); } /** @@ -71,10 +72,15 @@ class GlobalEventManager * @param array|object $argv * @param callable $callback * @return ResponseCollection + * @deprecated Please use trigger() */ public static function triggerUntil($event, $context, $argv, $callback) { - return static::getEventCollection()->triggerUntil($event, $context, $argv, $callback); + trigger_error( + 'This method is deprecated and will be removed in the future. Please use trigger() instead.', + E_USER_DEPRECATED + ); + return static::trigger($event, $context, $argv, $callback); } /** diff --git a/library/Zend/EventManager/ResponseCollection.php b/library/Zend/EventManager/ResponseCollection.php index f0b60e03b..62e584ed3 100644 --- a/library/Zend/EventManager/ResponseCollection.php +++ b/library/Zend/EventManager/ResponseCollection.php @@ -61,7 +61,7 @@ class ResponseCollection extends SplStack public function last() { if (count($this) === 0) { - return null; + return; } return parent::top(); } diff --git a/library/Zend/EventManager/StaticEventManager.php b/library/Zend/EventManager/StaticEventManager.php index e3b089e12..3b571362d 100644 --- a/library/Zend/EventManager/StaticEventManager.php +++ b/library/Zend/EventManager/StaticEventManager.php @@ -15,7 +15,7 @@ namespace Zend\EventManager; class StaticEventManager extends SharedEventManager { /** - * @var StaticEventManager + * @var SharedEventManagerInterface */ protected static $instance; diff --git a/library/Zend/EventManager/composer.json b/library/Zend/EventManager/composer.json index cdb67a0e0..ce922411e 100644 --- a/library/Zend/EventManager/composer.json +++ b/library/Zend/EventManager/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\EventManager\\": "" } }, - "target-dir": "Zend/EventManager", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Feed/Reader/AbstractEntry.php b/library/Zend/Feed/Reader/AbstractEntry.php index 73363553f..a5bcd4287 100644 --- a/library/Zend/Feed/Reader/AbstractEntry.php +++ b/library/Zend/Feed/Reader/AbstractEntry.php @@ -180,7 +180,7 @@ abstract class AbstractEntry if (array_key_exists($name . '\Entry', $this->extensions)) { return $this->extensions[$name . '\Entry']; } - return null; + return; } /** diff --git a/library/Zend/Feed/Reader/AbstractFeed.php b/library/Zend/Feed/Reader/AbstractFeed.php index 7a3a9729f..1ded74418 100644 --- a/library/Zend/Feed/Reader/AbstractFeed.php +++ b/library/Zend/Feed/Reader/AbstractFeed.php @@ -266,7 +266,7 @@ abstract class AbstractFeed implements Feed\FeedInterface if (array_key_exists($name . '\Feed', $this->extensions)) { return $this->extensions[$name . '\Feed']; } - return null; + return; } protected function loadExtensions() diff --git a/library/Zend/Feed/Reader/Entry/AbstractEntry.php b/library/Zend/Feed/Reader/Entry/AbstractEntry.php index c6e73259c..7b006875b 100644 --- a/library/Zend/Feed/Reader/Entry/AbstractEntry.php +++ b/library/Zend/Feed/Reader/Entry/AbstractEntry.php @@ -122,8 +122,9 @@ abstract class AbstractEntry */ public function saveXml() { - $dom = new DOMDocument('1.0', $this->getEncoding()); - $entry = $dom->importNode($this->getElement(), true); + $dom = new DOMDocument('1.0', $this->getEncoding()); + $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true; + $entry = $dom->importNode($this->getElement(), $deep); $dom->appendChild($entry); return $dom->saveXml(); } @@ -184,7 +185,7 @@ abstract class AbstractEntry if (array_key_exists($name . '\\Entry', $this->extensions)) { return $this->extensions[$name . '\\Entry']; } - return null; + return; } /** @@ -202,8 +203,10 @@ abstract class AbstractEntry return call_user_func_array(array($extension, $method), $args); } } - throw new Exception\RuntimeException('Method: ' . $method - . ' does not exist and could not be located on a registered Extension'); + throw new Exception\RuntimeException(sprintf( + 'Method: %s does not exist and could not be located on a registered Extension', + $method + )); } /** diff --git a/library/Zend/Feed/Reader/Entry/Atom.php b/library/Zend/Feed/Reader/Entry/Atom.php index 77e54b90b..543f45661 100644 --- a/library/Zend/Feed/Reader/Entry/Atom.php +++ b/library/Zend/Feed/Reader/Entry/Atom.php @@ -62,7 +62,7 @@ class Atom extends AbstractEntry implements EntryInterface return $authors[$index]; } - return null; + return; } /** @@ -207,7 +207,7 @@ class Atom extends AbstractEntry implements EntryInterface return $this->data['links'][$index]; } - return null; + return; } /** diff --git a/library/Zend/Feed/Reader/Entry/Rss.php b/library/Zend/Feed/Reader/Entry/Rss.php index 666c0c2f4..409190450 100644 --- a/library/Zend/Feed/Reader/Entry/Rss.php +++ b/library/Zend/Feed/Reader/Entry/Rss.php @@ -76,7 +76,7 @@ class Rss extends AbstractEntry implements EntryInterface return $authors[$index]; } - return null; + return; } /** @@ -109,8 +109,6 @@ class Rss extends AbstractEntry implements EntryInterface if ($list->length) { foreach ($list as $author) { $string = trim($author->nodeValue); - $email = null; - $name = null; $data = array(); // Pretty rough parsing - but it's a catchall if (preg_match("/^.*@[^ ]*/", $string, $matches)) { @@ -188,7 +186,6 @@ class Rss extends AbstractEntry implements EntryInterface return $this->data['datemodified']; } - $dateModified = null; $date = null; if ($this->getType() !== Reader\Reader::TYPE_RSS_10 @@ -366,7 +363,7 @@ class Rss extends AbstractEntry implements EntryInterface return $this->data['links'][$index]; } - return null; + return; } /** diff --git a/library/Zend/Feed/Reader/Extension/Atom/Entry.php b/library/Zend/Feed/Reader/Extension/Atom/Entry.php index 12fb3c636..06e94a275 100644 --- a/library/Zend/Feed/Reader/Extension/Atom/Entry.php +++ b/library/Zend/Feed/Reader/Extension/Atom/Entry.php @@ -34,7 +34,7 @@ class Entry extends Extension\AbstractEntry return $authors[$index]; } - return null; + return; } /** @@ -103,20 +103,21 @@ class Entry extends Extension\AbstractEntry case 'html': case 'text/html': $content = $el->nodeValue; - break; + break; case 'xhtml': $this->getXpath()->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml'); $xhtml = $this->getXpath()->query( $this->getXpathPrefix() . '/atom:content/xhtml:div' )->item(0); $d = new DOMDocument('1.0', $this->getEncoding()); - $xhtmls = $d->importNode($xhtml, true); + $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true; + $xhtmls = $d->importNode($xhtml, $deep); $d->appendChild($xhtmls); $content = $this->collectXhtml( $d->saveXML(), $d->lookupPrefix('http://www.w3.org/1999/xhtml') ); - break; + break; } } @@ -296,9 +297,12 @@ class Entry extends Extension\AbstractEntry return $this->data['baseUrl']; } - $baseUrl = $this->getXpath()->evaluate('string(' - . $this->getXpathPrefix() . '/@xml:base[1]' - . ')'); + $baseUrl = $this->getXpath()->evaluate( + 'string(' + . $this->getXpathPrefix() + . '/@xml:base[1]' + . ')' + ); if (!$baseUrl) { $baseUrl = $this->getXpath()->evaluate('string(//@xml:base[1])'); @@ -329,7 +333,7 @@ class Entry extends Extension\AbstractEntry return $this->data['links'][$index]; } - return null; + return; } /** @@ -588,7 +592,7 @@ class Entry extends Extension\AbstractEntry } if (empty($author)) { - return null; + return; } return $author; } diff --git a/library/Zend/Feed/Reader/Extension/Atom/Feed.php b/library/Zend/Feed/Reader/Extension/Atom/Feed.php index 14bf9c338..19dbf5a56 100644 --- a/library/Zend/Feed/Reader/Extension/Atom/Feed.php +++ b/library/Zend/Feed/Reader/Extension/Atom/Feed.php @@ -32,7 +32,7 @@ class Feed extends Extension\AbstractFeed return $authors[$index]; } - return null; + return; } /** @@ -471,7 +471,7 @@ class Feed extends Extension\AbstractFeed } if (empty($author)) { - return null; + return; } return $author; } diff --git a/library/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php b/library/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php index 9ecb486b1..9194682f8 100644 --- a/library/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php +++ b/library/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php @@ -27,7 +27,7 @@ class Entry extends Extension\AbstractEntry return $licenses[$index]; } - return null; + return; } /** diff --git a/library/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php b/library/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php index 5aabe8b99..c833bbda9 100644 --- a/library/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php +++ b/library/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php @@ -27,7 +27,7 @@ class Feed extends Extension\AbstractFeed return $licenses[$index]; } - return null; + return; } /** diff --git a/library/Zend/Feed/Reader/Extension/DublinCore/Entry.php b/library/Zend/Feed/Reader/Extension/DublinCore/Entry.php index 1e656cd06..e23de8101 100644 --- a/library/Zend/Feed/Reader/Extension/DublinCore/Entry.php +++ b/library/Zend/Feed/Reader/Extension/DublinCore/Entry.php @@ -30,7 +30,7 @@ class Entry extends Extension\AbstractEntry return $authors[$index]; } - return null; + return; } /** @@ -131,7 +131,6 @@ class Entry extends Extension\AbstractEntry return $this->data['description']; } - $description = null; $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:description)'); if (!$description) { @@ -158,7 +157,6 @@ class Entry extends Extension\AbstractEntry return $this->data['id']; } - $id = null; $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:identifier)'); if (!$id) { @@ -181,7 +179,6 @@ class Entry extends Extension\AbstractEntry return $this->data['title']; } - $title = null; $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:title)'); if (!$title) { diff --git a/library/Zend/Feed/Reader/Extension/DublinCore/Feed.php b/library/Zend/Feed/Reader/Extension/DublinCore/Feed.php index 182ce218a..6b54b081f 100644 --- a/library/Zend/Feed/Reader/Extension/DublinCore/Feed.php +++ b/library/Zend/Feed/Reader/Extension/DublinCore/Feed.php @@ -30,7 +30,7 @@ class Feed extends Extension\AbstractFeed return $authors[$index]; } - return null; + return; } /** @@ -87,7 +87,6 @@ class Feed extends Extension\AbstractFeed return $this->data['copyright']; } - $copyright = null; $copyright = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:rights)'); if (!$copyright) { @@ -114,7 +113,6 @@ class Feed extends Extension\AbstractFeed return $this->data['description']; } - $description = null; $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:description)'); if (!$description) { @@ -141,7 +139,6 @@ class Feed extends Extension\AbstractFeed return $this->data['id']; } - $id = null; $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:identifier)'); if (!$id) { @@ -164,7 +161,6 @@ class Feed extends Extension\AbstractFeed return $this->data['language']; } - $language = null; $language = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:language)'); if (!$language) { @@ -191,7 +187,6 @@ class Feed extends Extension\AbstractFeed return $this->data['title']; } - $title = null; $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/dc11:title)'); if (!$title) { diff --git a/library/Zend/Feed/Reader/Feed/AbstractFeed.php b/library/Zend/Feed/Reader/Feed/AbstractFeed.php index ea9cd978e..9814967a6 100644 --- a/library/Zend/Feed/Reader/Feed/AbstractFeed.php +++ b/library/Zend/Feed/Reader/Feed/AbstractFeed.php @@ -270,7 +270,7 @@ abstract class AbstractFeed implements FeedInterface if (array_key_exists($name . '\\Feed', $this->extensions)) { return $this->extensions[$name . '\\Feed']; } - return null; + return; } protected function loadExtensions() diff --git a/library/Zend/Feed/Reader/Feed/Atom.php b/library/Zend/Feed/Reader/Feed/Atom.php index 50a0fb03c..37064701c 100644 --- a/library/Zend/Feed/Reader/Feed/Atom.php +++ b/library/Zend/Feed/Reader/Feed/Atom.php @@ -58,7 +58,7 @@ class Atom extends AbstractFeed return $authors[$index]; } - return null; + return; } /** @@ -152,7 +152,7 @@ class Atom extends AbstractFeed */ public function getLastBuildDate() { - return null; + return; } /** diff --git a/library/Zend/Feed/Reader/Feed/Rss.php b/library/Zend/Feed/Reader/Feed/Rss.php index 16559971e..cb9f038bc 100644 --- a/library/Zend/Feed/Reader/Feed/Rss.php +++ b/library/Zend/Feed/Reader/Feed/Rss.php @@ -69,7 +69,7 @@ class Rss extends AbstractFeed return $authors[$index]; } - return null; + return; } /** @@ -106,8 +106,6 @@ class Rss extends AbstractFeed if ($list->length) { foreach ($list as $author) { $string = trim($author->nodeValue); - $email = null; - $name = null; $data = array(); // Pretty rough parsing - but it's a catchall if (preg_match("/^.*@[^ ]*/", $string, $matches)) { @@ -194,7 +192,6 @@ class Rss extends AbstractFeed return $this->data['datemodified']; } - $dateModified = null; $date = null; if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && @@ -258,7 +255,6 @@ class Rss extends AbstractFeed return $this->data['lastBuildDate']; } - $lastBuildDate = null; $date = null; if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && @@ -310,8 +306,6 @@ class Rss extends AbstractFeed return $this->data['description']; } - $description = null; - if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && $this->getType() !== Reader\Reader::TYPE_RSS_090) { $description = $this->xpath->evaluate('string(/rss/channel/description)'); @@ -481,8 +475,6 @@ class Rss extends AbstractFeed return $this->data['link']; } - $link = null; - if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && $this->getType() !== Reader\Reader::TYPE_RSS_090) { $link = $this->xpath->evaluate('string(/rss/channel/link)'); @@ -514,8 +506,6 @@ class Rss extends AbstractFeed return $this->data['feedlink']; } - $link = null; - $link = $this->getExtension('Atom')->getFeedLink(); if ($link === null || empty($link)) { @@ -578,8 +568,6 @@ class Rss extends AbstractFeed return $this->data['title']; } - $title = null; - if ($this->getType() !== Reader\Reader::TYPE_RSS_10 && $this->getType() !== Reader\Reader::TYPE_RSS_090) { $title = $this->xpath->evaluate('string(/rss/channel/title)'); diff --git a/library/Zend/Feed/Reader/FeedSet.php b/library/Zend/Feed/Reader/FeedSet.php index 798229e99..8fab2cbae 100644 --- a/library/Zend/Feed/Reader/FeedSet.php +++ b/library/Zend/Feed/Reader/FeedSet.php @@ -115,7 +115,7 @@ class FeedSet extends ArrayObject { if ($offset == 'feed' && !$this->offsetExists('feed')) { if (!$this->offsetExists('href')) { - return null; + return; } $feed = Reader::import($this->offsetGet('href')); $this->offsetSet('feed', $feed); diff --git a/library/Zend/Feed/Reader/Reader.php b/library/Zend/Feed/Reader/Reader.php index f6708df65..c5eb3d454 100644 --- a/library/Zend/Feed/Reader/Reader.php +++ b/library/Zend/Feed/Reader/Reader.php @@ -17,7 +17,7 @@ use Zend\Stdlib\ErrorHandler; /** */ -class Reader +class Reader implements ReaderImportInterface { /** * Namespace constants @@ -190,7 +190,6 @@ class Reader public static function import($uri, $etag = null, $lastModified = null) { $cache = self::getCache(); - $feed = null; $client = self::getHttpClient(); $client->resetParameters(); $headers = new ZendHttp\Headers(); @@ -545,7 +544,7 @@ class Reader public static function getExtensionManager() { if (!isset(static::$extensionManager)) { - static::setExtensionManager(new ExtensionManager()); + static::setExtensionManager(new StandaloneExtensionManager()); } return static::$extensionManager; } diff --git a/library/Zend/Feed/Reader/ReaderImportInterface.php b/library/Zend/Feed/Reader/ReaderImportInterface.php new file mode 100644 index 000000000..0a2edd14c --- /dev/null +++ b/library/Zend/Feed/Reader/ReaderImportInterface.php @@ -0,0 +1,62 @@ + 'Zend\Feed\Reader\Extension\Atom\Entry', + 'Atom\Feed' => 'Zend\Feed\Reader\Extension\Atom\Feed', + 'Content\Entry' => 'Zend\Feed\Reader\Extension\Content\Entry', + 'CreativeCommons\Entry' => 'Zend\Feed\Reader\Extension\CreativeCommons\Entry', + 'CreativeCommons\Feed' => 'Zend\Feed\Reader\Extension\CreativeCommons\Feed', + 'DublinCore\Entry' => 'Zend\Feed\Reader\Extension\DublinCore\Entry', + 'DublinCore\Feed' => 'Zend\Feed\Reader\Extension\DublinCore\Feed', + 'Podcast\Entry' => 'Zend\Feed\Reader\Extension\Podcast\Entry', + 'Podcast\Feed' => 'Zend\Feed\Reader\Extension\Podcast\Feed', + 'Slash\Entry' => 'Zend\Feed\Reader\Extension\Slash\Entry', + 'Syndication\Feed' => 'Zend\Feed\Reader\Extension\Syndication\Feed', + 'Thread\Entry' => 'Zend\Feed\Reader\Extension\Thread\Entry', + 'WellFormedWeb\Entry' => 'Zend\Feed\Reader\Extension\WellFormedWeb\Entry', + ); + + /** + * Do we have the extension? + * + * @param string $extension + * @return bool + */ + public function has($extension) + { + return array_key_exists($extension, $this->extensions); + } + + /** + * Retrieve the extension + * + * @param string $extension + * @return Extension\AbstractEntry|Extension\AbstractFeed + */ + public function get($extension) + { + $class = $this->extensions[$extension]; + return new $class(); + } +} diff --git a/library/Zend/Feed/Writer/AbstractFeed.php b/library/Zend/Feed/Writer/AbstractFeed.php index 097a0a722..26616b06d 100644 --- a/library/Zend/Feed/Writer/AbstractFeed.php +++ b/library/Zend/Feed/Writer/AbstractFeed.php @@ -531,7 +531,7 @@ class AbstractFeed return $this->data['authors'][$index]; } - return null; + return; } /** @@ -542,7 +542,7 @@ class AbstractFeed public function getAuthors() { if (!array_key_exists('authors', $this->data)) { - return null; + return; } return $this->data['authors']; } @@ -555,7 +555,7 @@ class AbstractFeed public function getCopyright() { if (!array_key_exists('copyright', $this->data)) { - return null; + return; } return $this->data['copyright']; } @@ -568,7 +568,7 @@ class AbstractFeed public function getDateCreated() { if (!array_key_exists('dateCreated', $this->data)) { - return null; + return; } return $this->data['dateCreated']; } @@ -581,7 +581,7 @@ class AbstractFeed public function getDateModified() { if (!array_key_exists('dateModified', $this->data)) { - return null; + return; } return $this->data['dateModified']; } @@ -594,7 +594,7 @@ class AbstractFeed public function getLastBuildDate() { if (!array_key_exists('lastBuildDate', $this->data)) { - return null; + return; } return $this->data['lastBuildDate']; } @@ -607,7 +607,7 @@ class AbstractFeed public function getDescription() { if (!array_key_exists('description', $this->data)) { - return null; + return; } return $this->data['description']; } @@ -620,7 +620,7 @@ class AbstractFeed public function getGenerator() { if (!array_key_exists('generator', $this->data)) { - return null; + return; } return $this->data['generator']; } @@ -633,7 +633,7 @@ class AbstractFeed public function getId() { if (!array_key_exists('id', $this->data)) { - return null; + return; } return $this->data['id']; } @@ -646,7 +646,7 @@ class AbstractFeed public function getImage() { if (!array_key_exists('image', $this->data)) { - return null; + return; } return $this->data['image']; } @@ -659,7 +659,7 @@ class AbstractFeed public function getLanguage() { if (!array_key_exists('language', $this->data)) { - return null; + return; } return $this->data['language']; } @@ -672,7 +672,7 @@ class AbstractFeed public function getLink() { if (!array_key_exists('link', $this->data)) { - return null; + return; } return $this->data['link']; } @@ -685,7 +685,7 @@ class AbstractFeed public function getFeedLinks() { if (!array_key_exists('feedLinks', $this->data)) { - return null; + return; } return $this->data['feedLinks']; } @@ -698,7 +698,7 @@ class AbstractFeed public function getTitle() { if (!array_key_exists('title', $this->data)) { - return null; + return; } return $this->data['title']; } @@ -724,7 +724,7 @@ class AbstractFeed public function getBaseUrl() { if (!array_key_exists('baseUrl', $this->data)) { - return null; + return; } return $this->data['baseUrl']; } @@ -737,7 +737,7 @@ class AbstractFeed public function getHubs() { if (!array_key_exists('hubs', $this->data)) { - return null; + return; } return $this->data['hubs']; } @@ -750,7 +750,7 @@ class AbstractFeed public function getCategories() { if (!array_key_exists('categories', $this->data)) { - return null; + return; } return $this->data['categories']; } diff --git a/library/Zend/Feed/Writer/Deleted.php b/library/Zend/Feed/Writer/Deleted.php index 0b469f3dd..1d72fc920 100644 --- a/library/Zend/Feed/Writer/Deleted.php +++ b/library/Zend/Feed/Writer/Deleted.php @@ -124,7 +124,7 @@ class Deleted public function getReference() { if (!array_key_exists('reference', $this->data)) { - return null; + return; } return $this->data['reference']; } @@ -157,7 +157,7 @@ class Deleted public function getWhen() { if (!array_key_exists('when', $this->data)) { - return null; + return; } return $this->data['when']; } @@ -208,7 +208,7 @@ class Deleted public function getBy() { if (!array_key_exists('by', $this->data)) { - return null; + return; } return $this->data['by']; } @@ -229,7 +229,7 @@ class Deleted public function getComment() { if (!array_key_exists('comment', $this->data)) { - return null; + return; } return $this->data['comment']; } diff --git a/library/Zend/Feed/Writer/Entry.php b/library/Zend/Feed/Writer/Entry.php index a17c3aa38..78b968dcb 100644 --- a/library/Zend/Feed/Writer/Entry.php +++ b/library/Zend/Feed/Writer/Entry.php @@ -365,7 +365,7 @@ class Entry public function getAuthors() { if (!array_key_exists('authors', $this->data)) { - return null; + return; } return $this->data['authors']; } @@ -378,7 +378,7 @@ class Entry public function getContent() { if (!array_key_exists('content', $this->data)) { - return null; + return; } return $this->data['content']; } @@ -391,7 +391,7 @@ class Entry public function getCopyright() { if (!array_key_exists('copyright', $this->data)) { - return null; + return; } return $this->data['copyright']; } @@ -404,7 +404,7 @@ class Entry public function getDateCreated() { if (!array_key_exists('dateCreated', $this->data)) { - return null; + return; } return $this->data['dateCreated']; } @@ -417,7 +417,7 @@ class Entry public function getDateModified() { if (!array_key_exists('dateModified', $this->data)) { - return null; + return; } return $this->data['dateModified']; } @@ -430,7 +430,7 @@ class Entry public function getDescription() { if (!array_key_exists('description', $this->data)) { - return null; + return; } return $this->data['description']; } @@ -443,7 +443,7 @@ class Entry public function getId() { if (!array_key_exists('id', $this->data)) { - return null; + return; } return $this->data['id']; } @@ -456,7 +456,7 @@ class Entry public function getLink() { if (!array_key_exists('link', $this->data)) { - return null; + return; } return $this->data['link']; } @@ -470,7 +470,7 @@ class Entry public function getLinks() { if (!array_key_exists('links', $this->data)) { - return null; + return; } return $this->data['links']; } @@ -483,7 +483,7 @@ class Entry public function getTitle() { if (!array_key_exists('title', $this->data)) { - return null; + return; } return $this->data['title']; } @@ -496,7 +496,7 @@ class Entry public function getCommentCount() { if (!array_key_exists('commentCount', $this->data)) { - return null; + return; } return $this->data['commentCount']; } @@ -509,7 +509,7 @@ class Entry public function getCommentLink() { if (!array_key_exists('commentLink', $this->data)) { - return null; + return; } return $this->data['commentLink']; } @@ -523,7 +523,7 @@ class Entry public function getCommentFeedLinks() { if (!array_key_exists('commentFeedLinks', $this->data)) { - return null; + return; } return $this->data['commentFeedLinks']; } @@ -582,7 +582,7 @@ class Entry public function getCategories() { if (!array_key_exists('categories', $this->data)) { - return null; + return; } return $this->data['categories']; } @@ -618,7 +618,7 @@ class Entry public function getEnclosure() { if (!array_key_exists('enclosure', $this->data)) { - return null; + return; } return $this->data['enclosure']; } @@ -659,7 +659,7 @@ class Entry if (array_key_exists($name . '\\Entry', $this->extensions)) { return $this->extensions[$name . '\\Entry']; } - return null; + return; } /** @@ -744,7 +744,7 @@ class Entry if (isset($this->data['source'])) { return $this->data['source']; } - return null; + return; } /** diff --git a/library/Zend/Feed/Writer/Extension/ITunes/Entry.php b/library/Zend/Feed/Writer/Extension/ITunes/Entry.php index 8032ce2f9..c06e8a970 100644 --- a/library/Zend/Feed/Writer/Extension/ITunes/Entry.php +++ b/library/Zend/Feed/Writer/Extension/ITunes/Entry.php @@ -239,7 +239,7 @@ class Entry if (!array_key_exists($point, $this->data) || empty($this->data[$point]) ) { - return null; + return; } return $this->data[$point]; } diff --git a/library/Zend/Feed/Writer/Extension/ITunes/Feed.php b/library/Zend/Feed/Writer/Extension/ITunes/Feed.php index 5568d5de3..08a6b13fe 100644 --- a/library/Zend/Feed/Writer/Extension/ITunes/Feed.php +++ b/library/Zend/Feed/Writer/Extension/ITunes/Feed.php @@ -355,7 +355,7 @@ class Feed ); } if (!array_key_exists($point, $this->data) || empty($this->data[$point])) { - return null; + return; } return $this->data[$point]; } diff --git a/library/Zend/Feed/Writer/Renderer/Entry/Atom.php b/library/Zend/Feed/Writer/Renderer/Entry/Atom.php index 9f3aa7401..31b0a9aca 100644 --- a/library/Zend/Feed/Writer/Renderer/Entry/Atom.php +++ b/library/Zend/Feed/Writer/Renderer/Entry/Atom.php @@ -265,12 +265,14 @@ class Atom extends Renderer\AbstractRenderer implements Renderer\RendererInterfa if (!$this->getDataContainer()->getId()) { $this->getDataContainer()->setId( - $this->getDataContainer()->getLink()); + $this->getDataContainer()->getLink() + ); } if (!Uri::factory($this->getDataContainer()->getId())->isValid() && !preg_match( "#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#", - $this->getDataContainer()->getId()) + $this->getDataContainer()->getId() + ) && !$this->_validateTagUri($this->getDataContainer()->getId()) ) { throw new Writer\Exception\InvalidArgumentException('Atom 1.0 IDs must be a valid URI/IRI'); @@ -289,7 +291,11 @@ class Atom extends Renderer\AbstractRenderer implements Renderer\RendererInterfa */ protected function _validateTagUri($id) { - if (preg_match('/^tag:(?P.*),(?P\d{4}-?\d{0,2}-?\d{0,2}):(?P.*)(.*:)*$/', $id, $matches)) { + if (preg_match( + '/^tag:(?P.*),(?P\d{4}-?\d{0,2}-?\d{0,2}):(?P.*)(.*:)*$/', + $id, + $matches + )) { $dvalid = false; $date = $matches['date']; $d6 = strtotime($date); @@ -341,7 +347,8 @@ class Atom extends Renderer\AbstractRenderer implements Renderer\RendererInterfa $element = $dom->createElement('content'); $element->setAttribute('type', 'xhtml'); $xhtmlElement = $this->_loadXhtml($content); - $xhtml = $dom->importNode($xhtmlElement, true); + $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true; + $xhtml = $dom->importNode($xhtmlElement, $deep); $element->appendChild($xhtml); $root->appendChild($element); } @@ -369,8 +376,11 @@ class Atom extends Renderer\AbstractRenderer implements Renderer\RendererInterfa "/(<[\/]?)([a-zA-Z]+)/" ), '$1xhtml:$2', $xhtml); $dom = new DOMDocument('1.0', $this->getEncoding()); - $dom->loadXML('' - . $xhtml . ''); + $dom->loadXML( + '' + . $xhtml + . '' + ); return $dom->documentElement; } diff --git a/library/Zend/Feed/Writer/Renderer/Feed/Atom.php b/library/Zend/Feed/Writer/Renderer/Feed/Atom.php index 2b33f6a1e..939babc0b 100644 --- a/library/Zend/Feed/Writer/Renderer/Feed/Atom.php +++ b/library/Zend/Feed/Writer/Renderer/Feed/Atom.php @@ -40,7 +40,8 @@ class Atom extends AbstractAtom implements Renderer\RendererInterface $this->dom = new DOMDocument('1.0', $this->container->getEncoding()); $this->dom->formatOutput = true; $root = $this->dom->createElementNS( - Writer\Writer::NAMESPACE_ATOM_10, 'feed' + Writer\Writer::NAMESPACE_ATOM_10, + 'feed' ); $this->setRootElement($root); $this->dom->appendChild($root); @@ -76,7 +77,8 @@ class Atom extends AbstractAtom implements Renderer\RendererInterface } else { if (!$this->dom->documentElement->hasAttribute('xmlns:at')) { $this->dom->documentElement->setAttribute( - 'xmlns:at', 'http://purl.org/atompub/tombstones/1.0' + 'xmlns:at', + 'http://purl.org/atompub/tombstones/1.0' ); } $renderer = new Renderer\Entry\AtomDeleted($entry); @@ -88,7 +90,8 @@ class Atom extends AbstractAtom implements Renderer\RendererInterface $renderer->setRootElement($this->dom->documentElement); $renderer->render(); $element = $renderer->getElement(); - $imported = $this->dom->importNode($element, true); + $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true; + $imported = $this->dom->importNode($element, $deep); $root->appendChild($imported); } return $this; diff --git a/library/Zend/Feed/Writer/Renderer/Feed/Rss.php b/library/Zend/Feed/Writer/Renderer/Feed/Rss.php index aff8ae160..be902b8a9 100644 --- a/library/Zend/Feed/Writer/Renderer/Feed/Rss.php +++ b/library/Zend/Feed/Writer/Renderer/Feed/Rss.php @@ -85,7 +85,8 @@ class Rss extends Renderer\AbstractRenderer implements Renderer\RendererInterfac $renderer->setRootElement($this->dom->documentElement); $renderer->render(); $element = $renderer->getElement(); - $imported = $this->dom->importNode($element, true); + $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true; + $imported = $this->dom->importNode($element, $deep); $channel->appendChild($imported); } return $this; @@ -195,8 +196,11 @@ class Rss extends Renderer\AbstractRenderer implements Renderer\RendererInterfac protected function _setGenerator(DOMDocument $dom, DOMElement $root) { if (!$this->getDataContainer()->getGenerator()) { - $this->getDataContainer()->setGenerator('Zend_Feed_Writer', - Version::VERSION, 'http://framework.zend.com'); + $this->getDataContainer()->setGenerator( + 'Zend_Feed_Writer', + Version::VERSION, + 'http://framework.zend.com' + ); } $gdata = $this->getDataContainer()->getGenerator(); diff --git a/library/Zend/Feed/composer.json b/library/Zend/Feed/composer.json index 0c4d7dc18..5541ae5d5 100644 --- a/library/Zend/Feed/composer.json +++ b/library/Zend/Feed/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Feed\\": "" } }, - "target-dir": "Zend/Feed", "require": { "php": ">=5.3.23", "zendframework/zend-escaper": "self.version", diff --git a/library/Zend/File/Transfer/Adapter/AbstractAdapter.php b/library/Zend/File/Transfer/Adapter/AbstractAdapter.php index 90959b05f..7606f3e2a 100644 --- a/library/Zend/File/Transfer/Adapter/AbstractAdapter.php +++ b/library/Zend/File/Transfer/Adapter/AbstractAdapter.php @@ -428,7 +428,7 @@ abstract class AbstractAdapter implements TranslatorAwareInterface public function getValidator($name) { if (false === ($identifier = $this->getValidatorIdentifier($name))) { - return null; + return; } return $this->validators[$identifier]; } @@ -804,7 +804,7 @@ abstract class AbstractAdapter implements TranslatorAwareInterface public function getFilter($name) { if (false === ($identifier = $this->getFilterIdentifier($name))) { - return null; + return; } return $this->filters[$identifier]; @@ -1031,7 +1031,7 @@ abstract class AbstractAdapter implements TranslatorAwareInterface public function getTranslator() { if ($this->isTranslatorEnabled()) { - return null; + return; } return $this->translator; @@ -1169,7 +1169,7 @@ abstract class AbstractAdapter implements TranslatorAwareInterface } elseif (file_exists($value['tmp_name'])) { $filename = $value['tmp_name']; } else { - return null; + return; } ErrorHandler::start(); @@ -1224,7 +1224,7 @@ abstract class AbstractAdapter implements TranslatorAwareInterface } elseif (file_exists($value['tmp_name'])) { $file = $value['tmp_name']; } else { - return null; + return; } if (class_exists('finfo', false)) { diff --git a/library/Zend/File/composer.json b/library/Zend/File/composer.json index d3d86cea9..63ba606f1 100644 --- a/library/Zend/File/composer.json +++ b/library/Zend/File/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\File\\": "" } }, - "target-dir": "Zend/File", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Filter/AbstractDateDropdown.php b/library/Zend/Filter/AbstractDateDropdown.php new file mode 100644 index 000000000..076b81371 --- /dev/null +++ b/library/Zend/Filter/AbstractDateDropdown.php @@ -0,0 +1,155 @@ +setOptions($options); + } + } + + /** + * @param bool $nullOnAllEmpty + * @return self + */ + public function setNullOnAllEmpty($nullOnAllEmpty) + { + $this->nullOnAllEmpty = $nullOnAllEmpty; + return $this; + } + + /** + * @return bool + */ + public function isNullOnAllEmpty() + { + return $this->nullOnAllEmpty; + } + + /** + * @param bool $nullOnEmpty + * @return self + */ + public function setNullOnEmpty($nullOnEmpty) + { + $this->nullOnEmpty = $nullOnEmpty; + return $this; + } + + /** + * @return bool + */ + public function isNullOnEmpty() + { + return $this->nullOnEmpty; + } + + /** + * Attempts to filter an array of date/time information to a formatted + * string. + * + * @param mixed $value + * @return mixed + * @throws Exception\RuntimeException If filtering $value is impossible + */ + public function filter($value) + { + if (! is_array($value)) { + // nothing to do + return $value; + } + + // Convert the date to a specific format + if ($this->isNullOnEmpty() + && array_reduce($value, __CLASS__ . '::reduce', false) + ) { + return; + } + + if ($this->isNullOnAllEmpty() + && array_reduce($value, __CLASS__ . '::reduce', true) + ) { + return; + } + + $this->filterable($value); + + ksort($value); + $value = vsprintf($this->format, $value); + + return $value; + } + + /** + * Ensures there are enough inputs in the array to properly format the date. + * + * @param $value + * @throws Exception\RuntimeException + */ + protected function filterable($value) + { + if (count($value) !== $this->expectedInputs) { + throw new Exception\RuntimeException( + sprintf( + 'There are not enough values in the array to filter this date (Required: %d, Received: %d)', + $this->expectedInputs, + count($value) + ) + ); + } + } + + /** + * Reduce to a single value + * + * @param string $soFar + * @param string $value + * @return bool + */ + public static function reduce($soFar, $value) + { + return $soFar || empty($value); + } +} diff --git a/library/Zend/Filter/Blacklist.php b/library/Zend/Filter/Blacklist.php new file mode 100644 index 000000000..c8e8ed6c9 --- /dev/null +++ b/library/Zend/Filter/Blacklist.php @@ -0,0 +1,90 @@ +setOptions($options); + } + } + + /** + * Determine whether the in_array() call should be "strict" or not. See in_array docs. + * + * @param bool $strict + */ + public function setStrict($strict = true) + { + $this->strict = (bool) $strict; + } + + /** + * Returns whether the in_array() call should be "strict" or not. See in_array docs. + * + * @return boolean + */ + public function getStrict() + { + return $this->strict; + } + + /** + * Set the list of items to black-list. + * + * @param array|Traversable $list + */ + public function setList($list = array()) + { + if (!is_array($list)) { + $list = ArrayUtils::iteratorToArray($list); + } + + $this->list = $list; + } + + /** + * Get the list of items to black-list + * + * @return array + */ + public function getList() + { + return $this->list; + } + + /** + * {@inheritDoc} + * + * Will return null if $value is present in the black-list. If $value is NOT present then it will return $value. + */ + public function filter($value) + { + return in_array($value, $this->getList(), $this->getStrict()) ? null : $value; + } +} diff --git a/library/Zend/Filter/Compress/AbstractCompressionAlgorithm.php b/library/Zend/Filter/Compress/AbstractCompressionAlgorithm.php index 352c2dcbc..4893181e4 100644 --- a/library/Zend/Filter/Compress/AbstractCompressionAlgorithm.php +++ b/library/Zend/Filter/Compress/AbstractCompressionAlgorithm.php @@ -51,7 +51,7 @@ abstract class AbstractCompressionAlgorithm implements CompressionAlgorithmInter } if (!array_key_exists($option, $this->options)) { - return null; + return; } return $this->options[$option]; diff --git a/library/Zend/Filter/DataUnitFormatter.php b/library/Zend/Filter/DataUnitFormatter.php new file mode 100644 index 000000000..b8ca41b8f --- /dev/null +++ b/library/Zend/Filter/DataUnitFormatter.php @@ -0,0 +1,245 @@ + array('', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'), + // decimal SI units: + self::MODE_DECIMAL => array('', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'), + ); + + /** + * Default options: + * + * @var array + */ + protected $options = array( + 'mode' => self::MODE_DECIMAL, + 'unit' => '', + 'precision' => 2, + 'prefixes' => array(), + ); + + /** + * @param array $options + */ + public function __construct($options = array()) + { + if (!static::isOptions($options)) { + throw new InvalidArgumentException('The unit filter needs options to work.'); + } + + if (!isset($options['unit'])) { + throw new InvalidArgumentException('The unit filter needs a unit to work with.'); + } + + $this->setOptions($options); + } + + /** + * Define the mode of the filter. Possible values can be fount at self::$modes. + * + * @param string $mode + * + * @throws InvalidArgumentException + */ + protected function setMode($mode) + { + $mode = strtolower($mode); + if (!in_array($mode, self::$modes)) { + throw new InvalidArgumentException(sprintf('Invalid binary mode: %s', $mode)); + } + $this->options['mode'] = $mode; + } + + /** + * Get current filter mode + * + * @return string + */ + protected function getMode() + { + return $this->options['mode']; + } + + /** + * Find out if the filter is in decimal mode. + * + * @return bool + */ + protected function isDecimalMode() + { + return $this->getMode() == self::MODE_DECIMAL; + } + + /** + * Find out if the filter is in binary mode. + * + * @return bool + */ + protected function isBinaryMode() + { + return $this->getMode() == self::MODE_BINARY; + } + + /** + * Define the unit of the filter. Possible values can be fount at self::$types. + * + * @param string $unit + */ + protected function setUnit($unit) + { + $this->options['unit'] = (string) $unit; + } + + /** + * Get current filter type + * + * @return string + */ + protected function getUnit() + { + return $this->options['unit']; + } + + /** + * Set the precision of the filtered result. + * + * @param $precision + */ + protected function setPrecision($precision) + { + $this->options['precision'] = (int) $precision; + } + + /** + * Get the precision of the filtered result. + * + * @return int + */ + protected function getPrecision() + { + return $this->options['precision']; + } + + /** + * Set the precision of the result. + * + * @param array $prefixes + */ + protected function setPrefixes(array $prefixes) + { + $this->options['prefixes'] = $prefixes; + } + + /** + * Get the predefined prefixes or use the build-in standardized lists of prefixes. + * + * @return array + */ + protected function getPrefixes() + { + $prefixes = $this->options['prefixes']; + if ($prefixes) { + return $prefixes; + } + + return self::$standardizedPrefixes[$this->getMode()]; + } + + /** + * Find the prefix at a specific location in the prefixes array. + * + * @param $index + * + * @return string|null + */ + protected function getPrefixAt($index) + { + $prefixes = $this->getPrefixes(); + return isset($prefixes[$index]) ? $prefixes[$index] : null; + } + + /** + * Defined by Zend\Filter\FilterInterface + * + * Returns a human readable format of the amount of bits or bytes. + * + * If the value provided is not numeric, the value will remain unfiltered + * + * @param string $value + * @return string|mixed + */ + public function filter($value) + { + if (!is_numeric($value)) { + return $value; + } + + // Parse to float and check if value is not zero + $amount = (float) $value; + if ($amount == 0) { + return $this->formatAmount($amount); + } + + // Calculate the correct size and prefix: + $base = $this->isBinaryMode() ? self::BASE_BINARY : self::BASE_DECIMAL; + $power = floor(log($amount, $base)); + $prefix = $this->getPrefixAt((int)$power); + + // When the amount is too big, no prefix can be found: + if (is_null($prefix)) { + return $this->formatAmount($amount); + } + + // return formatted value: + $result = ($amount / pow($base, $power)); + $formatted = number_format($result, $this->getPrecision()); + return $this->formatAmount($formatted, $prefix); + } + + /** + * @param $amount + * @param null $prefix + * + * @return string + */ + protected function formatAmount($amount, $prefix = null) + { + return sprintf('%s %s%s', $amount, $prefix, $this->getUnit()); + } +} diff --git a/library/Zend/Filter/DateSelect.php b/library/Zend/Filter/DateSelect.php new file mode 100644 index 000000000..8d16217f6 --- /dev/null +++ b/library/Zend/Filter/DateSelect.php @@ -0,0 +1,25 @@ +isNullOnEmpty() + && ( + empty($value['year']) + || empty($value['month']) + || empty($value['day']) + || empty($value['hour']) + || empty($value['minute']) + || (isset($value['second']) && empty($value['second'])) + ) + ) { + return; + } + + if ($this->isNullOnAllEmpty() + && ( + empty($value['year']) + && empty($value['month']) + && empty($value['day']) + && empty($value['hour']) + && empty($value['minute']) + && (!isset($value['second']) || empty($value['second'])) + ) + ) { + // Cannot handle this value + return; + } + + if (! isset($value['second'])) { + $value['second'] = '00'; + } + + $this->filterable($value); + + ksort($value); + + $value = vsprintf($this->format, $value); + + return $value; + } +} diff --git a/library/Zend/Filter/Encrypt.php b/library/Zend/Filter/Encrypt.php index 479a12bd5..7a5152a7b 100644 --- a/library/Zend/Filter/Encrypt.php +++ b/library/Zend/Filter/Encrypt.php @@ -38,9 +38,45 @@ class Encrypt extends AbstractFilter $this->setAdapter($options); } + /** + * Returns the adapter instance + * + * @throws Exception\RuntimeException + * @throws Exception\InvalidArgumentException + * @return Encrypt\EncryptionAlgorithmInterface + */ + public function getAdapterInstance() + { + if ($this->adapter instanceof Encrypt\EncryptionAlgorithmInterface) { + return $this->adapter; + } + + $adapter = $this->adapter; + $options = $this->getOptions(); + if (! class_exists($adapter)) { + $adapter = __CLASS__ . '\\' . ucfirst($adapter); + if (! class_exists($adapter)) { + throw new Exception\RuntimeException(sprintf( + '%s unable to load adapter; class "%s" not found', + __METHOD__, + $this->adapter + )); + } + } + + $this->adapter = new $adapter($options); + if (! $this->adapter instanceof Encrypt\EncryptionAlgorithmInterface) { + throw new Exception\InvalidArgumentException(sprintf( + 'Encryption adapter "%s" does not implement %s\\EncryptionAlgorithmInterface', + $adapter, + __CLASS__ + )); + } + return $this->adapter; + } + /** * Returns the name of the set adapter - * @todo inconsitent: get adapter should return the adapter and not the name * * @return string */ diff --git a/library/Zend/Filter/FilterPluginManager.php b/library/Zend/Filter/FilterPluginManager.php index d556bf72a..7a3b24f7a 100644 --- a/library/Zend/Filter/FilterPluginManager.php +++ b/library/Zend/Filter/FilterPluginManager.php @@ -20,65 +20,87 @@ use Zend\ServiceManager\AbstractPluginManager; */ class FilterPluginManager extends AbstractPluginManager { + protected $aliases = array( + 'Zend\Filter\Int' => 'Zend\Filter\ToInt', + 'Zend\Filter\Null' => 'Zend\Filter\ToNull', + ); + + /** + * Default set of plugins factories + * + * @var array + */ + protected $factories = array( + 'wordseparatortoseparator' => 'Zend\Filter\Word\Service\SeparatorToSeparatorFactory', + ); + /** * Default set of filters * * @var array */ protected $invokableClasses = array( - 'alnum' => 'Zend\I18n\Filter\Alnum', - 'alpha' => 'Zend\I18n\Filter\Alpha', - 'basename' => 'Zend\Filter\BaseName', - 'boolean' => 'Zend\Filter\Boolean', - 'callback' => 'Zend\Filter\Callback', - 'compress' => 'Zend\Filter\Compress', - 'compressbz2' => 'Zend\Filter\Compress\Bz2', - 'compressgz' => 'Zend\Filter\Compress\Gz', - 'compresslzf' => 'Zend\Filter\Compress\Lzf', - 'compressrar' => 'Zend\Filter\Compress\Rar', - 'compresssnappy' => 'Zend\Filter\Compress\Snappy', - 'compresstar' => 'Zend\Filter\Compress\Tar', - 'compresszip' => 'Zend\Filter\Compress\Zip', - 'datetimeformatter' => 'Zend\Filter\DateTimeFormatter', - 'decompress' => 'Zend\Filter\Decompress', - 'decrypt' => 'Zend\Filter\Decrypt', - 'digits' => 'Zend\Filter\Digits', - 'dir' => 'Zend\Filter\Dir', - 'encrypt' => 'Zend\Filter\Encrypt', - 'encryptblockcipher' => 'Zend\Filter\Encrypt\BlockCipher', - 'encryptopenssl' => 'Zend\Filter\Encrypt\Openssl', - 'filedecrypt' => 'Zend\Filter\File\Decrypt', - 'fileencrypt' => 'Zend\Filter\File\Encrypt', - 'filelowercase' => 'Zend\Filter\File\LowerCase', - 'filerename' => 'Zend\Filter\File\Rename', - 'filerenameupload' => 'Zend\Filter\File\RenameUpload', - 'fileuppercase' => 'Zend\Filter\File\UpperCase', - 'htmlentities' => 'Zend\Filter\HtmlEntities', - 'inflector' => 'Zend\Filter\Inflector', - 'int' => 'Zend\Filter\Int', - 'null' => 'Zend\Filter\Null', - 'numberformat' => 'Zend\I18n\Filter\NumberFormat', - 'numberparse' => 'Zend\I18n\Filter\NumberParse', - 'pregreplace' => 'Zend\Filter\PregReplace', - 'realpath' => 'Zend\Filter\RealPath', - 'stringtolower' => 'Zend\Filter\StringToLower', - 'stringtoupper' => 'Zend\Filter\StringToUpper', - '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', - 'worddashtocamelcase' => 'Zend\Filter\Word\DashToCamelCase', - 'worddashtoseparator' => 'Zend\Filter\Word\DashToSeparator', - 'worddashtounderscore' => 'Zend\Filter\Word\DashToUnderscore', - 'wordseparatortocamelcase' => 'Zend\Filter\Word\SeparatorToCamelCase', - 'wordseparatortodash' => 'Zend\Filter\Word\SeparatorToDash', - 'wordseparatortoseparator' => 'Zend\Filter\Word\SeparatorToSeparator', - 'wordunderscoretocamelcase' => 'Zend\Filter\Word\UnderscoreToCamelCase', - 'wordunderscoretodash' => 'Zend\Filter\Word\UnderscoreToDash', - 'wordunderscoretoseparator' => 'Zend\Filter\Word\UnderscoreToSeparator', + 'alnum' => 'Zend\I18n\Filter\Alnum', + 'alpha' => 'Zend\I18n\Filter\Alpha', + 'basename' => 'Zend\Filter\BaseName', + 'blacklist' => 'Zend\Filter\Blacklist', + 'boolean' => 'Zend\Filter\Boolean', + 'callback' => 'Zend\Filter\Callback', + 'compress' => 'Zend\Filter\Compress', + 'compressbz2' => 'Zend\Filter\Compress\Bz2', + 'compressgz' => 'Zend\Filter\Compress\Gz', + 'compresslzf' => 'Zend\Filter\Compress\Lzf', + 'compressrar' => 'Zend\Filter\Compress\Rar', + 'compresssnappy' => 'Zend\Filter\Compress\Snappy', + 'compresstar' => 'Zend\Filter\Compress\Tar', + 'compresszip' => 'Zend\Filter\Compress\Zip', + 'dataunitformatter' => 'Zend\Filter\DataUnitFormatter', + 'dateselect' => 'Zend\Filter\DateSelect', + 'datetimeformatter' => 'Zend\Filter\DateTimeFormatter', + 'datetimeselect' => 'Zend\Filter\DateTimeSelect', + 'decompress' => 'Zend\Filter\Decompress', + 'decrypt' => 'Zend\Filter\Decrypt', + 'digits' => 'Zend\Filter\Digits', + 'dir' => 'Zend\Filter\Dir', + 'encrypt' => 'Zend\Filter\Encrypt', + 'encryptblockcipher' => 'Zend\Filter\Encrypt\BlockCipher', + 'encryptopenssl' => 'Zend\Filter\Encrypt\Openssl', + 'filedecrypt' => 'Zend\Filter\File\Decrypt', + 'fileencrypt' => 'Zend\Filter\File\Encrypt', + 'filelowercase' => 'Zend\Filter\File\LowerCase', + 'filerename' => 'Zend\Filter\File\Rename', + 'filerenameupload' => 'Zend\Filter\File\RenameUpload', + 'fileuppercase' => 'Zend\Filter\File\UpperCase', + 'htmlentities' => 'Zend\Filter\HtmlEntities', + 'inflector' => 'Zend\Filter\Inflector', + 'int' => 'Zend\Filter\ToInt', + 'monthselect' => 'Zend\Filter\MonthSelect', + 'null' => 'Zend\Filter\ToNull', + 'numberformat' => 'Zend\I18n\Filter\NumberFormat', + 'numberparse' => 'Zend\I18n\Filter\NumberParse', + 'pregreplace' => 'Zend\Filter\PregReplace', + 'realpath' => 'Zend\Filter\RealPath', + 'stringtolower' => 'Zend\Filter\StringToLower', + 'stringtoupper' => 'Zend\Filter\StringToUpper', + 'stringtrim' => 'Zend\Filter\StringTrim', + 'stripnewlines' => 'Zend\Filter\StripNewlines', + 'striptags' => 'Zend\Filter\StripTags', + 'toint' => 'Zend\Filter\ToInt', + 'tonull' => 'Zend\Filter\ToNull', + 'urinormalize' => 'Zend\Filter\UriNormalize', + 'whitelist' => 'Zend\Filter\Whitelist', + 'wordcamelcasetodash' => 'Zend\Filter\Word\CamelCaseToDash', + 'wordcamelcasetoseparator' => 'Zend\Filter\Word\CamelCaseToSeparator', + 'wordcamelcasetounderscore' => 'Zend\Filter\Word\CamelCaseToUnderscore', + 'worddashtocamelcase' => 'Zend\Filter\Word\DashToCamelCase', + 'worddashtoseparator' => 'Zend\Filter\Word\DashToSeparator', + 'worddashtounderscore' => 'Zend\Filter\Word\DashToUnderscore', + 'wordseparatortocamelcase' => 'Zend\Filter\Word\SeparatorToCamelCase', + 'wordseparatortodash' => 'Zend\Filter\Word\SeparatorToDash', + 'wordunderscoretocamelcase' => 'Zend\Filter\Word\UnderscoreToCamelCase', + 'wordunderscoretostudlycase' => 'Zend\Filter\Word\UnderscoreToStudlyCase', + 'wordunderscoretodash' => 'Zend\Filter\Word\UnderscoreToDash', + 'wordunderscoretoseparator' => 'Zend\Filter\Word\UnderscoreToSeparator', ); /** diff --git a/library/Zend/Filter/Inflector.php b/library/Zend/Filter/Inflector.php index dc7e07ef3..a6bffdaaf 100644 --- a/library/Zend/Filter/Inflector.php +++ b/library/Zend/Filter/Inflector.php @@ -152,7 +152,7 @@ class Inflector extends AbstractFilter */ public function setThrowTargetExceptionsOn($throwTargetExceptionsOn) { - $this->throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false; + $this->throwTargetExceptionsOn = (bool) $throwTargetExceptionsOn; return $this; } diff --git a/library/Zend/Filter/Int.php b/library/Zend/Filter/Int.php index 787d6eb2c..a65b8d146 100644 --- a/library/Zend/Filter/Int.php +++ b/library/Zend/Filter/Int.php @@ -9,25 +9,27 @@ namespace Zend\Filter; -class Int extends AbstractFilter +/** + * Stub class for backwards compatibility. + * + * Since PHP 7 adds "int" as a reserved keyword, we can no longer have a class + * named that and retain PHP 7 compatibility. The original class has been + * renamed to "ToInt", and this class is now an extension of it. It raises an + * E_USER_DEPRECATED to warn users to migrate. + * + * @deprecated + */ +class Int extends ToInt { - /** - * Defined by Zend\Filter\FilterInterface - * - * Returns (int) $value - * - * If the value provided is non-scalar, the value will remain unfiltered - * - * @param string $value - * @return int|mixed - */ - public function filter($value) + public function __construct() { - if (!is_scalar($value)) { - return $value; - } - $value = (string) $value; - - return (int) $value; + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\ToInt', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); } } diff --git a/library/Zend/Filter/MonthSelect.php b/library/Zend/Filter/MonthSelect.php new file mode 100644 index 000000000..450aafbd0 --- /dev/null +++ b/library/Zend/Filter/MonthSelect.php @@ -0,0 +1,25 @@ + 'boolean', - self::TYPE_INTEGER => 'integer', - self::TYPE_EMPTY_ARRAY => 'array', - self::TYPE_STRING => 'string', - self::TYPE_ZERO_STRING => 'zero', - self::TYPE_FLOAT => 'float', - self::TYPE_ALL => 'all', - ); - - /** - * @var array - */ - protected $options = array( - 'type' => self::TYPE_ALL, - ); - - /** - * Constructor - * - * @param string|array|Traversable $typeOrOptions OPTIONAL + * {@inheritdoc} */ public function __construct($typeOrOptions = null) { - if ($typeOrOptions !== null) { - if ($typeOrOptions instanceof Traversable) { - $typeOrOptions = iterator_to_array($typeOrOptions); - } + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\ToNull', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); - if (is_array($typeOrOptions)) { - if (isset($typeOrOptions['type'])) { - $this->setOptions($typeOrOptions); - } else { - $this->setType($typeOrOptions); - } - } else { - $this->setType($typeOrOptions); - } - } - } - - /** - * Set boolean types - * - * @param int|array $type - * @throws Exception\InvalidArgumentException - * @return self - */ - public function setType($type = null) - { - if (is_array($type)) { - $detected = 0; - foreach ($type as $value) { - if (is_int($value)) { - $detected += $value; - } elseif (in_array($value, $this->constants)) { - $detected += array_search($value, $this->constants); - } - } - - $type = $detected; - } elseif (is_string($type) && in_array($type, $this->constants)) { - $type = array_search($type, $this->constants); - } - - if (!is_int($type) || ($type < 0) || ($type > self::TYPE_ALL)) { - throw new Exception\InvalidArgumentException(sprintf( - 'Unknown type value "%s" (%s)', - $type, - gettype($type) - )); - } - - $this->options['type'] = $type; - return $this; - } - - /** - * Returns defined boolean types - * - * @return int - */ - public function getType() - { - return $this->options['type']; - } - - /** - * Defined by Zend\Filter\FilterInterface - * - * Returns null representation of $value, if value is empty and matches - * types that should be considered null. - * - * @param string $value - * @return string - */ - public function filter($value) - { - $type = $this->getType(); - - // FLOAT (0.0) - if ($type >= self::TYPE_FLOAT) { - $type -= self::TYPE_FLOAT; - if (is_float($value) && ($value == 0.0)) { - return null; - } - } - - // STRING ZERO ('0') - if ($type >= self::TYPE_ZERO_STRING) { - $type -= self::TYPE_ZERO_STRING; - if (is_string($value) && ($value == '0')) { - return null; - } - } - - // STRING ('') - if ($type >= self::TYPE_STRING) { - $type -= self::TYPE_STRING; - if (is_string($value) && ($value == '')) { - return null; - } - } - - // EMPTY_ARRAY (array()) - if ($type >= self::TYPE_EMPTY_ARRAY) { - $type -= self::TYPE_EMPTY_ARRAY; - if (is_array($value) && ($value == array())) { - return null; - } - } - - // INTEGER (0) - if ($type >= self::TYPE_INTEGER) { - $type -= self::TYPE_INTEGER; - if (is_int($value) && ($value == 0)) { - return null; - } - } - - // BOOLEAN (false) - if ($type >= self::TYPE_BOOLEAN) { - $type -= self::TYPE_BOOLEAN; - if (is_bool($value) && ($value == false)) { - return null; - } - } - - return $value; + parent::__construct($typeOrOptions); } } diff --git a/library/Zend/Filter/StringToLower.php b/library/Zend/Filter/StringToLower.php index 9bbd71221..0a5042daa 100644 --- a/library/Zend/Filter/StringToLower.php +++ b/library/Zend/Filter/StringToLower.php @@ -53,7 +53,7 @@ class StringToLower extends AbstractUnicode } $value = (string) $value; - if ($this->options['encoding'] !== null) { + if (null !== $this->getEncoding()) { return mb_strtolower($value, $this->options['encoding']); } diff --git a/library/Zend/Filter/StringToUpper.php b/library/Zend/Filter/StringToUpper.php index 4da55114c..33be1d542 100644 --- a/library/Zend/Filter/StringToUpper.php +++ b/library/Zend/Filter/StringToUpper.php @@ -53,7 +53,7 @@ class StringToUpper extends AbstractUnicode } $value = (string) $value; - if ($this->options['encoding'] !== null) { + if (null !== $this->getEncoding()) { return mb_strtoupper($value, $this->options['encoding']); } diff --git a/library/Zend/Filter/ToInt.php b/library/Zend/Filter/ToInt.php new file mode 100644 index 000000000..8d9b79a9c --- /dev/null +++ b/library/Zend/Filter/ToInt.php @@ -0,0 +1,33 @@ + 'boolean', + self::TYPE_INTEGER => 'integer', + self::TYPE_EMPTY_ARRAY => 'array', + self::TYPE_STRING => 'string', + self::TYPE_ZERO_STRING => 'zero', + self::TYPE_FLOAT => 'float', + self::TYPE_ALL => 'all', + ); + + /** + * @var array + */ + protected $options = array( + 'type' => self::TYPE_ALL, + ); + + /** + * Constructor + * + * @param string|array|Traversable $typeOrOptions OPTIONAL + */ + public function __construct($typeOrOptions = null) + { + if ($typeOrOptions !== null) { + if ($typeOrOptions instanceof Traversable) { + $typeOrOptions = iterator_to_array($typeOrOptions); + } + + if (is_array($typeOrOptions)) { + if (isset($typeOrOptions['type'])) { + $this->setOptions($typeOrOptions); + } else { + $this->setType($typeOrOptions); + } + } else { + $this->setType($typeOrOptions); + } + } + } + + /** + * Set boolean types + * + * @param int|array $type + * @throws Exception\InvalidArgumentException + * @return self + */ + public function setType($type = null) + { + if (is_array($type)) { + $detected = 0; + foreach ($type as $value) { + if (is_int($value)) { + $detected += $value; + } elseif (in_array($value, $this->constants)) { + $detected += array_search($value, $this->constants); + } + } + + $type = $detected; + } elseif (is_string($type) && in_array($type, $this->constants)) { + $type = array_search($type, $this->constants); + } + + if (!is_int($type) || ($type < 0) || ($type > self::TYPE_ALL)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Unknown type value "%s" (%s)', + $type, + gettype($type) + )); + } + + $this->options['type'] = $type; + return $this; + } + + /** + * Returns defined boolean types + * + * @return int + */ + public function getType() + { + return $this->options['type']; + } + + /** + * Defined by Zend\Filter\FilterInterface + * + * Returns null representation of $value, if value is empty and matches + * types that should be considered null. + * + * @param string $value + * @return string + */ + public function filter($value) + { + $type = $this->getType(); + + // FLOAT (0.0) + if ($type >= self::TYPE_FLOAT) { + $type -= self::TYPE_FLOAT; + if (is_float($value) && ($value == 0.0)) { + return; + } + } + + // STRING ZERO ('0') + if ($type >= self::TYPE_ZERO_STRING) { + $type -= self::TYPE_ZERO_STRING; + if (is_string($value) && ($value == '0')) { + return; + } + } + + // STRING ('') + if ($type >= self::TYPE_STRING) { + $type -= self::TYPE_STRING; + if (is_string($value) && ($value == '')) { + return; + } + } + + // EMPTY_ARRAY (array()) + if ($type >= self::TYPE_EMPTY_ARRAY) { + $type -= self::TYPE_EMPTY_ARRAY; + if (is_array($value) && ($value == array())) { + return; + } + } + + // INTEGER (0) + if ($type >= self::TYPE_INTEGER) { + $type -= self::TYPE_INTEGER; + if (is_int($value) && ($value == 0)) { + return; + } + } + + // BOOLEAN (false) + if ($type >= self::TYPE_BOOLEAN) { + $type -= self::TYPE_BOOLEAN; + if (is_bool($value) && ($value == false)) { + return; + } + } + + return $value; + } +} diff --git a/library/Zend/Filter/UpperCaseWords.php b/library/Zend/Filter/UpperCaseWords.php new file mode 100644 index 000000000..0bcdeee42 --- /dev/null +++ b/library/Zend/Filter/UpperCaseWords.php @@ -0,0 +1,61 @@ + null + ); + + /** + * Constructor + * + * @param string|array|\Traversable $encodingOrOptions OPTIONAL + */ + public function __construct($encodingOrOptions = null) + { + if ($encodingOrOptions !== null) { + if (static::isOptions($encodingOrOptions)) { + $this->setOptions($encodingOrOptions); + } else { + $this->setEncoding($encodingOrOptions); + } + } + } + + /** + * {@inheritDoc} + * + * Returns the string $value, converting words to have an uppercase first character as necessary + * + * If the value provided is not a string, the value will remain unfiltered + * + * @param string|mixed $value + * @return string|mixed + */ + public function filter($value) + { + if (! is_string($value)) { + return $value; + } + + $value = (string) $value; + + if ($this->options['encoding'] !== null) { + return mb_convert_case($value, MB_CASE_TITLE, $this->options['encoding']); + } + + return ucwords(strtolower($value)); + } +} diff --git a/library/Zend/Filter/Whitelist.php b/library/Zend/Filter/Whitelist.php new file mode 100644 index 000000000..fafb6eb7b --- /dev/null +++ b/library/Zend/Filter/Whitelist.php @@ -0,0 +1,91 @@ +setOptions($options); + } + } + + /** + * Determine whether the in_array() call should be "strict" or not. See in_array docs. + * + * @param bool $strict + */ + public function setStrict($strict = true) + { + $this->strict = (bool) $strict; + } + + /** + * Returns whether the in_array() call should be "strict" or not. See in_array docs. + * + * @return boolean + */ + public function getStrict() + { + return $this->strict; + } + + /** + * Set the list of items to white-list. + * + * @param array|Traversable $list + */ + public function setList($list = array()) + { + if (!is_array($list)) { + $list = ArrayUtils::iteratorToArray($list); + } + + $this->list = $list; + } + + + /** + * Get the list of items to white-list + * + * @return array + */ + public function getList() + { + return $this->list; + } + + /** + * {@inheritDoc} + * + * Will return $value if its present in the white-list. If $value is rejected then it will return null. + */ + public function filter($value) + { + return in_array($value, $this->getList(), $this->getStrict()) ? $value : null; + } +} diff --git a/library/Zend/Filter/Word/SeparatorToCamelCase.php b/library/Zend/Filter/Word/SeparatorToCamelCase.php index 7526a30f5..931997b0e 100644 --- a/library/Zend/Filter/Word/SeparatorToCamelCase.php +++ b/library/Zend/Filter/Word/SeparatorToCamelCase.php @@ -30,8 +30,8 @@ class SeparatorToCamelCase extends AbstractSeparator if (StringUtils::hasPcreUnicodeSupport()) { $patterns = array( - '#(' . $pregQuotedSeparator.')(\p{L}{1})#u', - '#(^\p{Ll}{1})#u', + '#(' . $pregQuotedSeparator.')(\P{Z}{1})#u', + '#(^\P{Z}{1})#u', ); if (!extension_loaded('mbstring')) { $replacements = array( @@ -54,8 +54,8 @@ class SeparatorToCamelCase extends AbstractSeparator } } else { $patterns = array( - '#(' . $pregQuotedSeparator.')([A-Za-z]{1})#', - '#(^[A-Za-z]{1})#', + '#(' . $pregQuotedSeparator.')([\S]{1})#', + '#(^[\S]{1})#', ); $replacements = array( function ($matches) { diff --git a/library/Zend/Filter/Word/Service/SeparatorToSeparatorFactory.php b/library/Zend/Filter/Word/Service/SeparatorToSeparatorFactory.php new file mode 100644 index 000000000..148ac3b05 --- /dev/null +++ b/library/Zend/Filter/Word/Service/SeparatorToSeparatorFactory.php @@ -0,0 +1,53 @@ +creationOptions = $creationOptions; + } + + /** + * Get creation options + * + * @return array + */ + public function getCreationOptions() + { + return $this->creationOptions; + } + + /** + * {@inheritDoc} + * + * @return SeparatorToSeparator + * @throws ServiceNotCreatedException if Controllermanager service is not found in application service locator + */ + public function createService(ServiceLocatorInterface $plugins) + { + return new SeparatorToSeparator( + isset($this->creationOptions['search_separator']) ? $this->creationOptions['search_separator'] : ' ', + isset($this->creationOptions['replacement_separator']) ? $this->creationOptions['replacement_separator'] : '-' + ); + } +} diff --git a/library/Zend/Filter/Word/UnderscoreToStudlyCase.php b/library/Zend/Filter/Word/UnderscoreToStudlyCase.php new file mode 100644 index 000000000..21a9ec1af --- /dev/null +++ b/library/Zend/Filter/Word/UnderscoreToStudlyCase.php @@ -0,0 +1,36 @@ +=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Form/Annotation/AnnotationBuilder.php b/library/Zend/Form/Annotation/AnnotationBuilder.php index c64613828..014060747 100644 --- a/library/Zend/Form/Annotation/AnnotationBuilder.php +++ b/library/Zend/Form/Annotation/AnnotationBuilder.php @@ -24,11 +24,16 @@ use Zend\Form\FormFactoryAwareInterface; use Zend\Stdlib\ArrayUtils; /** - * Parses a class' properties for annotations in order to create a form and - * input filter definition. + * Parses the properties of a class for annotations in order to create a form + * and input filter definition. */ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareInterface { + /** + * @var Parser\DoctrineAnnotationParser + */ + protected $annotationParser; + /** * @var AnnotationManager */ @@ -56,6 +61,7 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI 'AllowEmpty', 'Attributes', 'ComposedObject', + 'ContinueIfEmpty', 'ErrorMessage', 'Exclude', 'Filter', @@ -63,6 +69,7 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI 'Hydrator', 'Input', 'InputFilter', + 'Instance', 'Name', 'Object', 'Options', @@ -72,6 +79,11 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI 'Validator' ); + /** + * @var bool + */ + protected $preserveDefinedOrder = false; + /** * Set form factory to use when building form from annotations * @@ -92,7 +104,7 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI */ public function setAnnotationManager(AnnotationManager $annotationManager) { - $parser = new Parser\DoctrineAnnotationParser(); + $parser = $this->getAnnotationParser(); foreach ($this->defaultAnnotations as $annotationName) { $class = __NAMESPACE__ . '\\' . $annotationName; $parser->registerAnnotation($class); @@ -214,6 +226,8 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI if (!isset($formSpec['input_filter'])) { $formSpec['input_filter'] = $filterSpec; + } elseif (is_array($formSpec['input_filter'])) { + $formSpec['input_filter'] = ArrayUtils::merge($filterSpec->getArrayCopy(), $formSpec['input_filter']); } return $formSpec; @@ -333,8 +347,9 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI ? $elementSpec['spec']['type'] : 'Zend\Form\Element'; - // Compose as a fieldset or an element, based on specification type - if (is_subclass_of($type, 'Zend\Form\FieldsetInterface')) { + // Compose as a fieldset or an element, based on specification type. + // If preserve defined order is true, all elements are composed as elements to keep their ordering + if (!$this->preserveDefinedOrder() && is_subclass_of($type, 'Zend\Form\FieldsetInterface')) { if (!isset($formSpec['fieldsets'])) { $formSpec['fieldsets'] = array(); } @@ -347,6 +362,24 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI } } + /** + * @param bool $preserveDefinedOrder + * @return $this + */ + public function setPreserveDefinedOrder($preserveDefinedOrder) + { + $this->preserveDefinedOrder = (bool) $preserveDefinedOrder; + return $this; + } + + /** + * @return bool + */ + public function preserveDefinedOrder() + { + return $this->preserveDefinedOrder; + } + /** * Discover the name of the given form or element * @@ -381,6 +414,18 @@ class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareI return (bool) $results->last(); } + /** + * @return \Zend\Code\Annotation\Parser\DoctrineAnnotationParser + */ + public function getAnnotationParser() + { + if (null === $this->annotationParser) { + $this->annotationParser = new Parser\DoctrineAnnotationParser(); + } + + return $this->annotationParser; + } + /** * Checks if the object has this class as one of its parents * diff --git a/library/Zend/Form/Annotation/ContinueIfEmpty.php b/library/Zend/Form/Annotation/ContinueIfEmpty.php new file mode 100644 index 000000000..d81f42733 --- /dev/null +++ b/library/Zend/Form/Annotation/ContinueIfEmpty.php @@ -0,0 +1,57 @@ +filter($continueIfEmpty); + } + + $this->continueIfEmpty = $continueIfEmpty; + } + + /** + * Get value of required flag + * + * @return bool + */ + public function getContinueIfEmpty() + { + return $this->continueIfEmpty; + } +} diff --git a/library/Zend/Form/Annotation/ElementAnnotationsListener.php b/library/Zend/Form/Annotation/ElementAnnotationsListener.php index 8bfdcb495..93e1f2fe7 100644 --- a/library/Zend/Form/Annotation/ElementAnnotationsListener.php +++ b/library/Zend/Form/Annotation/ElementAnnotationsListener.php @@ -25,7 +25,7 @@ use Zend\Stdlib\ArrayObject; * - Flags * - Input * - Hydrator - * - Object + * - Object and Instance (the latter is preferred starting in 2.4) * - Required * - Type * - Validator @@ -44,6 +44,7 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener $this->listeners[] = $events->attach('configureElement', array($this, 'handleAllowEmptyAnnotation')); $this->listeners[] = $events->attach('configureElement', array($this, 'handleAttributesAnnotation')); $this->listeners[] = $events->attach('configureElement', array($this, 'handleComposedObjectAnnotation')); + $this->listeners[] = $events->attach('configureElement', array($this, 'handleContinueIfEmptyAnnotation')); $this->listeners[] = $events->attach('configureElement', array($this, 'handleErrorMessageAnnotation')); $this->listeners[] = $events->attach('configureElement', array($this, 'handleFilterAnnotation')); $this->listeners[] = $events->attach('configureElement', array($this, 'handleFlagsAnnotation')); @@ -97,7 +98,10 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener $elementSpec = $e->getParam('elementSpec'); if (isset($elementSpec['spec']['attributes'])) { - $elementSpec['spec']['attributes'] = array_merge($elementSpec['spec']['attributes'], $annotation->getAttributes()); + $elementSpec['spec']['attributes'] = array_merge( + $elementSpec['spec']['attributes'], + $annotation->getAttributes() + ); return; } @@ -123,7 +127,6 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener $name = $e->getParam('name'); $elementSpec = $e->getParam('elementSpec'); - $filterSpec = $e->getParam('filterSpec'); if ($annotation->isCollection()) { // Compose specification as a fieldset into parent form/fieldset @@ -163,6 +166,11 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener $specification['type'] = 'Zend\Form\Fieldset'; } + if (isset($elementSpec['spec']['options'])) { + $specification['options'] = isset($specification['options']) ? $specification['options'] : array(); + $specification['options'] = array_merge($elementSpec['spec']['options'], $specification['options']); + } + // Add element spec: $elementSpec['spec'] = $specification; $elementSpec['spec']['name'] = $name; @@ -170,6 +178,25 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener } } + /** + * Handle the ContinueIfEmpty annotation + * + * Sets the continue_if_empty flag on the input specification array. + * + * @param \Zend\EventManager\EventInterface $e + * @return void + */ + public function handleContinueIfEmptyAnnotation($e) + { + $annotation = $e->getParam('annotation'); + if (!$annotation instanceof ContinueIfEmpty) { + return; + } + + $inputSpec = $e->getParam('inputSpec'); + $inputSpec['continue_if_empty'] = true; + } + /** * Handle the ErrorMessage annotation * @@ -286,7 +313,7 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener } /** - * Handle the Object annotation + * Handle the Object and Instance annotations * * Sets the object to bind to the form or fieldset * @@ -296,7 +323,9 @@ class ElementAnnotationsListener extends AbstractAnnotationsListener public function handleObjectAnnotation($e) { $annotation = $e->getParam('annotation'); - if (!$annotation instanceof Object) { + + // Only need to typehint on Instance, as Object extends it + if (! $annotation instanceof Instance) { return; } diff --git a/library/Zend/Form/Annotation/FormAnnotationsListener.php b/library/Zend/Form/Annotation/FormAnnotationsListener.php index 985660922..1701391a1 100644 --- a/library/Zend/Form/Annotation/FormAnnotationsListener.php +++ b/library/Zend/Form/Annotation/FormAnnotationsListener.php @@ -20,7 +20,7 @@ use Zend\EventManager\EventManagerInterface; * - Attributes * - Flags * - Hydrator - * - Object + * - Object and Instance (the latter is preferred starting in 2.4) * - InputFilter * - Type * - ValidationGroup @@ -129,7 +129,7 @@ class FormAnnotationsListener extends AbstractAnnotationsListener } /** - * Handle the Object annotation + * Handle the Object and Instance annotations * * Sets the object to bind to the form or fieldset * @@ -139,7 +139,9 @@ class FormAnnotationsListener extends AbstractAnnotationsListener public function handleObjectAnnotation($e) { $annotation = $e->getParam('annotation'); - if (!$annotation instanceof Object) { + + // Only need to typehint on Instance, as Object extends it + if (! $annotation instanceof Instance) { return; } diff --git a/library/Zend/Form/Annotation/InputFilter.php b/library/Zend/Form/Annotation/InputFilter.php index c2c8abc75..f35738f84 100644 --- a/library/Zend/Form/Annotation/InputFilter.php +++ b/library/Zend/Form/Annotation/InputFilter.php @@ -18,7 +18,7 @@ namespace Zend\Form\Annotation; * * @Annotation */ -class InputFilter extends AbstractStringAnnotation +class InputFilter extends AbstractArrayOrStringAnnotation { /** * Retrieve the input filter class diff --git a/library/Zend/Form/Annotation/Instance.php b/library/Zend/Form/Annotation/Instance.php new file mode 100644 index 000000000..395077815 --- /dev/null +++ b/library/Zend/Form/Annotation/Instance.php @@ -0,0 +1,33 @@ +value; + } +} diff --git a/library/Zend/Form/Annotation/Object.php b/library/Zend/Form/Annotation/Object.php index d2dd93bad..ed569f181 100644 --- a/library/Zend/Form/Annotation/Object.php +++ b/library/Zend/Form/Annotation/Object.php @@ -10,23 +10,33 @@ namespace Zend\Form\Annotation; /** - * Object annotation + * Stub class for backwards compatibility. * - * Use this annotation to specify an object to use as the bound object of a form or fieldset + * Since PHP 7 adds "object" as a reserved keyword, we can no longer have a class + * named that and retain PHP 7 compatibility. The original class has been + * renamed to "Instance", and this class is now an extension of it. It raises an + * E_USER_DEPRECATED to warn users to migrate. * + * @deprecated * @Annotation - * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Object extends AbstractStringAnnotation +class Object extends Instance { /** - * Retrieve the object - * - * @return null|string + * {@inheritdoc} */ - public function getObject() + public function __construct(array $data) { - return $this->value; + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\Instance,' + . ' and the annotation @Instance or @Annotation\Instance', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); + + parent::__construct($data); } } diff --git a/library/Zend/Form/Element.php b/library/Zend/Form/Element.php index b450d116d..decdadeb9 100644 --- a/library/Zend/Form/Element.php +++ b/library/Zend/Form/Element.php @@ -160,7 +160,7 @@ class Element implements public function getOption($option) { if (!isset($this->options[$option])) { - return null; + return; } return $this->options[$option]; @@ -206,7 +206,7 @@ class Element implements public function getAttribute($key) { if (!isset($this->attributes[$key])) { - return null; + return; } return $this->attributes[$key]; @@ -446,7 +446,7 @@ class Element implements public function getLabelOption($key) { if (!isset($this->labelOptions[$key])) { - return null; + return; } return $this->labelOptions[$key]; diff --git a/library/Zend/Form/Element/Collection.php b/library/Zend/Form/Element/Collection.php index ff6d1e7f1..112dc9faa 100644 --- a/library/Zend/Form/Element/Collection.php +++ b/library/Zend/Form/Element/Collection.php @@ -209,7 +209,7 @@ class Collection extends Fieldset } // Check to see if elements have been replaced or removed - foreach ($this->byName as $name => $elementOrFieldset) { + foreach ($this->iterator as $name => $elementOrFieldset) { if (isset($data[$name])) { continue; } @@ -516,11 +516,11 @@ class Collection extends Fieldset $values[$key] = $this->hydrator->extract($value); continue; } - + // If the target element is a fieldset that can accept the provided value // we should clone it, inject the value and extract the data - if ( $this->targetElement instanceof FieldsetInterface ) { - if ( ! $this->targetElement->allowObjectBinding($value) ) { + if ($this->targetElement instanceof FieldsetInterface) { + if (! $this->targetElement->allowObjectBinding($value)) { continue; } $targetElement = clone $this->targetElement; @@ -531,9 +531,9 @@ class Collection extends Fieldset } continue; } - + // If the target element is a non-fieldset element, just use the value - if ( $this->targetElement instanceof ElementInterface ) { + if ($this->targetElement instanceof ElementInterface) { $values[$key] = $value; if (!$this->createNewObjects() && $this->has($key)) { $this->get($key)->setValue($value); @@ -590,7 +590,7 @@ class Collection extends Fieldset protected function createTemplateElement() { if (!$this->shouldCreateTemplate) { - return null; + return; } if ($this->templateElement) { diff --git a/library/Zend/Form/Element/DateSelect.php b/library/Zend/Form/Element/DateSelect.php index d05bf4862..5376cc816 100644 --- a/library/Zend/Form/Element/DateSelect.php +++ b/library/Zend/Form/Element/DateSelect.php @@ -43,7 +43,7 @@ class DateSelect extends MonthSelect * - day_attributes: HTML attributes to be rendered with the day element * * @param array|\Traversable $options - * @return DateSelect + * @return self */ public function setOptions($options) { @@ -64,11 +64,21 @@ class DateSelect extends MonthSelect return $this->dayElement; } + /** + * Get both the year and month elements + * + * @return array + */ + public function getElements() + { + return array_merge(array($this->dayElement), parent::getElements()); + } + /** * Set the day attributes * * @param array $dayAttributes - * @return DateSelect + * @return self */ public function setDayAttributes(array $dayAttributes) { @@ -105,7 +115,7 @@ class DateSelect extends MonthSelect $value = array( 'year' => $value->format('Y'), 'month' => $value->format('m'), - 'day' => $value->format('d') + 'day' => $value->format('d'), ); } @@ -169,19 +179,7 @@ class DateSelect extends MonthSelect '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; - } - ) - ) + array('name' => 'DateSelect') ), 'validators' => array( $this->getValidator(), diff --git a/library/Zend/Form/Element/DateTimeSelect.php b/library/Zend/Form/Element/DateTimeSelect.php index a34747f89..c82c7d949 100644 --- a/library/Zend/Form/Element/DateTimeSelect.php +++ b/library/Zend/Form/Element/DateTimeSelect.php @@ -11,8 +11,10 @@ namespace Zend\Form\Element; use DateTime as PhpDateTime; use Exception; +use Traversable; use Zend\Form\FormInterface; use Zend\Form\Exception\InvalidArgumentException; +use Zend\Stdlib\ArrayUtils; use Zend\Validator\ValidatorInterface; use Zend\Validator\Date as DateValidator; @@ -62,19 +64,26 @@ class DateTimeSelect extends DateSelect } /** - * Accepted options for DateTimeSelect (plus the ones from DateSelect) : + * Set options for DateTimeSelect element. + * + * Accepted options for DateTimeSelect (plus the ones from DateSelect): + * * - hour_attributes: HTML attributes to be rendered with the hour element * - minute_attributes: HTML attributes to be rendered with the minute element * - second_attributes: HTML attributes to be rendered with the second element * - should_show_seconds: if set to true, the seconds select is shown * - * @param array|\Traversable $options - * @return DateSelect + * @param array|Traversable $options + * @return self */ public function setOptions($options) { parent::setOptions($options); + if ($options instanceof Traversable) { + $options = ArrayUtils::iteratorToArray($options); + } + if (isset($options['hour_attributes'])) { $this->setHourAttributes($options['hour_attributes']); } @@ -122,7 +131,7 @@ class DateTimeSelect extends DateSelect * Set the hour attributes * * @param array $hourAttributes - * @return DateSelect + * @return self */ public function setHourAttributes(array $hourAttributes) { @@ -144,7 +153,7 @@ class DateTimeSelect extends DateSelect * Set the minute attributes * * @param array $minuteAttributes - * @return DateSelect + * @return self */ public function setMinuteAttributes(array $minuteAttributes) { @@ -166,7 +175,7 @@ class DateTimeSelect extends DateSelect * Set the second attributes * * @param array $secondAttributes - * @return DateSelect + * @return self */ public function setSecondAttributes(array $secondAttributes) { @@ -189,7 +198,7 @@ class DateTimeSelect extends DateSelect * assumed to always be 00 * * @param bool $shouldShowSeconds - * @return DateTimeSelect + * @return self */ public function setShouldShowSeconds($shouldShowSeconds) { @@ -207,8 +216,8 @@ class DateTimeSelect extends DateSelect /** * @param mixed $value - * @throws \Zend\Form\Exception\InvalidArgumentException - * @return void|\Zend\Form\Element + * @return self + * @throws InvalidArgumentException */ public function setValue($value) { @@ -235,7 +244,7 @@ class DateTimeSelect extends DateSelect ); } - if (!isset($value['second'])) { + if (! isset($value['second'])) { $value['second'] = '00'; } @@ -245,10 +254,12 @@ class DateTimeSelect extends DateSelect $this->hourElement->setValue($value['hour']); $this->minuteElement->setValue($value['minute']); $this->secondElement->setValue($value['second']); + + return $this; } /** - * @return String + * @return string */ public function getValue() { @@ -267,7 +278,7 @@ class DateTimeSelect extends DateSelect * Prepare the form element (mostly used for rendering purposes) * * @param FormInterface $form - * @return mixed + * @return void */ public function prepareElement(FormInterface $form) { @@ -305,34 +316,11 @@ class DateTimeSelect extends DateSelect '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)) { - if (!isset($date['second'])) { - $date['second'] = '00'; - } - $date = sprintf( - '%s-%s-%s %s:%s:%s', - $date['year'], - $date['month'], - $date['day'], - $date['hour'], - $date['minute'], - $date['second'] - ); - } - - return $date; - } - ) - ) + array('name' => 'DateTimeSelect') ), 'validators' => array( $this->getValidator(), - ) + ), ); } diff --git a/library/Zend/Form/Element/MonthSelect.php b/library/Zend/Form/Element/MonthSelect.php index 62541bf25..69eaf6156 100644 --- a/library/Zend/Form/Element/MonthSelect.php +++ b/library/Zend/Form/Element/MonthSelect.php @@ -10,10 +10,12 @@ namespace Zend\Form\Element; use DateTime as PhpDateTime; +use Traversable; use Zend\Form\Element; use Zend\Form\ElementPrepareAwareInterface; use Zend\Form\FormInterface; use Zend\InputFilter\InputProviderInterface; +use Zend\Stdlib\ArrayUtils; use Zend\Validator\Regex as RegexValidator; use Zend\Validator\ValidatorInterface; @@ -86,19 +88,26 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep } /** - * Accepted options for DateSelect: + * Set element options. + * + * Accepted options for MonthSelect: + * * - 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 + * @param array|Traversable $options + * @return self */ public function setOptions($options) { parent::setOptions($options); + if ($options instanceof Traversable) { + $options = ArrayUtils::iteratorToArray($options); + } + if (isset($options['month_attributes'])) { $this->setMonthAttributes($options['month_attributes']); } @@ -142,11 +151,21 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep return $this->yearElement; } + /** + * Get both the year and month elements + * + * @return array + */ + public function getElements() + { + return array($this->monthElement, $this->yearElement); + } + /** * Set the month attributes * * @param array $monthAttributes - * @return MonthSelect + * @return self */ public function setMonthAttributes(array $monthAttributes) { @@ -168,7 +187,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep * Set the year attributes * * @param array $yearAttributes - * @return MonthSelect + * @return self */ public function setYearAttributes(array $yearAttributes) { @@ -188,7 +207,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep /** * @param int $minYear - * @return MonthSelect + * @return self */ public function setMinYear($minYear) { @@ -206,7 +225,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep /** * @param int $maxYear - * @return MonthSelect + * @return self */ public function setMaxYear($maxYear) { @@ -224,7 +243,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep /** * @param bool $createEmptyOption - * @return MonthSelect + * @return self */ public function setShouldCreateEmptyOption($createEmptyOption) { @@ -242,7 +261,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep /** * @param bool $renderDelimiters - * @return MonthSelect + * @return self */ public function setShouldRenderDelimiters($renderDelimiters) { @@ -260,7 +279,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep /** * @param mixed $value - * @return void|\Zend\Form\Element + * @return self */ public function setValue($value) { @@ -273,10 +292,11 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep $this->yearElement->setValue($value['year']); $this->monthElement->setValue($value['month']); + return $this; } /** - * @return String + * @return string */ public function getValue() { @@ -291,7 +311,7 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep * Prepare the form element (mostly used for rendering purposes) * * @param FormInterface $form - * @return mixed + * @return void */ public function prepareElement(FormInterface $form) { @@ -322,23 +342,11 @@ class MonthSelect extends Element implements InputProviderInterface, ElementPrep '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; - } - ) - ) + array('name' => 'MonthSelect'), ), 'validators' => array( $this->getValidator(), - ) + ), ); } diff --git a/library/Zend/Form/Element/Range.php b/library/Zend/Form/Element/Range.php index c9cf8e5fe..a4611cf5b 100644 --- a/library/Zend/Form/Element/Range.php +++ b/library/Zend/Form/Element/Range.php @@ -10,7 +10,7 @@ namespace Zend\Form\Element; use Zend\Form\Element\Number as NumberElement; -use Zend\I18n\Validator\Float as NumberValidator; +use Zend\I18n\Validator\IsFloat as NumberValidator; use Zend\Validator\GreaterThan as GreaterThanValidator; use Zend\Validator\LessThan as LessThanValidator; use Zend\Validator\Step as StepValidator; diff --git a/library/Zend/Form/Element/Url.php b/library/Zend/Form/Element/Url.php index 3aceca53e..f03b17135 100644 --- a/library/Zend/Form/Element/Url.php +++ b/library/Zend/Form/Element/Url.php @@ -48,7 +48,7 @@ class Url extends Element implements InputProviderInterface /** * Provide default input rules for this element * - * Attaches an email validator. + * Attaches an uri validator. * * @return array */ diff --git a/library/Zend/Form/Fieldset.php b/library/Zend/Form/Fieldset.php index 062254687..7fa8aa5d4 100644 --- a/library/Zend/Form/Fieldset.php +++ b/library/Zend/Form/Fieldset.php @@ -14,7 +14,7 @@ use Zend\Code\Reflection\ClassReflection; use Zend\Stdlib\Hydrator; use Zend\Stdlib\Hydrator\HydratorAwareInterface; use Zend\Stdlib\Hydrator\HydratorInterface; -use Zend\Stdlib\PriorityQueue; +use Zend\Stdlib\PriorityList; class Fieldset extends Element implements FieldsetInterface { @@ -23,11 +23,6 @@ class Fieldset extends Element implements FieldsetInterface */ protected $factory; - /** - * @var ElementInterface[] - */ - protected $byName = array(); - /** * @var array */ @@ -44,7 +39,7 @@ class Fieldset extends Element implements FieldsetInterface protected $messages = array(); /** - * @var PriorityQueue + * @var PriorityList */ protected $iterator; @@ -82,7 +77,8 @@ class Fieldset extends Element implements FieldsetInterface */ public function __construct($name = null, $options = array()) { - $this->iterator = new PriorityQueue(); + $this->iterator = new PriorityList(); + $this->iterator->isLIFO(false); parent::__construct($name, $options); } @@ -188,8 +184,7 @@ class Fieldset extends Element implements FieldsetInterface $order = $flags['priority']; } - $this->iterator->insert($elementOrFieldset, $order); - $this->byName[$name] = $elementOrFieldset; + $this->iterator->insert($name, $elementOrFieldset, $order); if ($elementOrFieldset instanceof FieldsetInterface) { $this->fieldsets[$name] = $elementOrFieldset; @@ -208,7 +203,7 @@ class Fieldset extends Element implements FieldsetInterface */ public function has($elementOrFieldset) { - return array_key_exists($elementOrFieldset, $this->byName); + return $this->iterator->get($elementOrFieldset) != null; } /** @@ -225,7 +220,7 @@ class Fieldset extends Element implements FieldsetInterface $elementOrFieldset )); } - return $this->byName[$elementOrFieldset]; + return $this->iterator->get($elementOrFieldset); } /** @@ -240,12 +235,9 @@ class Fieldset extends Element implements FieldsetInterface return $this; } - $entry = $this->byName[$elementOrFieldset]; - unset($this->byName[$elementOrFieldset]); + $this->iterator->remove($elementOrFieldset); - $this->iterator->remove($entry); - - if ($entry instanceof FieldsetInterface) { + if (isset($this->fieldsets[$elementOrFieldset])) { unset($this->fieldsets[$elementOrFieldset]); return $this; } @@ -263,9 +255,7 @@ class Fieldset extends Element implements FieldsetInterface */ public function setPriority($elementOrFieldset, $priority) { - $element = $this->get($elementOrFieldset); - $this->remove($elementOrFieldset); - $this->add($element, array('priority' => $priority)); + $this->iterator->setPriority($elementOrFieldset, $priority); return $this; } @@ -336,7 +326,7 @@ class Fieldset extends Element implements FieldsetInterface { if (null === $elementName) { $messages = array(); - foreach ($this->byName as $name => $element) { + foreach ($this->iterator as $name => $element) { $messageSet = $element->getMessages(); if (!is_array($messageSet) && !$messageSet instanceof Traversable @@ -371,7 +361,7 @@ class Fieldset extends Element implements FieldsetInterface { $name = $this->getName(); - foreach ($this->byName as $elementOrFieldset) { + foreach ($this->iterator as $elementOrFieldset) { $elementOrFieldset->setName($name . '[' . $elementOrFieldset->getName() . ']'); // Recursively prepare elements @@ -398,7 +388,7 @@ class Fieldset extends Element implements FieldsetInterface )); } - foreach ($this->byName as $name => $elementOrFieldset) { + foreach ($this->iterator as $name => $elementOrFieldset) { $valueExists = array_key_exists($name, $data); if ($elementOrFieldset instanceof FieldsetInterface) { @@ -439,7 +429,7 @@ class Fieldset extends Element implements FieldsetInterface /** * IteratorAggregate: return internal iterator * - * @return PriorityQueue + * @return PriorityList */ public function getIterator() { @@ -579,7 +569,7 @@ class Fieldset extends Element implements FieldsetInterface continue; } - $element = $this->byName[$name]; + $element = $this->iterator->get($name); if ($element instanceof FieldsetInterface && $element->allowValueBinding()) { $value = $element->bindValues($value); @@ -669,19 +659,17 @@ class Fieldset extends Element implements FieldsetInterface */ public function __clone() { - $items = $this->iterator->toArray(PriorityQueue::EXTR_BOTH); + $items = $this->iterator->toArray(PriorityList::EXTR_BOTH); - $this->byName = array(); $this->elements = array(); $this->fieldsets = array(); - $this->iterator = new PriorityQueue(); + $this->iterator = new PriorityList(); + $this->iterator->isLIFO(false); - foreach ($items as $item) { + foreach ($items as $name => $item) { $elementOrFieldset = clone $item['data']; - $name = $elementOrFieldset->getName(); - $this->iterator->insert($elementOrFieldset, $item['priority']); - $this->byName[$name] = $elementOrFieldset; + $this->iterator->insert($name, $elementOrFieldset, $item['priority']); if ($elementOrFieldset instanceof FieldsetInterface) { $this->fieldsets[$name] = $elementOrFieldset; @@ -689,7 +677,7 @@ class Fieldset extends Element implements FieldsetInterface $this->elements[$name] = $elementOrFieldset; } } - + $this->iterator->rewind(); // Also make a deep copy of the object in case it's used within a collection if (is_object($this->object)) { $this->object = clone $this->object; diff --git a/library/Zend/Form/Form.php b/library/Zend/Form/Form.php index 2259a0fd2..854644f3f 100644 --- a/library/Zend/Form/Form.php +++ b/library/Zend/Form/Form.php @@ -230,7 +230,7 @@ class Form extends Fieldset implements FormInterface { $name = $this->getName(); - foreach ($this->byName as $elementOrFieldset) { + foreach ($this->iterator as $elementOrFieldset) { if ($form->wrapElements()) { $elementOrFieldset->setName($name . '[' . $elementOrFieldset->getName() . ']'); } @@ -620,11 +620,11 @@ class Form extends Fieldset implements FormInterface continue; } - $fieldset = $formOrFieldset->byName[$key]; + $fieldset = $formOrFieldset->iterator->get($key); if ($fieldset instanceof Collection) { if (!isset($data[$key]) && $fieldset->getCount() == 0) { - unset ($validationGroup[$key]); + unset($validationGroup[$key]); continue; } @@ -764,9 +764,7 @@ class Form extends Fieldset implements FormInterface } if (!$fieldset instanceof Collection || !$fieldset->getTargetElement() instanceof FieldsetInterface || $inputFilter instanceof CollectionInputFilter) { - foreach ($elements as $element) { - $name = $element->getName(); - + foreach ($elements as $name => $element) { if ($this->preferFormInputFilter && $inputFilter->has($name)) { continue; } @@ -801,9 +799,7 @@ class Form extends Fieldset implements FormInterface } } - foreach ($fieldset->getFieldsets() as $childFieldset) { - $name = $childFieldset->getName(); - + foreach ($fieldset->getFieldsets() as $name => $childFieldset) { if (!$childFieldset instanceof InputFilterProviderInterface) { if (!$inputFilter->has($name)) { // Add a new empty input filter if it does not exist (or the fieldset's object input filter), diff --git a/library/Zend/Form/LabelAwareTrait.php b/library/Zend/Form/LabelAwareTrait.php index 9afaa7df7..545065d6e 100644 --- a/library/Zend/Form/LabelAwareTrait.php +++ b/library/Zend/Form/LabelAwareTrait.php @@ -131,7 +131,7 @@ trait LabelAwareTrait public function getLabelOption($key) { if (!array_key_exists($key, $this->labelOptions)) { - return null; + return; } return $this->labelOptions[$key]; } diff --git a/library/Zend/Form/View/Helper/AbstractHelper.php b/library/Zend/Form/View/Helper/AbstractHelper.php index 163d04fba..5d952b684 100644 --- a/library/Zend/Form/View/Helper/AbstractHelper.php +++ b/library/Zend/Form/View/Helper/AbstractHelper.php @@ -26,7 +26,6 @@ abstract class AbstractHelper extends BaseAbstractHelper * @var array */ protected $booleanAttributes = array( - 'autocomplete' => array('on' => 'on', 'off' => 'off'), 'autofocus' => array('on' => 'autofocus', 'off' => ''), 'checked' => array('on' => 'checked', 'off' => ''), 'disabled' => array('on' => 'disabled', 'off' => ''), diff --git a/library/Zend/Form/View/Helper/Form.php b/library/Zend/Form/View/Helper/Form.php index cdecbabb7..2dff25708 100644 --- a/library/Zend/Form/View/Helper/Form.php +++ b/library/Zend/Form/View/Helper/Form.php @@ -11,6 +11,7 @@ namespace Zend\Form\View\Helper; use Zend\Form\FieldsetInterface; use Zend\Form\FormInterface; +use Zend\View\Helper\Doctype; /** * View helper for rendering Form objects @@ -37,7 +38,7 @@ class Form extends AbstractHelper * Invoke as function * * @param null|FormInterface $form - * @return Form + * @return Form|string */ public function __invoke(FormInterface $form = null) { @@ -81,10 +82,15 @@ class Form extends AbstractHelper */ public function openTag(FormInterface $form = null) { - $attributes = array( - 'action' => '', - 'method' => 'get', - ); + $doctype = $this->getDoctype(); + $attributes = array(); + + if (! (Doctype::HTML5 === $doctype || Doctype::XHTML5 === $doctype)) { + $attributes = array( + 'action' => '', + 'method' => 'get', + ); + } if ($form instanceof FormInterface) { $formAttributes = $form->getAttributes(); @@ -94,7 +100,11 @@ class Form extends AbstractHelper $attributes = array_merge($attributes, $formAttributes); } - return sprintf('
', $this->createAttributesString($attributes)); + if ($attributes) { + return sprintf('', $this->createAttributesString($attributes)); + } + + return ''; } /** diff --git a/library/Zend/Form/View/Helper/FormButton.php b/library/Zend/Form/View/Helper/FormButton.php index 19c2b191d..74de9f93b 100644 --- a/library/Zend/Form/View/Helper/FormButton.php +++ b/library/Zend/Form/View/Helper/FormButton.php @@ -87,15 +87,15 @@ class FormButton extends FormInput ) ); } - - if (null !== ($translator = $this->getTranslator())) { - $buttonContent = $translator->translate( - $buttonContent, - $this->getTranslatorTextDomain() - ); - } } + if (null !== ($translator = $this->getTranslator())) { + $buttonContent = $translator->translate( + $buttonContent, $this->getTranslatorTextDomain() + ); + } + + if (! $element instanceof LabelAwareInterface || ! $element->getLabelOption('disable_html_escape')) { $escapeHtmlHelper = $this->getEscapeHtmlHelper(); $buttonContent = $escapeHtmlHelper($buttonContent); diff --git a/library/Zend/Form/View/Helper/FormCheckbox.php b/library/Zend/Form/View/Helper/FormCheckbox.php index e5282e5ec..aee31bffd 100644 --- a/library/Zend/Form/View/Helper/FormCheckbox.php +++ b/library/Zend/Form/View/Helper/FormCheckbox.php @@ -58,8 +58,9 @@ class FormCheckbox extends FormInput if ($element->useHiddenElement()) { $hiddenAttributes = array( - 'name' => $attributes['name'], - 'value' => $element->getUncheckedValue(), + 'disabled' => isset($attributes['disabled']) ? $attributes['disabled'] : false, + 'name' => $attributes['name'], + 'value' => $element->getUncheckedValue(), ); $rendered = sprintf( diff --git a/library/Zend/Form/View/Helper/FormCollection.php b/library/Zend/Form/View/Helper/FormCollection.php index fd63aa93b..1e0b30d0f 100644 --- a/library/Zend/Form/View/Helper/FormCollection.php +++ b/library/Zend/Form/View/Helper/FormCollection.php @@ -113,7 +113,7 @@ class FormCollection extends AbstractHelper foreach ($element->getIterator() as $elementOrFieldset) { if ($elementOrFieldset instanceof FieldsetInterface) { - $markup .= $fieldsetHelper($elementOrFieldset); + $markup .= $fieldsetHelper($elementOrFieldset, $this->shouldWrap()); } elseif ($elementOrFieldset instanceof ElementInterface) { $markup .= $elementHelper($elementOrFieldset); } @@ -178,13 +178,13 @@ class FormCollection extends AbstractHelper $elementOrFieldset = $collection->getTemplateElement(); if ($elementOrFieldset instanceof FieldsetInterface) { - $templateMarkup .= $fieldsetHelper($elementOrFieldset); + $templateMarkup .= $fieldsetHelper($elementOrFieldset, $this->shouldWrap()); } elseif ($elementOrFieldset instanceof ElementInterface) { $templateMarkup .= $elementHelper($elementOrFieldset); } return sprintf( - $this->templateWrapper, + $this->getTemplateWrapper(), $escapeHtmlAttribHelper($templateMarkup) ); } diff --git a/library/Zend/Form/View/Helper/FormElement.php b/library/Zend/Form/View/Helper/FormElement.php index 3dfe221bb..8327d18f8 100644 --- a/library/Zend/Form/View/Helper/FormElement.php +++ b/library/Zend/Form/View/Helper/FormElement.php @@ -187,7 +187,7 @@ class FormElement extends BaseAbstractHelper return $this->renderHelper($pluginName, $element); } } - return null; + return; } /** @@ -203,6 +203,6 @@ class FormElement extends BaseAbstractHelper if (isset($this->typeMap[$type])) { return $this->renderHelper($this->typeMap[$type], $element); } - return null; + return; } } diff --git a/library/Zend/Form/View/Helper/FormInput.php b/library/Zend/Form/View/Helper/FormInput.php index 150731c23..e7346159f 100644 --- a/library/Zend/Form/View/Helper/FormInput.php +++ b/library/Zend/Form/View/Helper/FormInput.php @@ -120,8 +120,12 @@ class FormInput extends AbstractHelper $attributes = $element->getAttributes(); $attributes['name'] = $name; - $attributes['type'] = $this->getType($element); + $type = $this->getType($element); + $attributes['type'] = $type; $attributes['value'] = $element->getValue(); + if ('password' == $type) { + $attributes['value'] = ''; + } return sprintf( 'setLabelPosition($labelPosition); - } elseif ($this->labelPosition === null) { - $this->setLabelPosition(self::LABEL_PREPEND); + if (is_null($labelPosition)) { + $labelPosition = $this->getLabelPosition(); } if ($renderErrors !== null) { @@ -106,17 +104,18 @@ class FormRow extends AbstractHelper $this->setPartial($partial); } - return $this->render($element); + return $this->render($element, $labelPosition); } /** * Utility form helper that renders a label (if it exists), an element and errors * * @param ElementInterface $element + * @param null|string $labelPosition * @throws \Zend\Form\Exception\DomainException * @return string */ - public function render(ElementInterface $element) + public function render(ElementInterface $element, $labelPosition = null) { $escapeHtmlHelper = $this->getEscapeHtmlHelper(); $labelHelper = $this->getLabelHelper(); @@ -126,6 +125,10 @@ class FormRow extends AbstractHelper $label = $element->getLabel(); $inputErrorClass = $this->getInputErrorClass(); + if (is_null($labelPosition)) { + $labelPosition = $this->labelPosition; + } + if (isset($label) && '' !== $label) { // Translate the label if (null !== ($translator = $this->getTranslator())) { @@ -146,7 +149,7 @@ class FormRow extends AbstractHelper 'element' => $element, 'label' => $label, 'labelAttributes' => $this->labelAttributes, - 'labelPosition' => $this->labelPosition, + 'labelPosition' => $labelPosition, 'renderErrors' => $this->renderErrors, ); @@ -213,7 +216,11 @@ class FormRow extends AbstractHelper $labelOpen = $labelClose = $label = ''; } - switch ($this->labelPosition) { + if ($element instanceof LabelAwareInterface && $element->getLabelOption('label_position')) { + $labelPosition = $element->getLabelOption('label_position'); + } + + switch ($labelPosition) { case self::LABEL_PREPEND: $markup = $labelOpen . $label . $elementString . $labelClose; break; diff --git a/library/Zend/Form/composer.json b/library/Zend/Form/composer.json index 9d2cad0f5..1c9395e87 100644 --- a/library/Zend/Form/composer.json +++ b/library/Zend/Form/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Form\\": "" } }, - "target-dir": "Zend/Form", "require": { "php": ">=5.3.23", "zendframework/zend-inputfilter": "self.version", diff --git a/library/Zend/Http/Client.php b/library/Zend/Http/Client.php index e204b7345..71c670e54 100644 --- a/library/Zend/Http/Client.php +++ b/library/Zend/Http/Client.php @@ -25,7 +25,7 @@ class Client implements Stdlib\DispatchableInterface * @const string Supported HTTP Authentication methods */ const AUTH_BASIC = 'basic'; - const AUTH_DIGEST = 'digest'; // not implemented yet + const AUTH_DIGEST = 'digest'; /** * @const string POST data encoding methods @@ -233,6 +233,7 @@ class Client implements Stdlib\DispatchableInterface { if (empty($this->request)) { $this->request = new Request(); + $this->request->setAllowCustomMethods(false); } return $this->request; } @@ -411,13 +412,16 @@ class Client implements Stdlib\DispatchableInterface */ public function setEncType($encType, $boundary = null) { - if (!empty($encType)) { - if (!empty($boundary)) { - $this->encType = $encType . "; boundary={$boundary}"; - } else { - $this->encType = $encType; - } + if (null === $encType || empty($encType)) { + $this->encType = null; + return $this; } + + if (! empty($boundary)) { + $encType .= sprintf('; boundary=%s', $boundary); + } + + $this->encType = $encType; return $this; } @@ -715,18 +719,18 @@ class Client implements Stdlib\DispatchableInterface */ public function setAuth($user, $password, $type = self::AUTH_BASIC) { - if (!defined('self::AUTH_' . strtoupper($type))) { + if (!defined('static::AUTH_' . strtoupper($type))) { throw new Exception\InvalidArgumentException("Invalid or not supported authentication type: '$type'"); } + if (empty($user)) { throw new Exception\InvalidArgumentException("The username cannot be empty"); } - $this->auth = array ( + $this->auth = array( 'user' => $user, 'password' => $password, 'type' => $type - ); return $this; @@ -823,7 +827,6 @@ class Client implements Stdlib\DispatchableInterface } $this->redirectCounter = 0; - $response = null; $adapter = $this->getAdapter(); @@ -1140,7 +1143,12 @@ class Client implements Stdlib\DispatchableInterface } break; case self::AUTH_DIGEST : - throw new Exception\RuntimeException("The digest authentication is not implemented yet"); + if (!$this->adapter instanceof Client\Adapter\Curl) { + throw new Exception\RuntimeException("The digest authentication is only available for curl adapters (Zend\\Http\\Client\\Adapter\\Curl)"); + } + + $this->adapter->setCurlOption(CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + $this->adapter->setCurlOption(CURLOPT_USERPWD, $this->auth['user'] . ':' . $this->auth['password']); } } @@ -1394,8 +1402,6 @@ class Client implements Stdlib\DispatchableInterface */ public static function encodeAuthHeader($user, $password, $type = self::AUTH_BASIC) { - $authHeader = null; - switch ($type) { case self::AUTH_BASIC: // In basic authentication, the user name cannot contain ":" @@ -1403,8 +1409,7 @@ class Client implements Stdlib\DispatchableInterface throw new Client\Exception\InvalidArgumentException("The user name cannot contain ':' in 'Basic' HTTP authentication"); } - $authHeader = 'Basic ' . base64_encode($user . ':' . $password); - break; + return 'Basic ' . base64_encode($user . ':' . $password); //case self::AUTH_DIGEST: /** @@ -1416,6 +1421,7 @@ class Client implements Stdlib\DispatchableInterface throw new Client\Exception\InvalidArgumentException("Not a supported HTTP authentication type: '$type'"); } - return $authHeader; + + return; } } diff --git a/library/Zend/Http/Client/Adapter/Curl.php b/library/Zend/Http/Client/Adapter/Curl.php index ccbcfbc5a..cdc406f66 100644 --- a/library/Zend/Http/Client/Adapter/Curl.php +++ b/library/Zend/Http/Client/Adapter/Curl.php @@ -72,7 +72,9 @@ class Curl implements HttpAdapter, StreamInterface public function __construct() { if (!extension_loaded('curl')) { - throw new AdapterException\InitializationException('cURL extension has to be loaded to use this Zend\Http\Client adapter'); + throw new AdapterException\InitializationException( + 'cURL extension has to be loaded to use this Zend\Http\Client adapter' + ); } $this->invalidOverwritableCurlOptions = array( CURLOPT_HTTPGET, @@ -82,14 +84,11 @@ class Curl implements HttpAdapter, StreamInterface CURLOPT_HEADER, CURLOPT_RETURNTRANSFER, CURLOPT_HTTPHEADER, - CURLOPT_POSTFIELDS, CURLOPT_INFILE, CURLOPT_INFILESIZE, CURLOPT_PORT, CURLOPT_MAXREDIRS, CURLOPT_CONNECTTIMEOUT, - CURL_HTTP_VERSION_1_1, - CURL_HTTP_VERSION_1_0, ); } @@ -122,6 +121,11 @@ class Curl implements HttpAdapter, StreamInterface unset($options['proxyuser'], $options['proxypass']); } + if (isset($options['sslverifypeer'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $options['sslverifypeer']); + unset($options['sslverifypeer']); + } + foreach ($options as $k => $v) { $option = strtolower($k); switch ($option) { @@ -144,14 +148,14 @@ class Curl implements HttpAdapter, StreamInterface } /** - * Retrieve the array of all configuration options - * - * @return array - */ - public function getConfig() - { - return $this->config; - } + * Retrieve the array of all configuration options + * + * @return array + */ + public function getConfig() + { + return $this->config; + } /** * Direct setter for cURL adapter related options. @@ -185,15 +189,6 @@ class Curl implements HttpAdapter, StreamInterface $this->close(); } - // If we are connected to a different server or port, disconnect first - if ($this->curl - && is_array($this->connectedTo) - && ($this->connectedTo[0] != $host - || $this->connectedTo[1] != $port) - ) { - $this->close(); - } - // Do the actual connection $this->curl = curl_init(); if ($port != 80) { @@ -248,7 +243,9 @@ class Curl implements HttpAdapter, StreamInterface * @param array $headers * @param string $body * @return string $request - * @throws AdapterException\RuntimeException If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option + * @throws AdapterException\RuntimeException If connection fails, connected + * to wrong host, no PUT file defined, unsupported method, or unsupported + * cURL option. * @throws AdapterException\InvalidArgumentException if $method is currently not supported */ public function write($method, $uri, $httpVersion = 1.1, $headers = array(), $body = '') @@ -268,15 +265,15 @@ class Curl implements HttpAdapter, StreamInterface // ensure correct curl call $curlValue = true; switch ($method) { - case 'GET' : + case 'GET': $curlMethod = CURLOPT_HTTPGET; break; - case 'POST' : + case 'POST': $curlMethod = CURLOPT_POST; break; - case 'PUT' : + case 'PUT': // There are two different types of PUT request, either a Raw Data string has been set // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used. if (is_resource($body)) { @@ -288,7 +285,10 @@ class Curl implements HttpAdapter, StreamInterface if (!isset($headers['Content-Length']) && !isset($this->config['curloptions'][CURLOPT_INFILESIZE]) ) { - throw new AdapterException\RuntimeException("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE."); + throw new AdapterException\RuntimeException( + 'Cannot set a file-handle for cURL option CURLOPT_INFILE' + . ' without also setting its size in CURLOPT_INFILESIZE.' + ); } if (isset($headers['Content-Length'])) { @@ -307,27 +307,27 @@ class Curl implements HttpAdapter, StreamInterface } break; - case 'PATCH' : + case 'PATCH': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "PATCH"; break; - case 'DELETE' : + case 'DELETE': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "DELETE"; break; - case 'OPTIONS' : + case 'OPTIONS': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "OPTIONS"; break; - case 'TRACE' : + case 'TRACE': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "TRACE"; break; - case 'HEAD' : + case 'HEAD': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "HEAD"; break; @@ -401,7 +401,10 @@ class Curl implements HttpAdapter, StreamInterface foreach ((array) $this->config['curloptions'] as $k => $v) { if (!in_array($k, $this->invalidOverwritableCurlOptions)) { if (curl_setopt($this->curl, $k, $v) == false) { - throw new AdapterException\RuntimeException(sprintf("Unknown or erroreous cURL option '%s' set", $k)); + throw new AdapterException\RuntimeException(sprintf( + 'Unknown or erroreous cURL option "%s" set', + $k + )); } } } @@ -422,35 +425,42 @@ class Curl implements HttpAdapter, StreamInterface throw new AdapterException\RuntimeException("Error in cURL request: " . curl_error($this->curl)); } - // cURL automatically decodes chunked-messages, this means we have to disallow the Zend\Http\Response to do it again - if (stripos($this->response, "Transfer-Encoding: chunked\r\n")) { - $this->response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $this->response); - } + // separating header from body because it is dangerous to accidentially replace strings in the body + $responseHeaderSize = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE); + $responseHeaders = substr($this->response, 0, $responseHeaderSize); + + // cURL automatically decodes chunked-messages, this means we have to + // disallow the Zend\Http\Response to do it again. + $responseHeaders = preg_replace("/Transfer-Encoding:\s*chunked\\r\\n/", "", $responseHeaders); // cURL can automatically handle content encoding; prevent double-decoding from occurring if (isset($this->config['curloptions'][CURLOPT_ENCODING]) && '' == $this->config['curloptions'][CURLOPT_ENCODING] - && stripos($this->response, "Content-Encoding: gzip\r\n") ) { - $this->response = str_ireplace("Content-Encoding: gzip\r\n", '', $this->response); + $responseHeaders = preg_replace("/Content-Encoding:\s*gzip\\r\\n/", '', $responseHeaders); } + // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: + $responseHeaders = preg_replace( + "/HTTP\/1.0\s*200\s*Connection\s*established\\r\\n\\r\\n/", + '', + $responseHeaders + ); + + // replace old header with new, cleaned up, header + $this->response = substr_replace($this->response, $responseHeaders, 0, $responseHeaderSize); + // Eliminate multiple HTTP responses. do { - $parts = preg_split('|(?:\r?\n){2}|m', $this->response, 2); - $again = false; + $parts = preg_split('|(?:\r?\n){2}|m', $this->response, 2); + $again = false; if (isset($parts[1]) && preg_match("|^HTTP/1\.[01](.*?)\r\n|mi", $parts[1])) { - $this->response = $parts[1]; - $again = true; + $this->response = $parts[1]; + $again = true; } } while ($again); - // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: - if (stripos($this->response, "HTTP/1.0 200 Connection established\r\n\r\n") !== false) { - $this->response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $this->response); - } - return $request; } diff --git a/library/Zend/Http/Client/Adapter/Proxy.php b/library/Zend/Http/Client/Adapter/Proxy.php index 4b1c69ad0..e4875dacc 100644 --- a/library/Zend/Http/Client/Adapter/Proxy.php +++ b/library/Zend/Http/Client/Adapter/Proxy.php @@ -204,7 +204,7 @@ class Proxy extends Socket protected function connectHandshake($host, $port = 443, $httpVer = '1.1', array &$headers = array()) { $request = "CONNECT $host:$port HTTP/$httpVer\r\n" . - "Host: " . $this->config['proxy_host'] . "\r\n"; + "Host: " . $host . "\r\n"; // Add the user-agent header if (isset($this->config['useragent'])) { diff --git a/library/Zend/Http/Client/Adapter/Test.php b/library/Zend/Http/Client/Adapter/Test.php index 0de14a157..23c6be0d3 100644 --- a/library/Zend/Http/Client/Adapter/Test.php +++ b/library/Zend/Http/Client/Adapter/Test.php @@ -124,9 +124,6 @@ class Test implements AdapterInterface */ public function write($method, $uri, $httpVer = '1.1', $headers = array(), $body = '') { - $host = $uri->getHost(); - $host = (strtolower($uri->getScheme()) == 'https' ? 'sslv2://' . $host : $host); - // Build request headers $path = $uri->getPath(); if (empty($path)) { diff --git a/library/Zend/Http/ClientStatic.php b/library/Zend/Http/ClientStatic.php index 6c8444386..4695a56ce 100644 --- a/library/Zend/Http/ClientStatic.php +++ b/library/Zend/Http/ClientStatic.php @@ -14,17 +14,21 @@ namespace Zend\Http; */ class ClientStatic { + /** + * @var Client + */ protected static $client; /** * Get the static HTTP client * + * @param array|Traversable $options * @return Client */ - protected static function getStaticClient() + protected static function getStaticClient($options = null) { - if (!isset(static::$client)) { - static::$client = new Client(); + if (!isset(static::$client) || $options !== null) { + static::$client = new Client(null, $options); } return static::$client; } @@ -36,9 +40,10 @@ class ClientStatic * @param array $query * @param array $headers * @param mixed $body + * @param array|Traversable $clientOptions * @return Response|bool */ - public static function get($url, $query = array(), $headers = array(), $body = null) + public static function get($url, $query = array(), $headers = array(), $body = null, $clientOptions = null) { if (empty($url)) { return false; @@ -60,7 +65,7 @@ class ClientStatic $request->setContent($body); } - return static::getStaticClient()->send($request); + return static::getStaticClient($clientOptions)->send($request); } /** @@ -70,10 +75,11 @@ class ClientStatic * @param array $params * @param array $headers * @param mixed $body + * @param array|Traversable $clientOptions * @throws Exception\InvalidArgumentException * @return Response|bool */ - public static function post($url, $params, $headers = array(), $body = null) + public static function post($url, $params, $headers = array(), $body = null, $clientOptions = null) { if (empty($url)) { return false; @@ -90,7 +96,7 @@ class ClientStatic } if (!isset($headers['Content-Type'])) { - $headers['Content-Type']= Client::ENC_URLENCODED; + $headers['Content-Type'] = Client::ENC_URLENCODED; } if (!empty($headers) && is_array($headers)) { @@ -101,6 +107,6 @@ class ClientStatic $request->setContent($body); } - return static::getStaticClient()->send($request); + return static::getStaticClient($clientOptions)->send($request); } } diff --git a/library/Zend/Http/Cookies.php b/library/Zend/Http/Cookies.php index eae2a0a69..725c06210 100644 --- a/library/Zend/Http/Cookies.php +++ b/library/Zend/Http/Cookies.php @@ -219,7 +219,8 @@ class Cookies extends Headers // Get correct cookie path $path = $uri->getPath(); - $path = substr($path, 0, strrpos($path, '/')); + $lastSlashPos = strrpos($path, '/') ?: 0; + $path = substr($path, 0, $lastSlashPos); if (! $path) { $path = '/'; } @@ -230,16 +231,13 @@ class Cookies extends Headers switch ($retAs) { case self::COOKIE_OBJECT: return $cookie; - break; case self::COOKIE_STRING_ARRAY: case self::COOKIE_STRING_CONCAT: return $cookie->__toString(); - break; default: throw new Exception\InvalidArgumentException("Invalid value passed for \$retAs: {$retAs}"); - break; } } @@ -270,20 +268,17 @@ class Cookies extends Headers switch ($retAs) { case self::COOKIE_STRING_ARRAY: return array($ptr->__toString()); - break; case self::COOKIE_STRING_CONCAT: return $ptr->__toString(); - break; case self::COOKIE_OBJECT: default: return array($ptr); - break; } } - return null; + return; } /** diff --git a/library/Zend/Http/Header/AbstractDate.php b/library/Zend/Http/Header/AbstractDate.php index 42bf30dd7..e0283547f 100644 --- a/library/Zend/Http/Header/AbstractDate.php +++ b/library/Zend/Http/Header/AbstractDate.php @@ -88,6 +88,44 @@ abstract class AbstractDate implements HeaderInterface return $dateHeader; } + /** + * Create date-based header from strtotime()-compatible string + * + * @param int|string $time + * + * @return self + * + * @throws Exception\InvalidArgumentException + */ + public static function fromTimeString($time) + { + return static::fromTimestamp(strtotime($time)); + } + + /** + * Create date-based header from Unix timestamp + * + * @param int $time + * + * @return self + * + * @throws Exception\InvalidArgumentException + */ + public static function fromTimestamp($time) + { + $dateHeader = new static(); + + if (! $time || ! is_numeric($time)) { + throw new Exception\InvalidArgumentException( + 'Invalid time for "' . $dateHeader->getFieldName() . '" header string' + ); + } + + $dateHeader->setDate(new DateTime('@' . $time)); + + return $dateHeader; + } + /** * Set date output format * diff --git a/library/Zend/Http/Header/Accept.php b/library/Zend/Http/Header/Accept.php index de74a9215..6f2fe1de6 100644 --- a/library/Zend/Http/Header/Accept.php +++ b/library/Zend/Http/Header/Accept.php @@ -80,7 +80,7 @@ class Accept extends AbstractAccept if ($pos = strpos($fieldValuePart, '/')) { $type = trim(substr($fieldValuePart, 0, $pos)); } else { - $type = trim(substr($fieldValuePart, 0)); + $type = trim($fieldValuePart); } $params = $this->getParametersFromFieldValuePart($fieldValuePart); @@ -89,7 +89,7 @@ class Accept extends AbstractAccept $fieldValuePart = trim(substr($fieldValuePart, 0, $pos)); } - if ($pos = strpos($fieldValuePart, '/')) { + if (strpos($fieldValuePart, '/')) { $subtypeWhole = $format = $subtype = trim(substr($fieldValuePart, strpos($fieldValuePart, '/') + 1)); } else { $subtypeWhole = ''; diff --git a/library/Zend/Http/Header/AcceptLanguage.php b/library/Zend/Http/Header/AcceptLanguage.php index 7c00b2591..5b25271a6 100644 --- a/library/Zend/Http/Header/AcceptLanguage.php +++ b/library/Zend/Http/Header/AcceptLanguage.php @@ -85,7 +85,7 @@ class AcceptLanguage extends AbstractAccept $fieldValuePart = $type = trim(substr($fieldValuePart, 0, $pos)); } - if ($pos = strpos($fieldValuePart, '-')) { + if (strpos($fieldValuePart, '-')) { $subtypeWhole = $format = $subtype = trim(substr($fieldValuePart, strpos($fieldValuePart, '-')+1)); } else { $subtypeWhole = ''; diff --git a/library/Zend/Http/Header/CacheControl.php b/library/Zend/Http/Header/CacheControl.php index fa1e429be..678041374 100644 --- a/library/Zend/Http/Header/CacheControl.php +++ b/library/Zend/Http/Header/CacheControl.php @@ -38,7 +38,10 @@ class CacheControl implements HeaderInterface // check to ensure proper header type for this factory if (strtolower($name) !== 'cache-control') { - throw new Exception\InvalidArgumentException('Invalid header line for Cache-Control string: "' . $name . '"'); + throw new Exception\InvalidArgumentException(sprintf( + 'Invalid header line for Cache-Control string: ""', + $name + )); } $directives = static::parseValue($value); @@ -179,11 +182,10 @@ class CacheControl implements HeaderInterface case 0: $directive = $lastMatch; goto state_value; - break; + // intentional fall-through default: throw new Exception\InvalidArgumentException('expected DIRECTIVE'); - break; } state_value: @@ -191,32 +193,29 @@ class CacheControl implements HeaderInterface case 0: $directives[$directive] = substr($lastMatch, 2, -1); goto state_separator; - break; + // intentional fall-through case 1: $directives[$directive] = rtrim(substr($lastMatch, 1)); goto state_separator; - break; + // intentional fall-through default: $directives[$directive] = true; goto state_separator; - break; } state_separator: switch (static::match(array('\s*,\s*', '$'), $value, $lastMatch)) { case 0: goto state_directive; - break; + // intentional fall-through case 1: return $directives; - break; default: throw new Exception\InvalidArgumentException('expected SEPARATOR or END'); - break; } } @@ -231,10 +230,13 @@ class CacheControl implements HeaderInterface */ protected static function match($tokens, &$string, &$lastMatch) { + // Ensure we have a string + $value = (string) $string; + foreach ($tokens as $i => $token) { - if (preg_match('/^' . $token . '/', $string, $matches)) { + if (preg_match('/^' . $token . '/', $value, $matches)) { $lastMatch = $matches[0]; - $string = substr($string, strlen($matches[0])); + $string = substr($value, strlen($matches[0])); return $i; } } diff --git a/library/Zend/Http/Header/ContentType.php b/library/Zend/Http/Header/ContentType.php index dad12d4a6..58f5a465e 100644 --- a/library/Zend/Http/Header/ContentType.php +++ b/library/Zend/Http/Header/ContentType.php @@ -55,7 +55,7 @@ class ContentType implements HeaderInterface $parameters = array(); foreach ($parts as $parameter) { $parameter = trim($parameter); - if (!preg_match('/^(?P[^\s\=]+)\=(?P[^\s\=]*)$/', $parameter, $matches)) { + if (!preg_match('/^(?P[^\s\=]+)\="?(?P[^\s\"]*)"?$/', $parameter, $matches)) { continue; } $parameters[$matches['key']] = $matches['value']; @@ -216,7 +216,7 @@ class ContentType implements HeaderInterface if (isset($this->parameters['charset'])) { return $this->parameters['charset']; } - return null; + return; } /** diff --git a/library/Zend/Http/Header/GenericHeader.php b/library/Zend/Http/Header/GenericHeader.php index 3ad6d71ab..bb1cc0e58 100644 --- a/library/Zend/Http/Header/GenericHeader.php +++ b/library/Zend/Http/Header/GenericHeader.php @@ -88,20 +88,18 @@ class GenericHeader implements HeaderInterface throw new Exception\InvalidArgumentException('Header name must be a string'); } - // Pre-filter to normalize valid characters, change underscore to dash - $fieldName = str_replace('_', '-', $fieldName); - /* - * Following RFC 2616 section 4.2 + * Following RFC 7230 section 3.2 * - * message-header = field-name ":" [ field-value ] - * field-name = token - * - * @see http://tools.ietf.org/html/rfc2616#section-2.2 for token definition. + * header-field = field-name ":" [ field-value ] + * field-name = token + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / + * "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA */ - if (!preg_match('/^[!#-\'*+\-\.0-9A-Z\^-z|~]+$/', $fieldName)) { + if (!preg_match('/^[!#$%&\'*+\-\.\^_`|~0-9a-zA-Z]+$/', $fieldName)) { throw new Exception\InvalidArgumentException( - 'Header name must be a valid RFC 2616 (section 4.2) field-name.' + 'Header name must be a valid RFC 7230 (section 3.2) field-name.' ); } diff --git a/library/Zend/Http/PhpEnvironment/Request.php b/library/Zend/Http/PhpEnvironment/Request.php index aedf90f89..3682f461d 100644 --- a/library/Zend/Http/PhpEnvironment/Request.php +++ b/library/Zend/Http/PhpEnvironment/Request.php @@ -60,8 +60,10 @@ class Request extends HttpRequest * Construct * Instantiates request. */ - public function __construct() + public function __construct($allowCustomMethods = true) { + $this->setAllowCustomMethods($allowCustomMethods); + $this->setEnv(new Parameters($_ENV)); if ($_GET) { @@ -250,7 +252,8 @@ class Request extends HttpRequest // URI scheme if ((!empty($this->serverParams['HTTPS']) && strtolower($this->serverParams['HTTPS']) !== 'off') - || (!empty($this->serverParams['HTTP_X_FORWARDED_PROTO']) && $this->serverParams['HTTP_X_FORWARDED_PROTO'] == 'https') + || (!empty($this->serverParams['HTTP_X_FORWARDED_PROTO']) + && $this->serverParams['HTTP_X_FORWARDED_PROTO'] == 'https') ) { $scheme = 'https'; } else { @@ -360,7 +363,7 @@ class Request extends HttpRequest * Return the parameter container responsible for env parameters or a single parameter value. * * @param string|null $name Parameter name to retrieve, or null to get the whole container. - * @param mixed|null $default Default value to use when the parameter is missing. * @return \Zend\Stdlib\ParametersInterface + * @param mixed|null $default Default value to use when the parameter is missing. * @return \Zend\Stdlib\ParametersInterface|mixed */ public function getEnv($name = null, $default = null) @@ -505,7 +508,8 @@ class Request extends HttpRequest $basename = basename($filename); if ($basename) { $path = ($phpSelf ? trim($phpSelf, '/') : ''); - $baseUrl .= substr($path, 0, strpos($path, $basename)) . $basename; + $basePos = strpos($path, $basename) ?: 0; + $baseUrl .= substr($path, 0, $basePos) . $basename; } } diff --git a/library/Zend/Http/Request.php b/library/Zend/Http/Request.php index 9e53ac2ec..987a47ad6 100644 --- a/library/Zend/Http/Request.php +++ b/library/Zend/Http/Request.php @@ -42,6 +42,11 @@ class Request extends AbstractMessage implements RequestInterface */ protected $method = self::METHOD_GET; + /** + * @var bool + */ + protected $allowCustomMethods = true; + /** * @var string|HttpUri */ @@ -66,22 +71,37 @@ class Request extends AbstractMessage implements RequestInterface * A factory that produces a Request object from a well-formed Http Request string * * @param string $string - * @return Request + * @param bool $allowCustomMethods * @throws Exception\InvalidArgumentException + * @return Request */ - public static function fromString($string) + public static function fromString($string, $allowCustomMethods = true) { + /** @var Request $request */ $request = new static(); + $request->setAllowCustomMethods($allowCustomMethods); $lines = explode("\r\n", $string); // first line must be Method/Uri/Version string - $matches = null; - $methods = implode('|', array( - self::METHOD_OPTIONS, self::METHOD_GET, self::METHOD_HEAD, self::METHOD_POST, - self::METHOD_PUT, self::METHOD_DELETE, self::METHOD_TRACE, self::METHOD_CONNECT, - self::METHOD_PATCH - )); + $matches = null; + $methods = $allowCustomMethods + ? '[\w-]+' + : implode( + '|', + array( + self::METHOD_OPTIONS, + self::METHOD_GET, + self::METHOD_HEAD, + self::METHOD_POST, + self::METHOD_PUT, + self::METHOD_DELETE, + self::METHOD_TRACE, + self::METHOD_CONNECT, + self::METHOD_PATCH + ) + ); + $regex = '#^(?P' . $methods . ')\s(?P[^ ]*)(?:\sHTTP\/(?P\d+\.\d+)){0,1}#'; $firstLine = array_shift($lines); if (!preg_match($regex, $firstLine, $matches)) { @@ -93,6 +113,13 @@ class Request extends AbstractMessage implements RequestInterface $request->setMethod($matches['method']); $request->setUri($matches['uri']); + $parsedUri = parse_url($matches['uri']); + if (array_key_exists('query', $parsedUri)) { + $parsedQuery = array(); + parse_str($parsedUri['query'], $parsedQuery); + $request->setQuery(new Parameters($parsedQuery)); + } + if (isset($matches['version'])) { $request->setVersion($matches['version']); } @@ -137,7 +164,7 @@ class Request extends AbstractMessage implements RequestInterface public function setMethod($method) { $method = strtoupper($method); - if (!defined('static::METHOD_' . $method)) { + if (!defined('static::METHOD_' . $method) && ! $this->getAllowCustomMethods()) { throw new Exception\InvalidArgumentException('Invalid HTTP method passed'); } $this->method = $method; @@ -503,4 +530,20 @@ class Request extends AbstractMessage implements RequestInterface $str .= $this->getContent(); return $str; } + + /** + * @return boolean + */ + public function getAllowCustomMethods() + { + return $this->allowCustomMethods; + } + + /** + * @param boolean $strictMethods + */ + public function setAllowCustomMethods($strictMethods) + { + $this->allowCustomMethods = (bool) $strictMethods; + } } diff --git a/library/Zend/Http/Response.php b/library/Zend/Http/Response.php index 4ff8b99b1..5dcab5991 100644 --- a/library/Zend/Http/Response.php +++ b/library/Zend/Http/Response.php @@ -124,7 +124,7 @@ class Response extends AbstractMessage implements ResponseInterface 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Large', + 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', @@ -245,8 +245,8 @@ class Response extends AbstractMessage implements ResponseInterface $code )); } - $this->statusCode = (int) $code; - return $this; + + return $this->saveStatusCode($code); } /** @@ -276,6 +276,18 @@ class Response extends AbstractMessage implements ResponseInterface )); } + return $this->saveStatusCode($code); + } + + /** + * Assign status code + * + * @param int $code + * @return self + */ + protected function saveStatusCode($code) + { + $this->reasonPhrase = null; $this->statusCode = (int) $code; return $this; } @@ -298,7 +310,7 @@ class Response extends AbstractMessage implements ResponseInterface public function getReasonPhrase() { if (null == $this->reasonPhrase and isset($this->recommendedReasonPhrases[$this->statusCode])) { - return $this->recommendedReasonPhrases[$this->statusCode]; + $this->reasonPhrase = $this->recommendedReasonPhrases[$this->statusCode]; } return $this->reasonPhrase; } diff --git a/library/Zend/Http/composer.json b/library/Zend/Http/composer.json index d459e5542..ec475c49e 100644 --- a/library/Zend/Http/composer.json +++ b/library/Zend/Http/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Http\\": "" } }, - "target-dir": "Zend/Http", "require": { "php": ">=5.3.23", "zendframework/zend-loader": "self.version", diff --git a/library/Zend/I18n/Translator/Plural/Parser.php b/library/Zend/I18n/Translator/Plural/Parser.php index 863834678..ffcf8f210 100644 --- a/library/Zend/I18n/Translator/Plural/Parser.php +++ b/library/Zend/I18n/Translator/Plural/Parser.php @@ -353,7 +353,6 @@ class Parser 'Found invalid character "%s" in input stream', $result )); - break; } $token = $this->getSymbol($id); diff --git a/library/Zend/I18n/Translator/Translator.php b/library/Zend/I18n/Translator/Translator.php index 7f11a63d6..727c61ba4 100644 --- a/library/Zend/I18n/Translator/Translator.php +++ b/library/Zend/I18n/Translator/Translator.php @@ -401,6 +401,8 @@ class Translator implements TranslatorInterface } return ($number == 1 ? $singular : $plural); + } elseif (is_string($translation)) { + $translation = array($translation); } $index = $this->messages[$textDomain][$locale] @@ -461,7 +463,7 @@ class Translator implements TranslatorInterface } } - return null; + return; } /** diff --git a/library/Zend/I18n/Validator/DateTime.php b/library/Zend/I18n/Validator/DateTime.php index f67886b24..24355d1a5 100644 --- a/library/Zend/I18n/Validator/DateTime.php +++ b/library/Zend/I18n/Validator/DateTime.php @@ -272,7 +272,7 @@ class DateTime extends AbstractValidator throw new ValidatorException\InvalidArgumentException($formatter->getErrorMessage()); } } catch (IntlException $intlException) { - throw new ValidatorException\InvalidArgumentException($e->getMessage(), 0, $intlException); + throw new ValidatorException\InvalidArgumentException($intlException->getMessage(), 0, $intlException); } diff --git a/library/Zend/I18n/Validator/Float.php b/library/Zend/I18n/Validator/Float.php index b52aa3962..afa491a12 100644 --- a/library/Zend/I18n/Validator/Float.php +++ b/library/Zend/I18n/Validator/Float.php @@ -9,44 +9,18 @@ namespace Zend\I18n\Validator; -use Locale; -use NumberFormatter; -use Traversable; -use IntlException; -use Zend\I18n\Exception as I18nException; -use Zend\Stdlib\ArrayUtils; -use Zend\Stdlib\StringUtils; -use Zend\Stdlib\StringWrapper\StringWrapperInterface; -use Zend\Validator\AbstractValidator; -use Zend\Validator\Exception; - -class Float extends AbstractValidator +/** + * Stub class for backwards compatibility. + * + * Since PHP 7 adds "float" as a reserved keyword, we can no longer have a class + * named that and retain PHP 7 compatibility. The original class has been + * renamed to "IsFloat", and this class is now an extension of it. It raises an + * E_USER_DEPRECATED to warn users to migrate. + * + * @deprecated + */ +class Float extends IsFloat { - const INVALID = 'floatInvalid'; - const NOT_FLOAT = 'notFloat'; - - /** - * @var array - */ - protected $messageTemplates = array( - self::INVALID => "Invalid type given. String, integer or float expected", - self::NOT_FLOAT => "The input does not appear to be a float", - ); - - /** - * Optional locale - * - * @var string|null - */ - protected $locale; - - /** - * UTF-8 compatable wrapper for string functions - * - * @var StringWrapperInterface - */ - protected $wrapper; - /** * Constructor for the integer validator * @@ -55,197 +29,15 @@ class Float extends AbstractValidator */ public function __construct($options = array()) { - if (!extension_loaded('intl')) { - throw new I18nException\ExtensionNotLoadedException( - sprintf('%s component requires the intl PHP extension', __NAMESPACE__) - ); - } - - $this->wrapper = StringUtils::getWrapper(); - - if ($options instanceof Traversable) { - $options = ArrayUtils::iteratorToArray($options); - } - - if (array_key_exists('locale', $options)) { - $this->setLocale($options['locale']); - } + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\IsFloat', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); parent::__construct($options); } - - /** - * Returns the set locale - * - * @return string - */ - public function getLocale() - { - if (null === $this->locale) { - $this->locale = Locale::getDefault(); - } - return $this->locale; - } - - /** - * Sets the locale to use - * - * @param string|null $locale - * @return Float - */ - public function setLocale($locale) - { - $this->locale = $locale; - return $this; - } - - /** - * Returns true if and only if $value is a floating-point value. Uses the formal definition of a float as described - * in the PHP manual: {@link http://www.php.net/float} - * - * @param string $value - * @return bool - * @throws Exception\InvalidArgumentException - */ - public function isValid($value) - { - if (!is_scalar($value) || is_bool($value)) { - $this->error(self::INVALID); - return false; - } - - $this->setValue($value); - - if (is_float($value) || is_int($value)) { - return true; - } - - // Need to check if this is scientific formatted string. If not, switch to decimal. - $formatter = new NumberFormatter($this->getLocale(), NumberFormatter::SCIENTIFIC); - - try { - if (intl_is_failure($formatter->getErrorCode())) { - throw new Exception\InvalidArgumentException($formatter->getErrorMessage()); - } - } catch (IntlException $intlException) { - throw new Exception\InvalidArgumentException($e->getMessage(), 0, $intlException); - } - - if (StringUtils::hasPcreUnicodeSupport()) { - $exponentialSymbols = '[Ee' . $formatter->getSymbol(NumberFormatter::EXPONENTIAL_SYMBOL) . ']+'; - $search = '/' . $exponentialSymbols . '/u'; - } else { - $exponentialSymbols = '[Ee]'; - $search = '/' . $exponentialSymbols . '/'; - } - - if (!preg_match($search, $value)) { - $formatter = new NumberFormatter($this->getLocale(), NumberFormatter::DECIMAL); - } - - /** - * @desc There are seperator "look-alikes" for decimal and group seperators that are more commonly used than the - * official unicode chracter. We need to replace those with the real thing - or remove it. - */ - $groupSeparator = $formatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL); - $decSeparator = $formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); - - //NO-BREAK SPACE and ARABIC THOUSANDS SEPARATOR - if ($groupSeparator == "\xC2\xA0") { - $value = str_replace(' ', $groupSeparator, $value); - } elseif ($groupSeparator == "\xD9\xAC") { //NumberFormatter doesn't have grouping at all for Arabic-Indic - $value = str_replace(array('\'', $groupSeparator), '', $value); - } - - //ARABIC DECIMAL SEPARATOR - if ($decSeparator == "\xD9\xAB") { - $value = str_replace(',', $decSeparator, $value); - } - - $groupSeparatorPosition = $this->wrapper->strpos($value, $groupSeparator); - $decSeparatorPosition = $this->wrapper->strpos($value, $decSeparator); - - //We have seperators, and they are flipped. i.e. 2.000,000 for en-US - if ($groupSeparatorPosition && $decSeparatorPosition && $groupSeparatorPosition > $decSeparatorPosition) { - $this->error(self::NOT_FLOAT); - - return false; - } - - //If we have Unicode support, we can use the real graphemes, otherwise, just the ASCII characters - $decimal = '['. preg_quote($decSeparator, '/') . ']'; - $prefix = '[+-]'; - $exp = $exponentialSymbols; - $numberRange = '0-9'; - $useUnicode = ''; - $suffix = ''; - - if (StringUtils::hasPcreUnicodeSupport()) { - $prefix = '[' - . preg_quote( - $formatter->getTextAttribute(NumberFormatter::POSITIVE_PREFIX) - . $formatter->getTextAttribute(NumberFormatter::NEGATIVE_PREFIX) - . $formatter->getSymbol(NumberFormatter::PLUS_SIGN_SYMBOL) - . $formatter->getSymbol(NumberFormatter::MINUS_SIGN_SYMBOL), - '/' - ) - . ']{0,3}'; - $suffix = ($formatter->getTextAttribute(NumberFormatter::NEGATIVE_SUFFIX)) - ? '[' - . preg_quote( - $formatter->getTextAttribute(NumberFormatter::POSITIVE_SUFFIX) - . $formatter->getTextAttribute(NumberFormatter::NEGATIVE_SUFFIX) - . $formatter->getSymbol(NumberFormatter::PLUS_SIGN_SYMBOL) - . $formatter->getSymbol(NumberFormatter::MINUS_SIGN_SYMBOL), - '/' - ) - . ']{0,3}' - : ''; - $numberRange = '\p{N}'; - $useUnicode = 'u'; - } - - /** - * @desc Match against the formal definition of a float. The - * exponential number check is modified for RTL non-Latin number - * systems (Arabic-Indic numbering). I'm also switching out the period - * for the decimal separator. The formal definition leaves out +- from - * the integer and decimal notations so add that. This also checks - * that a grouping sperator is not in the last GROUPING_SIZE graphemes - * of the string - i.e. 10,6 is not valid for en-US. - * @see http://www.php.net/float - */ - - $lnum = '[' . $numberRange . ']+'; - $dnum = '(([' . $numberRange . ']*' . $decimal . $lnum . ')|(' . $lnum . $decimal . '[' . $numberRange . ']*))'; - $expDnum = '((' . $prefix . '((' . $lnum . '|' . $dnum . ')' . $exp . $prefix . $lnum . ')' . $suffix . ')|' - . '(' . $suffix . '(' . $lnum . $prefix . $exp . '(' . $dnum . '|' . $lnum . '))' . $prefix . '))'; - - // LEFT-TO-RIGHT MARK (U+200E) is messing up everything for the handful - // of locales that have it - $lnumSearch = str_replace("\xE2\x80\x8E", '', '/^' .$prefix . $lnum . $suffix . '$/' . $useUnicode); - $dnumSearch = str_replace("\xE2\x80\x8E", '', '/^' .$prefix . $dnum . $suffix . '$/' . $useUnicode); - $expDnumSearch = str_replace("\xE2\x80\x8E", '', '/^' . $expDnum . '$/' . $useUnicode); - $value = str_replace("\xE2\x80\x8E", '', $value); - $unGroupedValue = str_replace($groupSeparator, '', $value); - - // No strrpos() in wrappers yet. ICU 4.x doesn't have grouping size for - // everything. ICU 52 has 3 for ALL locales. - $groupSize = ($formatter->getAttribute(NumberFormatter::GROUPING_SIZE)) - ? $formatter->getAttribute(NumberFormatter::GROUPING_SIZE) - : 3; - $lastStringGroup = $this->wrapper->substr($value, -$groupSize); - - if ((preg_match($lnumSearch, $unGroupedValue) - || preg_match($dnumSearch, $unGroupedValue) - || preg_match($expDnumSearch, $unGroupedValue)) - && false === $this->wrapper->strpos($lastStringGroup, $groupSeparator) - ) { - return true; - } - - $this->error(self::NOT_FLOAT); - - return false; - } } diff --git a/library/Zend/I18n/Validator/Int.php b/library/Zend/I18n/Validator/Int.php index 7f8df04b9..b244a228d 100644 --- a/library/Zend/I18n/Validator/Int.php +++ b/library/Zend/I18n/Validator/Int.php @@ -9,36 +9,18 @@ namespace Zend\I18n\Validator; -use Locale; -use NumberFormatter; -use Traversable; -use IntlException; -use Zend\I18n\Exception as I18nException; -use Zend\Stdlib\ArrayUtils; -use Zend\Validator\AbstractValidator; -use Zend\Validator\Exception; - - -class Int extends AbstractValidator +/** + * Stub class for backwards compatibility. + * + * Since PHP 7 adds "int" as a reserved keyword, we can no longer have a class + * named that and retain PHP 7 compatibility. The original class has been + * renamed to "IsInt", and this class is now an extension of it. It raises an + * E_USER_DEPRECATED to warn users to migrate. + * + * @deprecated + */ +class Int extends IsInt { - const INVALID = 'intInvalid'; - const NOT_INT = 'notInt'; - - /** - * @var array - */ - protected $messageTemplates = array( - self::INVALID => "Invalid type given. String or integer expected", - self::NOT_INT => "The input does not appear to be an integer", - ); - - /** - * Optional locale - * - * @var string|null - */ - protected $locale; - /** * Constructor for the integer validator * @@ -47,99 +29,15 @@ class Int extends AbstractValidator */ public function __construct($options = array()) { - if (!extension_loaded('intl')) { - throw new I18nException\ExtensionNotLoadedException(sprintf( - '%s component requires the intl PHP extension', + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\IsInt', + __CLASS__, __NAMESPACE__ - )); - } - - if ($options instanceof Traversable) { - $options = ArrayUtils::iteratorToArray($options); - } - - if (array_key_exists('locale', $options)) { - $this->setLocale($options['locale']); - } + ), + E_USER_DEPRECATED + ); parent::__construct($options); } - - /** - * Returns the set locale - */ - public function getLocale() - { - if (null === $this->locale) { - $this->locale = Locale::getDefault(); - } - return $this->locale; - } - - /** - * Sets the locale to use - * - * @param string $locale - * @return Int - */ - public function setLocale($locale) - { - $this->locale = $locale; - return $this; - } - - /** - * Returns true if and only if $value is a valid integer - * - * @param string|int $value - * @return bool - * @throws Exception\InvalidArgumentException - */ - public function isValid($value) - { - if (!is_string($value) && !is_int($value) && !is_float($value)) { - $this->error(self::INVALID); - return false; - } - - if (is_int($value)) { - return true; - } - - $this->setValue($value); - - $locale = $this->getLocale(); - try { - $format = new NumberFormatter($locale, NumberFormatter::DECIMAL); - if (intl_is_failure($format->getErrorCode())) { - throw new Exception\InvalidArgumentException("Invalid locale string given"); - } - } catch (IntlException $intlException) { - throw new Exception\InvalidArgumentException("Invalid locale string given", 0, $intlException); - } - - try { - $parsedInt = $format->parse($value, NumberFormatter::TYPE_INT64); - if (intl_is_failure($format->getErrorCode())) { - $this->error(self::NOT_INT); - return false; - } - } catch (IntlException $intlException) { - $this->error(self::NOT_INT); - return false; - } - - $decimalSep = $format->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); - $groupingSep = $format->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL); - - $valueFiltered = str_replace($groupingSep, '', $value); - $valueFiltered = str_replace($decimalSep, '.', $valueFiltered); - - if (strval($parsedInt) !== $valueFiltered) { - $this->error(self::NOT_INT); - return false; - } - - return true; - } } diff --git a/library/Zend/I18n/Validator/IsFloat.php b/library/Zend/I18n/Validator/IsFloat.php new file mode 100644 index 000000000..9a985eb29 --- /dev/null +++ b/library/Zend/I18n/Validator/IsFloat.php @@ -0,0 +1,253 @@ + "Invalid type given. String, integer or float expected", + self::NOT_FLOAT => "The input does not appear to be a float", + ); + + /** + * Optional locale + * + * @var string|null + */ + protected $locale; + + /** + * UTF-8 compatable wrapper for string functions + * + * @var StringWrapperInterface + */ + protected $wrapper; + + /** + * Constructor for the integer validator + * + * @param array|Traversable $options + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present + */ + public function __construct($options = array()) + { + if (!extension_loaded('intl')) { + throw new I18nException\ExtensionNotLoadedException( + sprintf('%s component requires the intl PHP extension', __NAMESPACE__) + ); + } + + $this->wrapper = StringUtils::getWrapper(); + + if ($options instanceof Traversable) { + $options = ArrayUtils::iteratorToArray($options); + } + + if (array_key_exists('locale', $options)) { + $this->setLocale($options['locale']); + } + + parent::__construct($options); + } + + /** + * Returns the set locale + * + * @return string + */ + public function getLocale() + { + if (null === $this->locale) { + $this->locale = Locale::getDefault(); + } + return $this->locale; + } + + /** + * Sets the locale to use + * + * @param string|null $locale + * @return Float + */ + public function setLocale($locale) + { + $this->locale = $locale; + return $this; + } + + /** + * Returns true if and only if $value is a floating-point value. Uses the formal definition of a float as described + * in the PHP manual: {@link http://www.php.net/float} + * + * @param string $value + * @return bool + * @throws Exception\InvalidArgumentException + */ + public function isValid($value) + { + if (!is_scalar($value) || is_bool($value)) { + $this->error(self::INVALID); + return false; + } + + $this->setValue($value); + + if (is_float($value) || is_int($value)) { + return true; + } + + // Need to check if this is scientific formatted string. If not, switch to decimal. + $formatter = new NumberFormatter($this->getLocale(), NumberFormatter::SCIENTIFIC); + + try { + if (intl_is_failure($formatter->getErrorCode())) { + throw new Exception\InvalidArgumentException($formatter->getErrorMessage()); + } + } catch (IntlException $intlException) { + throw new Exception\InvalidArgumentException($intlException->getMessage(), 0, $intlException); + } + + if (StringUtils::hasPcreUnicodeSupport()) { + $exponentialSymbols = '[Ee' . $formatter->getSymbol(NumberFormatter::EXPONENTIAL_SYMBOL) . ']+'; + $search = '/' . $exponentialSymbols . '/u'; + } else { + $exponentialSymbols = '[Ee]'; + $search = '/' . $exponentialSymbols . '/'; + } + + if (!preg_match($search, $value)) { + $formatter = new NumberFormatter($this->getLocale(), NumberFormatter::DECIMAL); + } + + /** + * @desc There are seperator "look-alikes" for decimal and group seperators that are more commonly used than the + * official unicode chracter. We need to replace those with the real thing - or remove it. + */ + $groupSeparator = $formatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL); + $decSeparator = $formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); + + //NO-BREAK SPACE and ARABIC THOUSANDS SEPARATOR + if ($groupSeparator == "\xC2\xA0") { + $value = str_replace(' ', $groupSeparator, $value); + } elseif ($groupSeparator == "\xD9\xAC") { + //NumberFormatter doesn't have grouping at all for Arabic-Indic + $value = str_replace(array('\'', $groupSeparator), '', $value); + } + + //ARABIC DECIMAL SEPARATOR + if ($decSeparator == "\xD9\xAB") { + $value = str_replace(',', $decSeparator, $value); + } + + $groupSeparatorPosition = $this->wrapper->strpos($value, $groupSeparator); + $decSeparatorPosition = $this->wrapper->strpos($value, $decSeparator); + + //We have seperators, and they are flipped. i.e. 2.000,000 for en-US + if ($groupSeparatorPosition && $decSeparatorPosition && $groupSeparatorPosition > $decSeparatorPosition) { + $this->error(self::NOT_FLOAT); + + return false; + } + + //If we have Unicode support, we can use the real graphemes, otherwise, just the ASCII characters + $decimal = '['. preg_quote($decSeparator, '/') . ']'; + $prefix = '[+-]'; + $exp = $exponentialSymbols; + $numberRange = '0-9'; + $useUnicode = ''; + $suffix = ''; + + if (StringUtils::hasPcreUnicodeSupport()) { + $prefix = '[' + . preg_quote( + $formatter->getTextAttribute(NumberFormatter::POSITIVE_PREFIX) + . $formatter->getTextAttribute(NumberFormatter::NEGATIVE_PREFIX) + . $formatter->getSymbol(NumberFormatter::PLUS_SIGN_SYMBOL) + . $formatter->getSymbol(NumberFormatter::MINUS_SIGN_SYMBOL), + '/' + ) + . ']{0,3}'; + $suffix = ($formatter->getTextAttribute(NumberFormatter::NEGATIVE_SUFFIX)) + ? '[' + . preg_quote( + $formatter->getTextAttribute(NumberFormatter::POSITIVE_SUFFIX) + . $formatter->getTextAttribute(NumberFormatter::NEGATIVE_SUFFIX) + . $formatter->getSymbol(NumberFormatter::PLUS_SIGN_SYMBOL) + . $formatter->getSymbol(NumberFormatter::MINUS_SIGN_SYMBOL), + '/' + ) + . ']{0,3}' + : ''; + $numberRange = '\p{N}'; + $useUnicode = 'u'; + } + + /** + * @desc Match against the formal definition of a float. The + * exponential number check is modified for RTL non-Latin number + * systems (Arabic-Indic numbering). I'm also switching out the period + * for the decimal separator. The formal definition leaves out +- from + * the integer and decimal notations so add that. This also checks + * that a grouping sperator is not in the last GROUPING_SIZE graphemes + * of the string - i.e. 10,6 is not valid for en-US. + * @see http://www.php.net/float + */ + + $lnum = '[' . $numberRange . ']+'; + $dnum = '(([' . $numberRange . ']*' . $decimal . $lnum . ')|(' + . $lnum . $decimal . '[' . $numberRange . ']*))'; + $expDnum = '((' . $prefix . '((' . $lnum . '|' . $dnum . ')' . $exp . $prefix . $lnum . ')' . $suffix . ')|' + . '(' . $suffix . '(' . $lnum . $prefix . $exp . '(' . $dnum . '|' . $lnum . '))' . $prefix . '))'; + + // LEFT-TO-RIGHT MARK (U+200E) is messing up everything for the handful + // of locales that have it + $lnumSearch = str_replace("\xE2\x80\x8E", '', '/^' .$prefix . $lnum . $suffix . '$/' . $useUnicode); + $dnumSearch = str_replace("\xE2\x80\x8E", '', '/^' .$prefix . $dnum . $suffix . '$/' . $useUnicode); + $expDnumSearch = str_replace("\xE2\x80\x8E", '', '/^' . $expDnum . '$/' . $useUnicode); + $value = str_replace("\xE2\x80\x8E", '', $value); + $unGroupedValue = str_replace($groupSeparator, '', $value); + + // No strrpos() in wrappers yet. ICU 4.x doesn't have grouping size for + // everything. ICU 52 has 3 for ALL locales. + $groupSize = ($formatter->getAttribute(NumberFormatter::GROUPING_SIZE)) + ? $formatter->getAttribute(NumberFormatter::GROUPING_SIZE) + : 3; + $lastStringGroup = $this->wrapper->substr($value, -$groupSize); + + if ((preg_match($lnumSearch, $unGroupedValue) + || preg_match($dnumSearch, $unGroupedValue) + || preg_match($expDnumSearch, $unGroupedValue)) + && false === $this->wrapper->strpos($lastStringGroup, $groupSeparator) + ) { + return true; + } + + $this->error(self::NOT_FLOAT); + + return false; + } +} diff --git a/library/Zend/I18n/Validator/IsInt.php b/library/Zend/I18n/Validator/IsInt.php new file mode 100644 index 000000000..e4a815f03 --- /dev/null +++ b/library/Zend/I18n/Validator/IsInt.php @@ -0,0 +1,144 @@ + "Invalid type given. String or integer expected", + self::NOT_INT => "The input does not appear to be an integer", + ); + + /** + * Optional locale + * + * @var string|null + */ + protected $locale; + + /** + * Constructor for the integer validator + * + * @param array|Traversable $options + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present + */ + public function __construct($options = array()) + { + if (!extension_loaded('intl')) { + throw new I18nException\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + + if ($options instanceof Traversable) { + $options = ArrayUtils::iteratorToArray($options); + } + + if (array_key_exists('locale', $options)) { + $this->setLocale($options['locale']); + } + + parent::__construct($options); + } + + /** + * Returns the set locale + */ + public function getLocale() + { + if (null === $this->locale) { + $this->locale = Locale::getDefault(); + } + return $this->locale; + } + + /** + * Sets the locale to use + * + * @param string $locale + * @return Int + */ + public function setLocale($locale) + { + $this->locale = $locale; + return $this; + } + + /** + * Returns true if and only if $value is a valid integer + * + * @param string|int $value + * @return bool + * @throws Exception\InvalidArgumentException + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value)) { + $this->error(self::INVALID); + return false; + } + + if (is_int($value)) { + return true; + } + + $this->setValue($value); + + $locale = $this->getLocale(); + try { + $format = new NumberFormatter($locale, NumberFormatter::DECIMAL); + if (intl_is_failure($format->getErrorCode())) { + throw new Exception\InvalidArgumentException("Invalid locale string given"); + } + } catch (IntlException $intlException) { + throw new Exception\InvalidArgumentException("Invalid locale string given", 0, $intlException); + } + + try { + $parsedInt = $format->parse($value, NumberFormatter::TYPE_INT64); + if (intl_is_failure($format->getErrorCode())) { + $this->error(self::NOT_INT); + return false; + } + } catch (IntlException $intlException) { + $this->error(self::NOT_INT); + return false; + } + + $decimalSep = $format->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); + $groupingSep = $format->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL); + + $valueFiltered = str_replace($groupingSep, '', $value); + $valueFiltered = str_replace($decimalSep, '.', $valueFiltered); + + if (strval($parsedInt) !== $valueFiltered) { + $this->error(self::NOT_INT); + return false; + } + + return true; + } +} diff --git a/library/Zend/I18n/Validator/PhoneNumber/FR.php b/library/Zend/I18n/Validator/PhoneNumber/FR.php index b14e32afd..d12baba17 100644 --- a/library/Zend/I18n/Validator/PhoneNumber/FR.php +++ b/library/Zend/I18n/Validator/PhoneNumber/FR.php @@ -13,9 +13,9 @@ return array( 'national' => array( 'general' => '/^[124-9]\\d{8}|3\\d{3}(?:\\d{5})?$/', 'fixed' => '/^[1-5]\\d{8}$/', - 'mobile' => '/^[6-7]\\d{8}|7[5-9]\\d{7}$/', + 'mobile' => '/^(?:[6-7]\\d{8}|7[5-9]\\d{7})$/', 'tollfree' => '/^80\\d{7}$/', - 'premium' => '/^3\\d{3}|89[1-37-9]\\d{6}$/', + 'premium' => '/^(?:3\\d{3}|89[1-37-9])\\d{6}$/', 'shared' => '/^8(?:1[019]|2[0156]|84|90)\\d{6}$/', 'voip' => '/^9\\d{8}$/', 'emergency' => '/^1(?:[578]|12)$/', diff --git a/library/Zend/I18n/Validator/PhoneNumber/XK.php b/library/Zend/I18n/Validator/PhoneNumber/XK.php new file mode 100644 index 000000000..e0da04df7 --- /dev/null +++ b/library/Zend/I18n/Validator/PhoneNumber/XK.php @@ -0,0 +1,34 @@ + '383', + 'patterns' => array( + 'national' => array( + 'general' => '/^[126-9]\\d{4,11}|3(?:[0-79]\\d{3,10}|8[2-9]\\d{2,9})$/', + 'fixed' => '/^(?:1(?:[02-9][2-9]|1[1-9])\\d|2(?:[0-24-7][2-9]\\d|[389](?:0[2-9]|[2-9]\\d))|3(?:[0-8][2-9]\\d|9(?:[2-9]\\d|0[2-9])))\\d{3,8}$/', + 'mobile' => '/^6(?:[0-689]|7\\d)\\d{6,7}$/', + 'tollfree' => '/^800\\d{3,9}$/', + 'premium' => '/^(?:90[0169]|78\\d)\\d{3,7}$/', + 'uan' => '/^7[06]\\d{4,10}$/', + 'shortcode' => '/^1(?:1(?:[013-9]|\\d(2,4))|[89]\\d{1,4})$/', + 'emergency' => '/^112|9[234]$/', + ), + 'possible' => array( + 'general' => '/^\\d{5,12}$/', + 'fixed' => '/^\\d{5,12}$/', + 'mobile' => '/^\\d{8,10}$/', + 'tollfree' => '/^\\d{6,12}$/', + 'premium' => '/^\\d{6,12}$/', + 'uan' => '/^\\d{6,12}$/', + 'shortcode' => '/^\\d{3,6}$/', + 'emergency' => '/^\\d{2,3}$/', + ), + ), +); diff --git a/library/Zend/I18n/Validator/PostCode.php b/library/Zend/I18n/Validator/PostCode.php index da532bb86..eafc39057 100644 --- a/library/Zend/I18n/Validator/PostCode.php +++ b/library/Zend/I18n/Validator/PostCode.php @@ -61,7 +61,7 @@ class PostCode extends AbstractValidator * @var array */ protected static $postCodeRegex = array( - 'GB' => 'GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}', + 'GB' => 'GIR[ ]?0AA|^((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))$|^BFPO[ ]?\d{1,4}', 'JE' => 'JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}', 'GG' => 'GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}', 'IM' => 'IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}', @@ -69,7 +69,7 @@ class PostCode extends AbstractValidator 'CA' => '[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d', 'DE' => '\d{5}', 'JP' => '\d{3}-\d{4}', - 'FR' => '\d{2}[ ]?\d{3}', + 'FR' => '(?!(0{2})|(9(6|9))[ ]?\d{3})(\d{2}[ ]?\d{3})', 'AU' => '\d{4}', 'IT' => '\d{5}', 'CH' => '\d{4}', @@ -79,7 +79,7 @@ class PostCode extends AbstractValidator 'BE' => '\d{4}', 'DK' => '\d{4}', 'SE' => '\d{3}[ ]?\d{2}', - 'NO' => '\d{4}', + 'NO' => '(?!0000)\d{4}', 'BR' => '\d{5}[\-]?\d{3}', 'PT' => '\d{4}([\-]\d{3})?', 'FI' => '\d{5}', diff --git a/library/Zend/I18n/View/Helper/AbstractTranslatorHelper.php b/library/Zend/I18n/View/Helper/AbstractTranslatorHelper.php index 61b3a32ee..5e7cacd63 100644 --- a/library/Zend/I18n/View/Helper/AbstractTranslatorHelper.php +++ b/library/Zend/I18n/View/Helper/AbstractTranslatorHelper.php @@ -64,7 +64,7 @@ abstract class AbstractTranslatorHelper extends AbstractHelper implements public function getTranslator() { if (! $this->isTranslatorEnabled()) { - return null; + return; } return $this->translator; diff --git a/library/Zend/I18n/composer.json b/library/Zend/I18n/composer.json index 6eec5a6a1..955683b0e 100644 --- a/library/Zend/I18n/composer.json +++ b/library/Zend/I18n/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\I18n\\": "" } }, - "target-dir": "Zend/I18n", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/InputFilter/ArrayInput.php b/library/Zend/InputFilter/ArrayInput.php index 4d1dc7b43..08876f91e 100644 --- a/library/Zend/InputFilter/ArrayInput.php +++ b/library/Zend/InputFilter/ArrayInput.php @@ -50,11 +50,18 @@ class ArrayInput extends Input */ public function isValid($context = null) { - $this->injectNotEmptyValidator(); + if (!$this->continueIfEmpty() && !$this->allowEmpty()) { + $this->injectNotEmptyValidator(); + } $validator = $this->getValidatorChain(); $values = $this->getValue(); $result = true; foreach ($values as $value) { + $empty = ($value === null || $value === '' || $value === array()); + if ($empty && $this->allowEmpty() && !$this->continueIfEmpty()) { + $result = true; + continue; + } $result = $validator->isValid($value, $context); if (!$result) { if ($this->hasFallback()) { diff --git a/library/Zend/InputFilter/BaseInputFilter.php b/library/Zend/InputFilter/BaseInputFilter.php index 13dd90017..3e41a24cd 100644 --- a/library/Zend/InputFilter/BaseInputFilter.php +++ b/library/Zend/InputFilter/BaseInputFilter.php @@ -189,10 +189,11 @@ class BaseInputFilter implements /** * Is the data set valid? * + * @param mixed|null $context * @throws Exception\RuntimeException * @return bool */ - public function isValid() + public function isValid($context = null) { $data = $this->getRawValues(); if (null === $data) { @@ -203,17 +204,18 @@ class BaseInputFilter implements } $inputs = $this->validationGroup ?: array_keys($this->inputs); - return $this->validateInputs($inputs, $data); + return $this->validateInputs($inputs, $data, $context); } /** * Validate a set of inputs against the current data * - * @param array $inputs - * @param array $data + * @param array $inputs + * @param array $data + * @param mixed|null $context * @return bool */ - protected function validateInputs(array $inputs, array $data = array()) + protected function validateInputs(array $inputs, array $data = array(), $context = null) { // backwards compatibility if (empty($data)) { @@ -226,109 +228,15 @@ class BaseInputFilter implements foreach ($inputs as $name) { $input = $this->inputs[$name]; - $dataExists = array_key_exists($name, $data); - // key doesn't exist, but input is not required; valid - if (!$dataExists - && $input instanceof InputInterface - && !$input->isRequired() - ) { - $this->validInputs[$name] = $input; - continue; - } - - // key doesn't exist, input is required, allows empty; valid if - // continueIfEmpty is false or input doesn't implement - // that interface; otherwise validation chain continues - if (!$dataExists - && $input instanceof InputInterface - && $input->isRequired() - && $input->allowEmpty() - ) { - if (!($input instanceof EmptyContextInterface && $input->continueIfEmpty())) { - $this->validInputs[$name] = $input; - continue; - } - } - - // key exists, is null, input is not required; valid - if ($dataExists - && null === $data[$name] - && $input instanceof InputInterface - && !$input->isRequired() - ) { - $this->validInputs[$name] = $input; - continue; - } - - // key exists, is null, input is required, allows empty; valid if - // continueIfEmpty is false or input doesn't implement - // that interface; otherwise validation chain continues - if ($dataExists - && null === $data[$name] - && $input instanceof InputInterface - && $input->isRequired() - && $input->allowEmpty() - ) { - if (!($input instanceof EmptyContextInterface && $input->continueIfEmpty())) { - $this->validInputs[$name] = $input; - continue; - } - } - - // key exists, empty string, input is not required, allows empty; valid - if ($dataExists - && '' === $data[$name] - && $input instanceof InputInterface - && !$input->isRequired() - && $input->allowEmpty() - ) { - $this->validInputs[$name] = $input; - continue; - } - - // key exists, empty string, input is required, allows empty; valid - // if continueIfEmpty is false, otherwise validation continues - if ($dataExists - && '' === $data[$name] - && $input instanceof InputInterface - && $input->isRequired() - && $input->allowEmpty() - ) { - if (!($input instanceof EmptyContextInterface && $input->continueIfEmpty())) { - $this->validInputs[$name] = $input; - continue; - } - } - - // key exists, is array representing file, no file present, input not - // required or allows empty; valid - if ($dataExists - && is_array($data[$name]) - && ( - (isset($data[$name]['error']) - && $data[$name]['error'] === UPLOAD_ERR_NO_FILE) - || (count($data[$name]) === 1 - && isset($data[$name][0]) - && is_array($data[$name][0]) - && isset($data[$name][0]['error']) - && $data[$name][0]['error'] === UPLOAD_ERR_NO_FILE) - ) - && $input instanceof InputInterface - && (!$input->isRequired() || $input->allowEmpty()) - ) { - $this->validInputs[$name] = $input; - continue; - } - - // make sure we have a value (empty) for validation - if (!$dataExists) { + // make sure we have a value (empty) for validation of context + if (!array_key_exists($name, $data)) { $data[$name] = null; } // Validate an input filter if ($input instanceof InputFilterInterface) { - if (!$input->isValid()) { + if (!$input->isValid($context)) { $this->invalidInputs[$name] = $input; $valid = false; continue; @@ -339,7 +247,9 @@ class BaseInputFilter implements // Validate an input if ($input instanceof InputInterface) { - if (!$input->isValid($data)) { + $inputContext = $context ?: $data; + + if (!$input->isValid($inputContext)) { // Validation failure $this->invalidInputs[$name] = $input; $valid = false; @@ -531,6 +441,7 @@ class BaseInputFilter implements $values[$name] = $input->getRawValues(); continue; } + $values[$name] = $input->getRawValue(); } return $values; @@ -679,4 +590,18 @@ class BaseInputFilter implements { return $this->inputs; } + + /** + * Merges the inputs from an InputFilter into the current one + * + * @param BaseInputFilter $inputFilter + * + * @return self + */ + public function merge(BaseInputFilter $inputFilter) + { + foreach ($inputFilter->getInputs() as $name => $input) { + $this->add($input, $name); + } + } } diff --git a/library/Zend/InputFilter/Factory.php b/library/Zend/InputFilter/Factory.php index ff1796512..244233ec5 100644 --- a/library/Zend/InputFilter/Factory.php +++ b/library/Zend/InputFilter/Factory.php @@ -145,13 +145,17 @@ class Factory /** * Factory for input objects * - * @param array|Traversable $inputSpecification + * @param array|Traversable|InputProviderInterface $inputSpecification * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException * @return InputInterface|InputFilterInterface */ public function createInput($inputSpecification) { + if ($inputSpecification instanceof InputProviderInterface) { + $inputSpecification = $inputSpecification->getInputSpecification(); + } + if (!is_array($inputSpecification) && !$inputSpecification instanceof Traversable) { throw new Exception\InvalidArgumentException(sprintf( '%s expects an array or Traversable; received "%s"', @@ -269,13 +273,17 @@ class Factory /** * Factory for input filters * - * @param array|Traversable $inputFilterSpecification + * @param array|Traversable|InputFilterProviderInterface $inputFilterSpecification * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException * @return InputFilterInterface */ public function createInputFilter($inputFilterSpecification) { + if ($inputFilterSpecification instanceof InputFilterProviderInterface) { + $inputFilterSpecification = $inputFilterSpecification->getInputFilterSpecification(); + } + if (!is_array($inputFilterSpecification) && !$inputFilterSpecification instanceof Traversable) { throw new Exception\InvalidArgumentException(sprintf( '%s expects an array or Traversable; received "%s"', diff --git a/library/Zend/InputFilter/FileInput.php b/library/Zend/InputFilter/FileInput.php index 223d7cb90..3a11f934d 100644 --- a/library/Zend/InputFilter/FileInput.php +++ b/library/Zend/InputFilter/FileInput.php @@ -83,16 +83,46 @@ class FileInput extends Input return $value; } + /** + * Checks if the raw input value is an empty file input eg: no file was uploaded + * + * @param $rawValue + * @return bool + */ + public function isEmptyFile($rawValue) + { + if (!is_array($rawValue)) { + return true; + } + + if (isset($rawValue['error']) && $rawValue['error'] === UPLOAD_ERR_NO_FILE) { + return true; + } + + if (count($rawValue) === 1 && isset($rawValue[0])) { + return $this->isEmptyFile($rawValue[0]); + } + + return false; + } + /** * @param mixed $context Extra "context" to provide the validator * @return bool */ public function isValid($context = null) { + $rawValue = $this->getRawValue(); + $empty = $this->isEmptyFile($rawValue); + + if ($empty && $this->allowEmpty() && !$this->continueIfEmpty()) { + return true; + } + $this->injectUploadValidator(); $validator = $this->getValidatorChain(); //$value = $this->getValue(); // Do not run the filters yet for File uploads (see getValue()) - $rawValue = $this->getRawValue(); + if (!is_array($rawValue)) { // This can happen in an AJAX POST, where the input comes across as a string $rawValue = array( diff --git a/library/Zend/InputFilter/Input.php b/library/Zend/InputFilter/Input.php index a5dae88f0..665af4218 100644 --- a/library/Zend/InputFilter/Input.php +++ b/library/Zend/InputFilter/Input.php @@ -319,14 +319,21 @@ class Input implements InputInterface, EmptyContextInterface */ public function isValid($context = null) { + $value = $this->getValue(); + $empty = ($value === null || $value === '' || $value === array()); + + if ($empty && $this->allowEmpty() && !$this->continueIfEmpty()) { + return true; + } + // Empty value needs further validation if continueIfEmpty is set // so don't inject NotEmpty validator which would always // mark that as false - if (!$this->continueIfEmpty()) { + if (!$this->continueIfEmpty() && !$this->allowEmpty()) { $this->injectNotEmptyValidator(); } $validator = $this->getValidatorChain(); - $value = $this->getValue(); + $result = $validator->isValid($value, $context); if (!$result && $this->hasFallback()) { $this->setValue($this->getFallbackValue()); @@ -372,7 +379,14 @@ class Input implements InputInterface, EmptyContextInterface } } - $chain->prependByName('NotEmpty', array(), true); $this->notEmptyValidator = true; + + if (class_exists('Zend\ServiceManager\AbstractPluginManager')) { + $chain->prependByName('NotEmpty', array(), true); + + return; + } + + $chain->prependValidator(new NotEmpty(), true); } } diff --git a/library/Zend/InputFilter/InputFilterAbstractServiceFactory.php b/library/Zend/InputFilter/InputFilterAbstractServiceFactory.php new file mode 100644 index 000000000..19a53b7f2 --- /dev/null +++ b/library/Zend/InputFilter/InputFilterAbstractServiceFactory.php @@ -0,0 +1,112 @@ +getServiceLocator(); + if (! $services instanceof ServiceLocatorInterface + || ! $services->has('Config') + ) { + return false; + } + + $config = $services->get('Config'); + if (!isset($config['input_filter_specs'][$rName]) + || !is_array($config['input_filter_specs'][$rName]) + ) { + return false; + } + + return true; + } + + /** + * @param ServiceLocatorInterface $inputFilters + * @param string $cName + * @param string $rName + * @return \Zend\InputFilter\InputFilterInterface + */ + public function createServiceWithName(ServiceLocatorInterface $inputFilters, $cName, $rName) + { + $services = $inputFilters->getServiceLocator(); + $allConfig = $services->get('Config'); + $config = $allConfig['input_filter_specs'][$rName]; + + $factory = $this->getInputFilterFactory($services); + + return $factory->createInputFilter($config); + } + + /** + * @param ServiceLocatorInterface $services + * @return Factory + */ + protected function getInputFilterFactory(ServiceLocatorInterface $services) + { + if ($this->factory instanceof Factory) { + return $this->factory; + } + + $this->factory = new Factory(); + $this->factory + ->getDefaultFilterChain() + ->setPluginManager($this->getFilterPluginManager($services)); + $this->factory + ->getDefaultValidatorChain() + ->setPluginManager($this->getValidatorPluginManager($services)); + + return $this->factory; + } + + /** + * @param ServiceLocatorInterface $services + * @return FilterPluginManager + */ + protected function getFilterPluginManager(ServiceLocatorInterface $services) + { + if ($services->has('FilterManager')) { + return $services->get('FilterManager'); + } + + return new FilterPluginManager(); + } + + /** + * @param ServiceLocatorInterface $services + * @return ValidatorPluginManager + */ + protected function getValidatorPluginManager(ServiceLocatorInterface $services) + { + if ($services->has('ValidatorManager')) { + return $services->get('ValidatorManager'); + } + + return new ValidatorPluginManager(); + } +} diff --git a/library/Zend/InputFilter/InputInterface.php b/library/Zend/InputFilter/InputInterface.php index 134b06d81..14b0529a8 100644 --- a/library/Zend/InputFilter/InputInterface.php +++ b/library/Zend/InputFilter/InputInterface.php @@ -14,26 +14,112 @@ use Zend\Validator\ValidatorChain; interface InputInterface { + /** + * @param bool $allowEmpty + * @return self + */ public function setAllowEmpty($allowEmpty); + + /** + * @param bool $breakOnFailure + * @return self + */ public function setBreakOnFailure($breakOnFailure); + + /** + * @param string|null $errorMessage + * @return self + */ public function setErrorMessage($errorMessage); + + /** + * @param FilterChain $filterChain + * @return self + */ public function setFilterChain(FilterChain $filterChain); + + /** + * @param string $name + * @return self + */ public function setName($name); + + /** + * @param bool $required + * @return self + */ public function setRequired($required); + + /** + * @param ValidatorChain $validatorChain + * @return self + */ public function setValidatorChain(ValidatorChain $validatorChain); + + /** + * @param mixed $value + * @return self + */ public function setValue($value); + + /** + * @param InputInterface $input + * @return self + */ public function merge(InputInterface $input); + /** + * @return bool + */ public function allowEmpty(); + + /** + * @return bool + */ public function breakOnFailure(); + + /** + * @return string|null + */ public function getErrorMessage(); + + /** + * @return FilterChain + */ public function getFilterChain(); + + /** + * @return string + */ public function getName(); + + /** + * @return mixed + */ public function getRawValue(); + + /** + * @return bool + */ public function isRequired(); + + /** + * @return ValidatorChain + */ public function getValidatorChain(); + + /** + * @return mixed + */ public function getValue(); + /** + * @return bool + */ public function isValid(); + + /** + * @return array + */ public function getMessages(); } diff --git a/library/Zend/InputFilter/composer.json b/library/Zend/InputFilter/composer.json index 886d7310b..ca9357d84 100644 --- a/library/Zend/InputFilter/composer.json +++ b/library/Zend/InputFilter/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\InputFilter\\": "" } }, - "target-dir": "Zend/InputFilter", "require": { "php": ">=5.3.23", "zendframework/zend-filter": "self.version", diff --git a/library/Zend/Json/Decoder.php b/library/Zend/Json/Decoder.php index 15937da2f..fc4779bb3 100644 --- a/library/Zend/Json/Decoder.php +++ b/library/Zend/Json/Decoder.php @@ -220,16 +220,12 @@ class Decoder $result = $this->tokenValue; $this->_getNextToken(); return($result); - break; case self::LBRACE: return($this->_decodeObject()); - break; case self::LBRACKET: return($this->_decodeArray()); - break; default: - return null; - break; + return; } } diff --git a/library/Zend/Json/Encoder.php b/library/Zend/Json/Encoder.php index 82929e44c..5c02f1afe 100644 --- a/library/Zend/Json/Encoder.php +++ b/library/Zend/Json/Encoder.php @@ -65,7 +65,7 @@ class Encoder */ public static function encode($value, $cycleCheck = false, $options = array()) { - $encoder = new static(($cycleCheck) ? true : false, $options); + $encoder = new static($cycleCheck, $options); if ($value instanceof JsonSerializable) { $value = $value->jsonSerialize(); diff --git a/library/Zend/Json/Json.php b/library/Zend/Json/Json.php index 41512460a..e8253df50 100644 --- a/library/Zend/Json/Json.php +++ b/library/Zend/Json/Json.php @@ -114,16 +114,29 @@ class Json $valueToEncode = static::_recursiveJsonExprFinder($valueToEncode, $javascriptExpressions); } + $prettyPrint = (isset($options['prettyPrint']) && ($options['prettyPrint'] == true)); + // Encoding if (function_exists('json_encode') && static::$useBuiltinEncoderDecoder !== true) { + $encodeOptions = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP; + + if ($prettyPrint && defined('JSON_PRETTY_PRINT')) { + $encodeOptions |= JSON_PRETTY_PRINT; + $prettyPrint = false; + } + $encodedResult = json_encode( $valueToEncode, - JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP + $encodeOptions ); } else { $encodedResult = Encoder::encode($valueToEncode, $cycleCheck, $options); } + if ($prettyPrint) { + $encodedResult = self::prettyPrint($encodedResult, array("intent" => " ")); + } + //only do post-processing to revert back the Zend\Json\Expr if any. if (count($javascriptExpressions) > 0) { $count = count($javascriptExpressions); @@ -322,8 +335,6 @@ class Json throw new RuntimeException('Function fromXml was called with an invalid XML formatted string.'); } // End of if ($simpleXmlElementObject == null) - $resultArray = null; - // Call the recursive function to convert the XML into a PHP array. $resultArray = static::_processXml($simpleXmlElementObject, $ignoreXmlAttributes); @@ -348,17 +359,22 @@ class Json $result = ""; $indent = 0; - $ind = "\t"; + $ind = " "; if (isset($options['indent'])) { $ind = $options['indent']; } $inLiteral = false; foreach ($tokens as $token) { + $token = trim($token); if ($token == "") { continue; } + if (preg_match('/^("(?:.*)"):[ ]?(.*)$/', $token, $matches)) { + $token = $matches[1] . ': ' . $matches[2]; + } + $prefix = str_repeat($ind, $indent); if (!$inLiteral && ($token == "{" || $token == "[")) { $indent++; diff --git a/library/Zend/Json/Server/Request.php b/library/Zend/Json/Server/Request.php index cb57e4f49..d27e10a93 100644 --- a/library/Zend/Json/Server/Request.php +++ b/library/Zend/Json/Server/Request.php @@ -135,7 +135,7 @@ class Request return $this->params[$index]; } - return null; + return; } /** diff --git a/library/Zend/Json/Server/Server.php b/library/Zend/Json/Server/Server.php index c5076e622..531ccf363 100644 --- a/library/Zend/Json/Server/Server.php +++ b/library/Zend/Json/Server/Server.php @@ -269,7 +269,7 @@ class Server extends AbstractServer */ public function setReturnResponse($flag = true) { - $this->returnResponse = ($flag) ? true : false; + $this->returnResponse = (bool) $flag; return $this; } @@ -304,7 +304,7 @@ class Server extends AbstractServer } } } - return null; + return; } /** diff --git a/library/Zend/Json/composer.json b/library/Zend/Json/composer.json index 0ca65aa4b..53abdcc2c 100644 --- a/library/Zend/Json/composer.json +++ b/library/Zend/Json/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Json\\": "" } }, - "target-dir": "Zend/Json", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Ldap/Attribute.php b/library/Zend/Ldap/Attribute.php index 9ff7e8dfc..80524c06a 100644 --- a/library/Zend/Ldap/Attribute.php +++ b/library/Zend/Ldap/Attribute.php @@ -81,15 +81,15 @@ class Attribute return $retArray; } elseif (is_int($index)) { if (!isset($data[$attribName])) { - return null; + return; } elseif ($index >= 0 && $index < count($data[$attribName])) { return self::valueFromLdap($data[$attribName][$index]); } else { - return null; + return; } } - return null; + return; } /** @@ -318,7 +318,7 @@ class Attribute return Converter\Converter::toLdapDateTime($value, $utc); } - return null; + return; } /** @@ -361,10 +361,10 @@ class Attribute try { return Converter\Converter::fromLdapDateTime($value, false)->format('U'); } catch (Converter\Exception\InvalidArgumentException $e) { - return null; + return; } } - return null; + return; } } diff --git a/library/Zend/Ldap/Collection.php b/library/Zend/Ldap/Collection.php index 2e7f30888..2204c6a86 100644 --- a/library/Zend/Ldap/Collection.php +++ b/library/Zend/Ldap/Collection.php @@ -88,7 +88,7 @@ class Collection implements Iterator, Countable $this->rewind(); return $this->current(); } - return null; + return; } /** @@ -128,13 +128,13 @@ class Collection implements Iterator, Countable if (!array_key_exists($this->current, $this->cache)) { $current = $this->iterator->current(); if ($current === null) { - return null; + return; } $this->cache[$this->current] = $this->createEntry($current); } return $this->cache[$this->current]; } - return null; + return; } /** @@ -161,7 +161,7 @@ class Collection implements Iterator, Countable } return $this->iterator->key(); } - return null; + return; } /** @@ -178,7 +178,7 @@ class Collection implements Iterator, Countable } return $this->current; } - return null; + return; } /** diff --git a/library/Zend/Ldap/Collection/DefaultIterator.php b/library/Zend/Ldap/Collection/DefaultIterator.php index 5876f390c..9c71ed330 100644 --- a/library/Zend/Ldap/Collection/DefaultIterator.php +++ b/library/Zend/Ldap/Collection/DefaultIterator.php @@ -192,7 +192,7 @@ class DefaultIterator implements Iterator, Countable $this->rewind(); } if (!is_resource($this->current)) { - return null; + return; } $entry = array('dn' => $this->key()); @@ -270,7 +270,7 @@ class DefaultIterator implements Iterator, Countable return $currentDn; } else { - return null; + return; } } diff --git a/library/Zend/Ldap/Converter/Converter.php b/library/Zend/Ldap/Converter/Converter.php index 4347ba28c..e6ff940e8 100644 --- a/library/Zend/Ldap/Converter/Converter.php +++ b/library/Zend/Ldap/Converter/Converter.php @@ -85,10 +85,8 @@ class Converter switch ($type) { case self::BOOLEAN: return static::toldapBoolean($value); - break; case self::GENERALIZED_TIME: return static::toLdapDatetime($value); - break; default: if (is_string($value)) { return $value; @@ -106,10 +104,9 @@ class Converter return static::toLdapSerialize($value); } elseif (is_resource($value) && get_resource_type($value) === 'stream') { return stream_get_contents($value); - } else { - return null; } - break; + + return; } } catch (\Exception $e) { throw new Exception\ConverterException($e->getMessage(), $e->getCode(), $e); @@ -166,7 +163,7 @@ class Converter if (!is_scalar($value)) { return $return; } - if (true === $value || 'true' === strtolower($value) || 1 === $value) { + if (true === $value || (is_string($value) && 'true' === strtolower($value)) || 1 === $value) { $return = 'TRUE'; } return $return; @@ -202,10 +199,8 @@ class Converter switch ($type) { case self::BOOLEAN: return static::fromldapBoolean($value); - break; case self::GENERALIZED_TIME: return static::fromLdapDateTime($value); - break; default: if (is_numeric($value)) { // prevent numeric values to be treated as date/time @@ -326,7 +321,9 @@ class Converter if (isset($off[3])) { $offsetMinutes = substr($off[3], 0, 2); if ($offsetMinutes < 0 || $offsetMinutes > 59) { - throw new Exception\InvalidArgumentException('Invalid date format found (invalid offset minute)'); + throw new Exception\InvalidArgumentException( + 'Invalid date format found (invalid offset minute)' + ); } $time['offsetminutes'] = $offsetMinutes; } @@ -334,9 +331,6 @@ class Converter } // Raw-Data is present, so lets create a DateTime-Object from it. - $offset = $time['offdir'] - . str_pad($time['offsethours'], 2, '0', STR_PAD_LEFT) - . str_pad($time['offsetminutes'], 2, '0', STR_PAD_LEFT); $timestring = $time['year'] . '-' . str_pad($time['month'], 2, '0', STR_PAD_LEFT) . '-' . str_pad($time['day'], 2, '0', STR_PAD_LEFT) . ' ' diff --git a/library/Zend/Ldap/Dn.php b/library/Zend/Ldap/Dn.php index 0809a15ce..1b94e19e8 100644 --- a/library/Zend/Ldap/Dn.php +++ b/library/Zend/Ldap/Dn.php @@ -445,10 +445,8 @@ class Dn implements ArrayAccess case self::ATTR_CASEFOLD_UPPER: case self::ATTR_CASEFOLD_LOWER: return $caseFold; - break; default: return $default; - break; } } @@ -474,7 +472,7 @@ class Dn implements ArrayAccess foreach ($values as $key => $val) { // Escaping of filter meta characters $val = str_replace( - array('\\', ',', '+', '"', '<', '>', ';', '#', '=',), + array('\\', ',', '+', '"', '<', '>', ';', '#', '='), array('\\\\', '\,', '\+', '\"', '\<', '\>', '\;', '\#', '\='), $val ); $val = Converter\Converter::ascToHex32($val); @@ -518,7 +516,7 @@ class Dn implements ArrayAccess // strip slashes from special chars $val = str_replace( array('\\\\', '\,', '\+', '\"', '\<', '\>', '\;', '\#', '\='), - array('\\', ',', '+', '"', '<', '>', ';', '#', '=',), $val + array('\\', ',', '+', '"', '<', '>', ';', '#', '=', ), $val ); $values[$key] = Converter\Converter::hex32ToAsc($val); } @@ -594,8 +592,6 @@ class Dn implements ArrayAccess * to state 1. If a backslash (\) is encountered, state 3 is used to collect the * following character without engaging the logic of other states. */ - $key = null; - $value = null; $slen = strlen($dn); $state = 1; $ko = $vo = 0; diff --git a/library/Zend/Ldap/Ldap.php b/library/Zend/Ldap/Ldap.php index f4d036fc0..cd7cff5aa 100644 --- a/library/Zend/Ldap/Ldap.php +++ b/library/Zend/Ldap/Ldap.php @@ -1083,7 +1083,7 @@ class Ldap } } - return null; + return; } /** diff --git a/library/Zend/Ldap/Ldif/Encoder.php b/library/Zend/Ldap/Ldif/Encoder.php index 6e2184eeb..6d6ae8779 100644 --- a/library/Zend/Ldap/Ldif/Encoder.php +++ b/library/Zend/Ldap/Ldif/Encoder.php @@ -87,7 +87,6 @@ class Encoder } elseif (count($item) > 0 && $name === 'dn') { $items[] = $item; $item = array(); - $last = null; } $last = array($name, $type, $value); } elseif (trim($line) === '') { @@ -156,7 +155,7 @@ class Encoder return $value->toLdif($this->options); } - return null; + return; } /** diff --git a/library/Zend/Ldap/Node.php b/library/Zend/Ldap/Node.php index 1cd3920e6..cea738018 100644 --- a/library/Zend/Ldap/Node.php +++ b/library/Zend/Ldap/Node.php @@ -221,7 +221,7 @@ class Node extends Node\AbstractNode implements Iterator, RecursiveIterator $this->originalData = array(); } $this->children = null; - $this->markAsNew(($fromDataSource === true) ? false : true); + $this->markAsNew($fromDataSource !== true); $this->markAsToBeDeleted(false); } @@ -268,7 +268,7 @@ class Node extends Node\AbstractNode implements Iterator, RecursiveIterator } $data = $ldap->getEntry($dn, array('*', '+'), true); if ($data === null) { - return null; + return; } $entry = new static($dn, $data, true, $ldap); @@ -295,7 +295,7 @@ class Node extends Node\AbstractNode implements Iterator, RecursiveIterator } else { throw new Exception\LdapException(null, '\'dn\' key is of a wrong data type.'); } - $fromDataSource = ($fromDataSource === true) ? true : false; + $fromDataSource = ($fromDataSource === true); $new = new static($dn, $data, $fromDataSource, null); $new->ensureRdnAttributeValues(); @@ -328,7 +328,7 @@ class Node extends Node\AbstractNode implements Iterator, RecursiveIterator */ protected function markAsNew($new) { - $this->new = ($new === false) ? false : true; + $this->new = (bool) $new; } /** @@ -353,7 +353,7 @@ class Node extends Node\AbstractNode implements Iterator, RecursiveIterator */ protected function markAsToBeDeleted($delete) { - $this->delete = ($delete === true) ? true : false; + $this->delete = (bool) $delete; } diff --git a/library/Zend/Ldap/Node/ChildrenIterator.php b/library/Zend/Ldap/Node/ChildrenIterator.php index 7c4eaa407..6296e46e6 100644 --- a/library/Zend/Ldap/Node/ChildrenIterator.php +++ b/library/Zend/Ldap/Node/ChildrenIterator.php @@ -127,7 +127,7 @@ class ChildrenIterator implements Iterator, Countable, RecursiveIterator, ArrayA return $this->current()->getChildren(); } - return null; + return; } /** @@ -143,7 +143,7 @@ class ChildrenIterator implements Iterator, Countable, RecursiveIterator, ArrayA return $this->data[$rdn]; } - return null; + return; } /** diff --git a/library/Zend/Ldap/Node/Schema/AbstractItem.php b/library/Zend/Ldap/Node/Schema/AbstractItem.php index 635a146a1..3de4bfd7e 100644 --- a/library/Zend/Ldap/Node/Schema/AbstractItem.php +++ b/library/Zend/Ldap/Node/Schema/AbstractItem.php @@ -70,7 +70,7 @@ abstract class AbstractItem implements ArrayAccess, Countable return $this->data[$name]; } - return null; + return; } /** diff --git a/library/Zend/Ldap/Node/Schema/AttributeType/OpenLdap.php b/library/Zend/Ldap/Node/Schema/AttributeType/OpenLdap.php index 78226cda0..65af6af44 100644 --- a/library/Zend/Ldap/Node/Schema/AttributeType/OpenLdap.php +++ b/library/Zend/Ldap/Node/Schema/AttributeType/OpenLdap.php @@ -47,7 +47,7 @@ class OpenLdap extends Schema\AbstractItem implements AttributeTypeInterface if ($this->syntax === null) { $parent = $this->getParent(); if ($parent === null) { - return null; + return; } else { return $parent->getSyntax(); } @@ -67,7 +67,7 @@ class OpenLdap extends Schema\AbstractItem implements AttributeTypeInterface if ($maxLength === null) { $parent = $this->getParent(); if ($parent === null) { - return null; + return; } else { return $parent->getMaxLength(); } @@ -107,6 +107,6 @@ class OpenLdap extends Schema\AbstractItem implements AttributeTypeInterface return $this->_parents[0]; } - return null; + return; } } diff --git a/library/Zend/Ldap/composer.json b/library/Zend/Ldap/composer.json index 512d8903e..bf527af6e 100644 --- a/library/Zend/Ldap/composer.json +++ b/library/Zend/Ldap/composer.json @@ -8,13 +8,13 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Ldap\\": "" } }, - "target-dir": "Zend/Ldap", "require": { "php": ">=5.3.23", + "ext-ldap": "*", "zendframework/zend-stdlib": "self.version" }, "require-dev": { diff --git a/library/Zend/Loader/ClassMapAutoloader.php b/library/Zend/Loader/ClassMapAutoloader.php index 4d848bf3f..a50e1fc0a 100644 --- a/library/Zend/Loader/ClassMapAutoloader.php +++ b/library/Zend/Loader/ClassMapAutoloader.php @@ -91,7 +91,7 @@ class ClassMapAutoloader implements SplAutoloader )); } - $this->map = array_merge($this->map, $map); + $this->map = $map + $this->map; if (isset($location)) { $this->mapsLoaded[] = $location; diff --git a/library/Zend/Loader/ModuleAutoloader.php b/library/Zend/Loader/ModuleAutoloader.php index 773f3dc7a..e867aae84 100644 --- a/library/Zend/Loader/ModuleAutoloader.php +++ b/library/Zend/Loader/ModuleAutoloader.php @@ -13,6 +13,8 @@ namespace Zend\Loader; require_once __DIR__ . '/SplAutoloader.php'; use GlobIterator; +use Phar; +use PharFileInfo; use SplFileInfo; use Traversable; @@ -33,6 +35,11 @@ class ModuleAutoloader implements SplAutoloader */ protected $namespacedPaths = array(); + /** + * @var string Will contain the absolute phar:// path to the executable when packaged as phar file + */ + protected $pharBasePath = ""; + /** * @var array An array of supported phar extensions (filled on constructor) */ @@ -53,6 +60,7 @@ class ModuleAutoloader implements SplAutoloader public function __construct($options = null) { if (extension_loaded('phar')) { + $this->pharBasePath = Phar::running(true); $this->pharExtensions = array( 'phar', 'phar.tar', @@ -185,7 +193,9 @@ class ModuleAutoloader implements SplAutoloader $path = $path . $moduleClassPath; if ($path == '.' || substr($path, 0, 2) == './' || substr($path, 0, 2) == '.\\') { - $basePath = realpath('.'); + if (!$basePath = $this->pharBasePath) { + $basePath = realpath('.'); + } if (false === $basePath) { $basePath = getcwd(); @@ -232,12 +242,19 @@ class ModuleAutoloader implements SplAutoloader */ protected function loadModuleFromDir($dirPath, $class) { - $file = new SplFileInfo($dirPath . '/Module.php'); - if ($file->isReadable() && $file->isFile()) { + $modulePath = $dirPath . '/Module.php'; + if (substr($modulePath, 0, 7) === 'phar://') { + $file = new PharFileInfo($modulePath); + } else { + $file = new SplFileInfo($modulePath); + } + + if (($file->isReadable() && $file->isFile())) { // Found directory with Module.php in it - require_once $file->getRealPath(); + $absModulePath = $this->pharBasePath ? (string) $file : $file->getRealPath(); + require_once $absModulePath; if (class_exists($class)) { - $this->moduleClassMap[$class] = $file->getRealPath(); + $this->moduleClassMap[$class] = $absModulePath; return $class; } } diff --git a/library/Zend/Loader/StandardAutoloader.php b/library/Zend/Loader/StandardAutoloader.php index 6e00908e5..2d744a88e 100644 --- a/library/Zend/Loader/StandardAutoloader.php +++ b/library/Zend/Loader/StandardAutoloader.php @@ -89,7 +89,7 @@ class StandardAutoloader implements SplAutoloader case self::AUTOREGISTER_ZF: if ($pairs) { $this->registerNamespace('Zend', dirname(__DIR__)); - $this->registerNamespace('ZendXml', dirname(dirname((__DIR__))) . '/ZendXml'); + $this->registerNamespace('ZendXml', dirname(dirname((__DIR__))) . DIRECTORY_SEPARATOR . 'ZendXml'); } break; case self::LOAD_NS: diff --git a/library/Zend/Loader/composer.json b/library/Zend/Loader/composer.json index c2cab6347..e34b4f9fb 100644 --- a/library/Zend/Loader/composer.json +++ b/library/Zend/Loader/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Loader\\": "" } }, - "target-dir": "Zend/Loader", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Log/Filter/Timestamp.php b/library/Zend/Log/Filter/Timestamp.php new file mode 100644 index 000000000..f611dd6b3 --- /dev/null +++ b/library/Zend/Log/Filter/Timestamp.php @@ -0,0 +1,126 @@ + + */ +class Timestamp implements FilterInterface +{ + /** + * DateTime instance or desired value based on $dateFormatChar. + * + * @var int|DateTime + */ + protected $value; + + /** + * PHP idate()-compliant format character. + * + * @var string|null + */ + protected $dateFormatChar; + + /** + * @var string + */ + protected $operator; + + /** + * @param int|DateTime|array|Traversable $value DateTime instance or desired value based on $dateFormatChar + * @param string $dateFormatChar PHP idate()-compliant format character + * @param string $operator Comparison operator + * @return Timestamp + * @throws Exception\InvalidArgumentException + */ + public function __construct($value, $dateFormatChar = null, $operator = '<=') + { + if ($value instanceof Traversable) { + $value = ArrayUtils::iteratorToArray($value); + } + + if (is_array($value)) { + $dateFormatChar = isset($value['dateFormatChar']) ? $value['dateFormatChar'] : null; + $operator = isset($value['operator']) ? $value['operator'] : null; + $value = isset($value['value']) ? $value['value'] : null; + } + + if ($value instanceof DateTime) { + $this->value = $value; + } else { + if (!is_int($value)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Value must be either DateTime instance or integer; received "%s"', + gettype($value) + )); + } + if (!is_string($dateFormatChar)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Date format character must be supplied as string; received "%s"', + gettype($dateFormatChar) + )); + } + + $this->value = $value; + $this->dateFormatChar = $dateFormatChar; + } + + if ($operator === null) { + $operator = '<='; + } elseif (!in_array( + $operator, + array('<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq', '!=', '<>') + )) { + throw new Exception\InvalidArgumentException( + "Unsupported comparison operator: '$operator'" + ); + } + + $this->operator = $operator; + } + + /** + * Returns TRUE if timestamp is accepted, otherwise FALSE is returned. + * + * @param array $event event data + * @return bool + */ + public function filter(array $event) + { + if (! isset($event['timestamp'])) { + return false; + } + + $datetime = $event['timestamp']; + + if (! ($datetime instanceof DateTime || is_int($datetime) || is_string($datetime))) { + return false; + } + + $timestamp = $datetime instanceof DateTime ? $datetime->getTimestamp() : (int) $datetime; + + if ($this->value instanceof DateTime) { + return version_compare($timestamp, $this->value->getTimestamp(), $this->operator); + } + + return version_compare( + idate($this->dateFormatChar, $timestamp), + $this->value, + $this->operator + ); + } +} diff --git a/library/Zend/Log/Formatter/Xml.php b/library/Zend/Log/Formatter/Xml.php index 00a6ec225..4e894bbab 100644 --- a/library/Zend/Log/Formatter/Xml.php +++ b/library/Zend/Log/Formatter/Xml.php @@ -160,10 +160,11 @@ class Xml implements FormatterInterface $event['timestamp'] = $event['timestamp']->format($this->getDateTimeFormat()); } - if ($this->elementMap === null) { - $dataToInsert = $event; - } else { + $dataToInsert = $event; + + if (null !== $this->elementMap) { $dataToInsert = array(); + foreach ($this->elementMap as $elementName => $fieldKey) { $dataToInsert[$elementName] = $event[$fieldKey]; } @@ -177,21 +178,78 @@ class Xml implements FormatterInterface foreach ($dataToInsert as $key => $value) { if (empty($value) || is_scalar($value) + || ((is_array($value) || $value instanceof Traversable) && $key == "extra") || (is_object($value) && method_exists($value, '__toString')) ) { if ($key == "message") { $value = $escaper->escapeHtml($value); - } elseif ($key == "extra" && empty($value)) { + } + + if ($key == "extra" && empty($value)) { continue; } + + if ($key == "extra" && (is_array($value) || $value instanceof Traversable)) { + $elt->appendChild($this->buildElementTree($dom, $dom->createElement('extra'), $value)); + + continue; + } + $elt->appendChild(new DOMElement($key, (string) $value)); } } - $xml = $dom->saveXML(); - $xml = preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $xml); + return preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $dom->saveXML()) . PHP_EOL; + } - return $xml . PHP_EOL; + /** + * Recursion function to create an xml tree structure out of array structure + * @param DomDocument $doc - DomDocument where the current nodes will be generated + * @param DomElement $rootElement - root element the tree will be attached to + * @param $mixedData array|Traversable - mixedData + * @return DomElement $domElement - DOM Element with appended child nodes + */ + protected function buildElementTree(DOMDocument $doc, DOMElement $rootElement, $mixedData) + { + if (! (is_array($mixedData) || $mixedData instanceof Traversable)) { + return $rootElement; + } + + foreach ($mixedData as $key => $value) { + // key is numeric and switch is not possible, numeric values are not valid node names + if ((empty($value) || is_numeric($value)) && is_numeric($key)) { + continue; + } + + if ($value instanceof Traversable || is_array($value)) { + // current value is an array, start recursion + $rootElement->appendChild($this->buildElementTree($doc, $doc->createElement($key), $value)); + + continue; + } + + if (is_object($value) && ! method_exists($value, '__toString')) { + // object does not support __toString() method, manually convert the value + $value = $this->getEscaper()->escapeHtml( + '"Object" of type ' . get_class($value) . " does not support __toString() method" + ); + } + + if (is_numeric($key)) { + // xml does not allow numeric values, try to switch the value and the key + $key = (string) $value; + $value = null; + } + + try { + $rootElement->appendChild(new DOMElement($key, empty($value) ? null : (string) $value)); + } catch (\DOMException $e) { + // the input name is not valid, go one. + continue; + } + } + + return $rootElement; } /** diff --git a/library/Zend/Log/Logger.php b/library/Zend/Log/Logger.php index 880738e15..21c09e6ea 100644 --- a/library/Zend/Log/Logger.php +++ b/library/Zend/Log/Logger.php @@ -49,6 +49,9 @@ class Logger implements LoggerInterface E_USER_ERROR => self::ERR, E_CORE_ERROR => self::ERR, E_RECOVERABLE_ERROR => self::ERR, + E_PARSE => self::ERR, + E_COMPILE_ERROR => self::ERR, + E_COMPILE_WARNING => self::ERR, E_STRICT => self::DEBUG, E_DEPRECATED => self::DEBUG, E_USER_DEPRECATED => self::DEBUG, @@ -416,7 +419,7 @@ class Logger implements LoggerInterface { if (!is_int($priority) || ($priority<0) || ($priority>=count($this->priorities))) { throw new Exception\InvalidArgumentException(sprintf( - '$priority must be an integer > 0 and < %d; received %s', + '$priority must be an integer >= 0 and < %d; received %s', count($this->priorities), var_export($priority, 1) )); @@ -613,19 +616,35 @@ class Logger implements LoggerInterface register_shutdown_function(function () use ($logger, $errorPriorityMap) { $error = error_get_last(); - if (null !== $error && $error['type'] === E_ERROR) { - $logger->log( - $errorPriorityMap[E_ERROR], - $error['message'], + + if (null === $error + || ! in_array( + $error['type'], array( - 'file' => $error['file'], - 'line' => $error['line'], - ) - ); + E_ERROR, + E_PARSE, + E_CORE_ERROR, + E_CORE_WARNING, + E_COMPILE_ERROR, + E_COMPILE_WARNING + ), + true + ) + ) { + return; } + + $logger->log($errorPriorityMap[$error['type']], + $error['message'], + array( + 'file' => $error['file'], + 'line' => $error['line'], + ) + ); }); static::$registeredFatalErrorShutdownFunction = true; + return true; } diff --git a/library/Zend/Log/Processor/ReferenceId.php b/library/Zend/Log/Processor/ReferenceId.php new file mode 100644 index 000000000..3507c8f40 --- /dev/null +++ b/library/Zend/Log/Processor/ReferenceId.php @@ -0,0 +1,59 @@ +getIdentifier(); + + return $event; + } + + /** + * Sets identifier. + * + * @param string $identifier + * @return self + */ + public function setReferenceId($identifier) + { + $this->identifier = $identifier; + + return $this; + } + + /** + * Returns identifier. + * + * @return string + */ + public function getReferenceId() + { + return $this->getIdentifier(); + } +} diff --git a/library/Zend/Log/Processor/RequestId.php b/library/Zend/Log/Processor/RequestId.php index 7614e8e9e..55f132111 100644 --- a/library/Zend/Log/Processor/RequestId.php +++ b/library/Zend/Log/Processor/RequestId.php @@ -21,7 +21,7 @@ class RequestId implements ProcessorInterface protected $identifier; /** - * Adds an identifier for the request to the log. + * Adds an identifier for the request to the log, unless one has already been set. * * This enables to filter the log for messages belonging to a specific request * @@ -30,6 +30,10 @@ class RequestId implements ProcessorInterface */ public function process(array $event) { + if (isset($event['extra']['requestId'])) { + return $event; + } + if (!isset($event['extra'])) { $event['extra'] = array(); } diff --git a/library/Zend/Log/ProcessorPluginManager.php b/library/Zend/Log/ProcessorPluginManager.php index 4164481ec..0e2cae2b7 100644 --- a/library/Zend/Log/ProcessorPluginManager.php +++ b/library/Zend/Log/ProcessorPluginManager.php @@ -20,6 +20,7 @@ class ProcessorPluginManager extends AbstractPluginManager */ protected $invokableClasses = array( 'backtrace' => 'Zend\Log\Processor\Backtrace', + 'referenceid' => 'Zend\Log\Processor\ReferenceId', 'requestid' => 'Zend\Log\Processor\RequestId', ); diff --git a/library/Zend/Log/Writer/AbstractWriter.php b/library/Zend/Log/Writer/AbstractWriter.php index b519e4cf8..f3ee13fc7 100644 --- a/library/Zend/Log/Writer/AbstractWriter.php +++ b/library/Zend/Log/Writer/AbstractWriter.php @@ -266,14 +266,12 @@ abstract class AbstractWriter implements WriterInterface } catch (\Exception $e) { if ($errorHandlerStarted) { ErrorHandler::stop(); - $errorHandlerStarted = false; } throw $e; } if ($errorHandlerStarted) { $error = ErrorHandler::stop(); - $errorHandlerStarted = false; if ($error) { throw new Exception\RuntimeException("Unable to write", 0, $error); } diff --git a/library/Zend/Log/Writer/Db.php b/library/Zend/Log/Writer/Db.php index 33ba0c94b..675708aa5 100644 --- a/library/Zend/Log/Writer/Db.php +++ b/library/Zend/Log/Writer/Db.php @@ -163,7 +163,12 @@ class Db extends AbstractWriter if (is_array($value)) { foreach ($value as $key => $subvalue) { if (isset($columnMap[$name][$key])) { - $data[$columnMap[$name][$key]] = $subvalue; + if (is_scalar($subvalue)) { + $data[$columnMap[$name][$key]] = $subvalue; + continue; + } + + $data[$columnMap[$name][$key]] = var_export($subvalue, true); } } } elseif (isset($columnMap[$name])) { @@ -189,7 +194,12 @@ class Db extends AbstractWriter foreach ($event as $name => $value) { if (is_array($value)) { foreach ($value as $key => $subvalue) { - $data[$name . $this->separator . $key] = $subvalue; + if (is_scalar($subvalue)) { + $data[$name . $this->separator . $key] = $subvalue; + continue; + } + + $data[$name . $this->separator . $key] = var_export($subvalue, true); } } else { $data[$name] = $value; diff --git a/library/Zend/Log/Writer/FirePhp.php b/library/Zend/Log/Writer/FirePhp.php index a04a9be4d..b57b343d6 100644 --- a/library/Zend/Log/Writer/FirePhp.php +++ b/library/Zend/Log/Writer/FirePhp.php @@ -14,7 +14,6 @@ use FirePHP as FirePHPService; use Zend\Log\Exception; use Zend\Log\Formatter\FirePhp as FirePhpFormatter; use Zend\Log\Logger; -use FirePhp\FirePhpInterface; class FirePhp extends AbstractWriter { @@ -42,7 +41,7 @@ class FirePhp extends AbstractWriter $instance = isset($instance['instance']) ? $instance['instance'] : null; } - if ($instance instanceof FirePhpInterface) { + if ($instance !== null && !($instance instanceof FirePhp\FirePhpInterface)) { throw new Exception\InvalidArgumentException('You must pass a valid FirePhp\FirePhpInterface'); } diff --git a/library/Zend/Log/Writer/FirePhp/FirePhpBridge.php b/library/Zend/Log/Writer/FirePhp/FirePhpBridge.php index 5c8db0e56..d55274840 100644 --- a/library/Zend/Log/Writer/FirePhp/FirePhpBridge.php +++ b/library/Zend/Log/Writer/FirePhp/FirePhpBridge.php @@ -53,34 +53,37 @@ class FirePhpBridge implements FirePhpInterface /** * Log an error message * - * @param string $line + * @param string $line + * @param string|null $label * @return void */ - public function error($line) + public function error($line, $label = null) { - return $this->firephp->error($line); + return $this->firephp->error($line, $label); } /** * Log a warning * - * @param string $line + * @param string $line + * @param string|null $label * @return void */ - public function warn($line) + public function warn($line, $label = null) { - return $this->firephp->warn($line); + return $this->firephp->warn($line, $label); } /** * Log informational message * - * @param string $line + * @param string $line + * @param string|null $label * @return void */ - public function info($line) + public function info($line, $label = null) { - return $this->firephp->info($line); + return $this->firephp->info($line, $label); } /** @@ -97,11 +100,12 @@ class FirePhpBridge implements FirePhpInterface /** * Log a message * - * @param string $line + * @param string $line + * @param string|null $label * @return void */ - public function log($line) + public function log($line, $label = null) { - return $this->firephp->trace($line); + return $this->firephp->trace($line, $label); } } diff --git a/library/Zend/Log/Writer/Mail.php b/library/Zend/Log/Writer/Mail.php index 056528ed3..f27a5bf22 100644 --- a/library/Zend/Log/Writer/Mail.php +++ b/library/Zend/Log/Writer/Mail.php @@ -13,6 +13,7 @@ use Traversable; use Zend\Log\Exception; use Zend\Log\Formatter\Simple as SimpleFormatter; use Zend\Mail\Message as MailMessage; +use Zend\Mail\MessageFactory as MailMessageFactory; use Zend\Mail\Transport; use Zend\Mail\Transport\Exception as TransportException; @@ -86,6 +87,9 @@ class Mail extends AbstractWriter } $transport = isset($mail['transport']) ? $mail['transport'] : null; $mail = isset($mail['mail']) ? $mail['mail'] : null; + if (is_array($mail)) { + $mail = MailMessageFactory::getInstance($mail); + } } // Ensure we have a valid mail message diff --git a/library/Zend/Log/Writer/Noop.php b/library/Zend/Log/Writer/Noop.php new file mode 100644 index 000000000..6a456baa9 --- /dev/null +++ b/library/Zend/Log/Writer/Noop.php @@ -0,0 +1,23 @@ + 'noop', + 'Zend\Log\Writer\Null' => 'noop', + ); + /** * Default set of writers * @@ -25,7 +30,7 @@ class WriterPluginManager extends AbstractPluginManager 'firephp' => 'Zend\Log\Writer\FirePhp', 'mail' => 'Zend\Log\Writer\Mail', 'mock' => 'Zend\Log\Writer\Mock', - 'null' => 'Zend\Log\Writer\Null', + 'noop' => 'Zend\Log\Writer\Noop', 'stream' => 'Zend\Log\Writer\Stream', 'syslog' => 'Zend\Log\Writer\Syslog', 'zendmonitor' => 'Zend\Log\Writer\ZendMonitor', diff --git a/library/Zend/Log/composer.json b/library/Zend/Log/composer.json index af6421947..ec27f288e 100644 --- a/library/Zend/Log/composer.json +++ b/library/Zend/Log/composer.json @@ -9,11 +9,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Log\\": "" } }, - "target-dir": "Zend/Log", "require": { "php": ">=5.3.23", "zendframework/zend-servicemanager": "self.version", diff --git a/library/Zend/Mail/AddressList.php b/library/Zend/Mail/AddressList.php index 751b65c89..60a34d618 100644 --- a/library/Zend/Mail/AddressList.php +++ b/library/Zend/Mail/AddressList.php @@ -79,6 +79,40 @@ class AddressList implements Countable, Iterator return $this; } + /** + * Add an address to the list from any valid string format, such as + * - "ZF Dev" + * - dev@zf.com + * + * @param string $address + * @throws Exception\InvalidArgumentException + * @return AddressList + */ + public function addFromString($address) + { + if (!preg_match('/^((?P.*?)<(?P[^>]+)>|(?P.+))$/', $address, $matches)) { + throw new Exception\InvalidArgumentException('Invalid address format'); + } + + $name = null; + if (isset($matches['name'])) { + $name = trim($matches['name']); + } + if (empty($name)) { + $name = null; + } + + if (isset($matches['namedEmail'])) { + $email = $matches['namedEmail']; + } + if (isset($matches['email'])) { + $email = $matches['email']; + } + $email = trim($email); + + return $this->add($email, $name); + } + /** * Merge another address list into this one * diff --git a/library/Zend/Mail/Header/AbstractAddressList.php b/library/Zend/Mail/Header/AbstractAddressList.php index 78587ea46..b76d04a80 100644 --- a/library/Zend/Mail/Header/AbstractAddressList.php +++ b/library/Zend/Mail/Header/AbstractAddressList.php @@ -57,7 +57,7 @@ abstract class AbstractAddressList implements HeaderInterface } // split value on "," $fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue); - $values = explode(',', $fieldValue); + $values = str_getcsv($fieldValue, ','); array_walk( $values, function (&$value) { @@ -67,29 +67,7 @@ abstract class AbstractAddressList implements HeaderInterface $addressList = $header->getAddressList(); foreach ($values as $address) { - // split values into name/email - if (!preg_match('/^((?P.*?)<(?P[^>]+)>|(?P.+))$/', $address, $matches)) { - // Should we raise an exception here? - continue; - } - $name = null; - if (isset($matches['name'])) { - $name = trim($matches['name']); - } - if (empty($name)) { - $name = null; - } - - if (isset($matches['namedEmail'])) { - $email = $matches['namedEmail']; - } - if (isset($matches['email'])) { - $email = $matches['email']; - } - $email = trim($email); // we may have leading whitespace - - // populate address list - $addressList->add($email, $name); + $addressList->addFromString($address); } return $header; } diff --git a/library/Zend/Mail/Header/ContentTransferEncoding.php b/library/Zend/Mail/Header/ContentTransferEncoding.php index 5d386f363..c97bfb459 100644 --- a/library/Zend/Mail/Header/ContentTransferEncoding.php +++ b/library/Zend/Mail/Header/ContentTransferEncoding.php @@ -21,9 +21,9 @@ class ContentTransferEncoding implements HeaderInterface '8bit', 'quoted-printable', 'base64', + 'binary', /* * not implemented: - * 'binary', * x-token: 'X-' */ ); diff --git a/library/Zend/Mail/Header/ContentType.php b/library/Zend/Mail/Header/ContentType.php index 5e72fbdc1..7d0788290 100644 --- a/library/Zend/Mail/Header/ContentType.php +++ b/library/Zend/Mail/Header/ContentType.php @@ -43,6 +43,8 @@ class ContentType implements HeaderInterface $header = new static(); $header->setType($type); + $values = array_filter($values); + if (count($values)) { foreach ($values as $keyValuePair) { list($key, $value) = explode('=', $keyValuePair, 2); @@ -156,7 +158,7 @@ class ContentType implements HeaderInterface if (isset($this->parameters[$name])) { return $this->parameters[$name]; } - return null; + return; } /** diff --git a/library/Zend/Mail/Headers.php b/library/Zend/Mail/Headers.php index 414168f38..e5b8ad495 100644 --- a/library/Zend/Mail/Headers.php +++ b/library/Zend/Mail/Headers.php @@ -70,15 +70,16 @@ class Headers implements Countable, Iterator // iterate the header lines, some might be continuations foreach (explode($EOL, $string) as $line) { // check if a header name is present - if (preg_match('/^(?P[\x21-\x39\x3B-\x7E]+):.*$/', $line, $matches)) { + if (preg_match('/^[\x21-\x39\x3B-\x7E]+:.*$/', $line)) { if ($currentLine) { // a header name was present, then store the current complete line $headers->addHeaderLine($currentLine); } $currentLine = trim($line); - } elseif (preg_match('/^\s+.*$/', $line, $matches)) { + } elseif (preg_match('/^\s+.*$/', $line)) { // continuation: append to current line - $currentLine .= trim($line); + // recover the whitespace that break the line (unfolding, rfc2822#section-2.2.3) + $currentLine .= ' ' . trim($line); } elseif (preg_match('/^\s*$/', $line)) { // empty line indicates end of headers break; @@ -250,8 +251,8 @@ class Headers implements Countable, Iterator if (!empty($indexes)) { foreach ($indexes as $index) { - unset ($this->headersKeys[$index]); - unset ($this->headers[$index]); + unset($this->headersKeys[$index]); + unset($this->headers[$index]); } return true; } diff --git a/library/Zend/Mail/Message.php b/library/Zend/Mail/Message.php index e1b999bb9..a1cfdbcb6 100644 --- a/library/Zend/Mail/Message.php +++ b/library/Zend/Mail/Message.php @@ -346,7 +346,7 @@ class Message { $headers = $this->getHeaders(); if (!$headers->has('subject')) { - return null; + return; } $header = $headers->get('subject'); return $header->getFieldValue(); diff --git a/library/Zend/Mail/MessageFactory.php b/library/Zend/Mail/MessageFactory.php new file mode 100644 index 000000000..9a9af88ac --- /dev/null +++ b/library/Zend/Mail/MessageFactory.php @@ -0,0 +1,65 @@ + $value) { + $setter = self::getSetterMethod($key); + if (method_exists($message, $setter)) { + $message->{$setter}($value); + } + } + + return $message; + } + + /** + * Generate a setter method name based on a provided key. + * + * @param string $key + * @return string + */ + private static function getSetterMethod($key) + { + return 'set' + . str_replace( + ' ', + '', + ucwords( + strtr( + $key, + array( + '-' => ' ', + '_' => ' ', + ) + ) + ) + ); + } +} diff --git a/library/Zend/Mail/Protocol/Imap.php b/library/Zend/Mail/Protocol/Imap.php index e7dd02453..c56ba948a 100644 --- a/library/Zend/Mail/Protocol/Imap.php +++ b/library/Zend/Mail/Protocol/Imap.php @@ -299,7 +299,7 @@ class Imap } elseif ($tokens[0] == 'NO') { return false; } - return null; + return; } /** @@ -658,7 +658,7 @@ class Imap $result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent); if ($silent) { - return $result ? true : false; + return (bool) $result; } $tokens = $result; @@ -751,6 +751,17 @@ class Imap return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true); } + /** + * subscribe to a folder + * + * @param string $folder folder name + * @return bool success + */ + public function subscribe($folder) + { + return $this->requestAndResponse('SUBSCRIBE', array($this->escapeString($folder)), true); + } + /** * permanently remove messages * diff --git a/library/Zend/Mail/Protocol/Smtp.php b/library/Zend/Mail/Protocol/Smtp.php index 8110f624e..2c67e111b 100644 --- a/library/Zend/Mail/Protocol/Smtp.php +++ b/library/Zend/Mail/Protocol/Smtp.php @@ -124,7 +124,6 @@ class Smtp extends AbstractProtocol default: throw new Exception\InvalidArgumentException($config['ssl'] . ' is unsupported SSL type'); - break; } } @@ -275,9 +274,7 @@ class Smtp extends AbstractProtocol $this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2 // Ensure newlines are CRLF (\r\n) - if (PHP_EOL === "\n") { - $data = str_replace("\n", "\r\n", str_replace("\r", '', $data)); - } + $data = str_replace("\n", "\r\n", str_replace("\r", '', $data)); foreach (explode(self::EOL, $data) as $line) { if (strpos($line, '.') === 0) { diff --git a/library/Zend/Mail/Storage.php b/library/Zend/Mail/Storage.php index 3c0b0df4e..934589c56 100644 --- a/library/Zend/Mail/Storage.php +++ b/library/Zend/Mail/Storage.php @@ -15,6 +15,7 @@ class Storage // system flags and other flags const FLAG_PASSED = 'Passed'; const FLAG_SEEN = '\Seen'; + const FLAG_UNSEEN = '\Unseen'; const FLAG_ANSWERED = '\Answered'; const FLAG_FLAGGED = '\Flagged'; const FLAG_DELETED = '\Deleted'; diff --git a/library/Zend/Mail/Storage/Imap.php b/library/Zend/Mail/Storage/Imap.php index 0bd2b2772..2eacf0663 100644 --- a/library/Zend/Mail/Storage/Imap.php +++ b/library/Zend/Mail/Storage/Imap.php @@ -36,6 +36,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W protected static $knownFlags = array('\Passed' => Mail\Storage::FLAG_PASSED, '\Answered' => Mail\Storage::FLAG_ANSWERED, '\Seen' => Mail\Storage::FLAG_SEEN, + '\Unseen' => Mail\Storage::FLAG_UNSEEN, '\Deleted' => Mail\Storage::FLAG_DELETED, '\Draft' => Mail\Storage::FLAG_DRAFT, '\Flagged' => Mail\Storage::FLAG_FLAGGED); @@ -47,6 +48,7 @@ class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\W protected static $searchFlags = array('\Recent' => 'RECENT', '\Answered' => 'ANSWERED', '\Seen' => 'SEEN', + '\Unseen' => 'UNSEEN', '\Deleted' => 'DELETED', '\Draft' => 'DRAFT', '\Flagged' => 'FLAGGED'); diff --git a/library/Zend/Mail/Storage/Mbox.php b/library/Zend/Mail/Storage/Mbox.php index 35113677c..e542b84de 100644 --- a/library/Zend/Mail/Storage/Mbox.php +++ b/library/Zend/Mail/Storage/Mbox.php @@ -43,6 +43,13 @@ class Mbox extends AbstractStorage */ protected $messageClass = '\Zend\Mail\Storage\Message\File'; + /** + * end of Line for messages + * + * @var string|null + */ + protected $messageEOL; + /** * Count messages all messages in current box * @@ -105,8 +112,18 @@ class Mbox extends AbstractStorage || is_subclass_of($this->messageClass, '\Zend\Mail\Storage\Message\File')) { // TODO top/body lines $messagePos = $this->getPos($id); - return new $this->messageClass(array('file' => $this->fh, 'startPos' => $messagePos['start'], - 'endPos' => $messagePos['end'])); + + $messageClassParams = array( + 'file' => $this->fh, + 'startPos' => $messagePos['start'], + 'endPos' => $messagePos['end'] + ); + + if (isset($this->messageEOL)) { + $messageClassParams['EOL'] = $this->messageEOL; + } + + return new $this->messageClass($messageClassParams); } $bodyLines = 0; // TODO: need a way to change that @@ -181,6 +198,10 @@ class Mbox extends AbstractStorage throw new Exception\InvalidArgumentException('no valid filename given in params'); } + if (isset($params->messageEOL)) { + $this->messageEOL = (string) $params->messageEOL; + } + $this->openMboxFile($params->filename); $this->has['top'] = true; $this->has['uniqueid'] = false; @@ -210,7 +231,7 @@ class Mbox extends AbstractStorage $result = false; - $line = fgets($file); + $line = fgets($file) ?: ''; if (strpos($line, 'From ') === 0) { $result = true; } diff --git a/library/Zend/Mail/Storage/Part/File.php b/library/Zend/Mail/Storage/Part/File.php index 2bf0d57a6..110205e0c 100644 --- a/library/Zend/Mail/Storage/Part/File.php +++ b/library/Zend/Mail/Storage/Part/File.php @@ -25,6 +25,7 @@ class File extends Part * - file filename or open file handler with message content (required) * - startPos start position of message or part in file (default: current position) * - endPos end position of message or part in file (default: end of file) + * - EOL end of Line for messages * * @param array $params full message with or without headers * @throws Exception\RuntimeException @@ -53,7 +54,11 @@ class File extends Part $header .= $line; } - $this->headers = Headers::fromString($header); + if (isset($params['EOL'])) { + $this->headers = Headers::fromString($header, $params['EOL']); + } else { + $this->headers = Headers::fromString($header); + } $this->contentPos[0] = ftell($this->fh); if ($endPos !== null) { diff --git a/library/Zend/Mail/Storage/Pop3.php b/library/Zend/Mail/Storage/Pop3.php index e1e49b1a0..53393bdfc 100644 --- a/library/Zend/Mail/Storage/Pop3.php +++ b/library/Zend/Mail/Storage/Pop3.php @@ -270,7 +270,7 @@ class Pop3 extends AbstractStorage } catch (MailException\ExceptionInterface $e) { // ignoring error } - $this->has['uniqueid'] = $id ? true : false; + $this->has['uniqueid'] = (bool) $id; return $this->has['uniqueid']; } diff --git a/library/Zend/Mail/Transport/Envelope.php b/library/Zend/Mail/Transport/Envelope.php new file mode 100644 index 000000000..eb6d917d0 --- /dev/null +++ b/library/Zend/Mail/Transport/Envelope.php @@ -0,0 +1,65 @@ +from; + } + + /** + * Set MAIL FROM + * + * @param string $from + */ + public function setFrom($from) + { + $this->from = (string) $from; + } + + /** + * Get RCPT TO + * + * @return string|null + */ + public function getTo() + { + return $this->to; + } + + /** + * Set RCPT TO + * + * @param string $to + */ + public function setTo($to) + { + $this->to = $to; + } +} diff --git a/library/Zend/Mail/Transport/Factory.php b/library/Zend/Mail/Transport/Factory.php index 63b69486a..8840de727 100644 --- a/library/Zend/Mail/Transport/Factory.php +++ b/library/Zend/Mail/Transport/Factory.php @@ -19,7 +19,9 @@ abstract class Factory */ protected static $classMap = array( 'file' => 'Zend\Mail\Transport\File', - 'null' => 'Zend\Mail\Transport\Null', + 'inmemory' => 'Zend\Mail\Transport\InMemory', + 'memory' => 'Zend\Mail\Transport\InMemory', + 'null' => 'Zend\Mail\Transport\InMemory', 'sendmail' => 'Zend\Mail\Transport\Sendmail', 'smtp' => 'Zend\Mail\Transport\Smtp', ); @@ -64,7 +66,8 @@ abstract class Factory if (! $transport instanceof TransportInterface) { throw new Exception\DomainException(sprintf( - '%s expects the "type" attribute to resolve to a valid Zend\Mail\Transport\TransportInterface instance; received "%s"', + '%s expects the "type" attribute to resolve to a valid' + . ' Zend\Mail\Transport\TransportInterface instance; received "%s"', __METHOD__, $type )); diff --git a/library/Zend/Mail/Transport/FileOptions.php b/library/Zend/Mail/Transport/FileOptions.php index 13d208c28..8ed862968 100644 --- a/library/Zend/Mail/Transport/FileOptions.php +++ b/library/Zend/Mail/Transport/FileOptions.php @@ -15,7 +15,7 @@ use Zend\Stdlib\AbstractOptions; class FileOptions extends AbstractOptions { /** - * @var string Local client hostname + * @var string Path to stored mail files */ protected $path; @@ -87,7 +87,7 @@ class FileOptions extends AbstractOptions public function getCallback() { if (null === $this->callback) { - $this->setCallback(function ($transport) { + $this->setCallback(function () { return 'ZendMail_' . time() . '_' . mt_rand() . '.eml'; }); } diff --git a/library/Zend/Mail/Transport/InMemory.php b/library/Zend/Mail/Transport/InMemory.php new file mode 100644 index 000000000..de088911c --- /dev/null +++ b/library/Zend/Mail/Transport/InMemory.php @@ -0,0 +1,47 @@ +lastMessage = $message; + } + + /** + * Get the last message sent. + * + * @return Message + */ + public function getLastMessage() + { + return $this->lastMessage; + } +} diff --git a/library/Zend/Mail/Transport/Null.php b/library/Zend/Mail/Transport/Null.php index 2abea75f4..29f474721 100644 --- a/library/Zend/Mail/Transport/Null.php +++ b/library/Zend/Mail/Transport/Null.php @@ -9,38 +9,27 @@ namespace Zend\Mail\Transport; -use Zend\Mail\Message; - /** - * File transport + * Stub class for backwards compatibility. * - * The null transport will just store the message in memory. It is helpful - * when unit testing. + * Since PHP 7 adds "null" as a reserved keyword, we can no longer have a class + * named that and retain PHP 7 compatibility. The original class has been + * renamed to "InMemory", and this class is now an extension of it. It raises an + * E_USER_DEPRECATED to warn users to migrate. + * + * @deprecated */ -class Null implements TransportInterface +class Null extends InMemory { - /** - * @var Message - */ - protected $lastMessage; - - /** - * Takes the last message and Saves it for testing - * - * @param Message $message - */ - public function send(Message $message) + public function __construct() { - $this->lastMessage = $message; - } - - /** - * Get the last message sent - * - * @return Message - */ - public function getLastMessage() - { - return $this->lastMessage; + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\InMemory', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); } } diff --git a/library/Zend/Mail/Transport/Sendmail.php b/library/Zend/Mail/Transport/Sendmail.php index aac12993a..d9e5460f9 100644 --- a/library/Zend/Mail/Transport/Sendmail.php +++ b/library/Zend/Mail/Transport/Sendmail.php @@ -184,7 +184,7 @@ class Sendmail implements TransportInterface { $headers = $message->getHeaders(); if (!$headers->has('subject')) { - return null; + return; } $header = $headers->get('subject'); return $header->getFieldValue(HeaderInterface::FORMAT_ENCODED); @@ -241,7 +241,7 @@ class Sendmail implements TransportInterface protected function prepareParameters(Mail\Message $message) { if ($this->isWindowsOs()) { - return null; + return; } $parameters = (string) $this->parameters; diff --git a/library/Zend/Mail/Transport/Smtp.php b/library/Zend/Mail/Transport/Smtp.php index 82bf3d1dc..30acad585 100644 --- a/library/Zend/Mail/Transport/Smtp.php +++ b/library/Zend/Mail/Transport/Smtp.php @@ -27,6 +27,11 @@ class Smtp implements TransportInterface */ protected $options; + /** + * @var Envelope|null + */ + protected $envelope; + /** * @var Protocol\Smtp */ @@ -77,6 +82,26 @@ class Smtp implements TransportInterface return $this->options; } + /** + * Set options + * + * @param Envelope $envelope + */ + public function setEnvelope(Envelope $envelope) + { + $this->envelope = $envelope; + } + + /** + * Get envelope + * + * @return Envelope|null + */ + public function getEnvelope() + { + return $this->envelope; + } + /** * Set plugin manager for obtaining SMTP protocol connection * @@ -244,13 +269,18 @@ class Smtp implements TransportInterface */ protected function prepareFromAddress(Message $message) { + if ($this->getEnvelope() && $this->getEnvelope()->getFrom()) { + return $this->getEnvelope()->getFrom(); + } + $sender = $message->getSender(); if ($sender instanceof Address\AddressInterface) { return $sender->getEmail(); } $from = $message->getFrom(); - if (!count($from)) { // Per RFC 2822 3.6 + if (!count($from)) { + // Per RFC 2822 3.6 throw new Exception\RuntimeException(sprintf( '%s transport expects either a Sender or at least one From address in the Message; none provided', __CLASS__ @@ -270,6 +300,10 @@ class Smtp implements TransportInterface */ protected function prepareRecipients(Message $message) { + if ($this->getEnvelope() && $this->getEnvelope()->getTo()) { + return (array) $this->getEnvelope()->getTo(); + } + $recipients = array(); foreach ($message->getTo() as $address) { $recipients[] = $address->getEmail(); @@ -280,6 +314,7 @@ class Smtp implements TransportInterface foreach ($message->getBcc() as $address) { $recipients[] = $address->getEmail(); } + $recipients = array_unique($recipients); return $recipients; } diff --git a/library/Zend/Mail/composer.json b/library/Zend/Mail/composer.json index 57b7f0836..069e8ba40 100644 --- a/library/Zend/Mail/composer.json +++ b/library/Zend/Mail/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Mail\\": "" } }, - "target-dir": "Zend/Mail", "require": { "php": ">=5.3.23", "zendframework/zend-crypt": "self.version", diff --git a/library/Zend/Math/BigInteger/Adapter/Bcmath.php b/library/Zend/Math/BigInteger/Adapter/Bcmath.php index 65c2fcf7f..62b686997 100644 --- a/library/Zend/Math/BigInteger/Adapter/Bcmath.php +++ b/library/Zend/Math/BigInteger/Adapter/Bcmath.php @@ -212,7 +212,7 @@ class Bcmath implements AdapterInterface public function intToBin($operand, $twoc = false) { $nb = chr(0); - $isNegative = (strpos($operand, '-') === 0) ? true : false; + $isNegative = (strpos($operand, '-') === 0); $operand = ltrim($operand, '+-0'); if (empty($operand)) { diff --git a/library/Zend/Math/BigInteger/Adapter/Gmp.php b/library/Zend/Math/BigInteger/Adapter/Gmp.php index 8084965d6..e29dc9c04 100644 --- a/library/Zend/Math/BigInteger/Adapter/Gmp.php +++ b/library/Zend/Math/BigInteger/Adapter/Gmp.php @@ -203,7 +203,7 @@ class Gmp implements AdapterInterface public function intToBin($int, $twoc = false) { $nb = chr(0); - $isNegative = (strpos($int, '-') === 0) ? true : false; + $isNegative = (strpos($int, '-') === 0); $int = ltrim($int, '+-0'); if (empty($int)) { diff --git a/library/Zend/Math/Rand.php b/library/Zend/Math/Rand.php index 0ab500f8a..7a2095c6d 100644 --- a/library/Zend/Math/Rand.php +++ b/library/Zend/Math/Rand.php @@ -54,7 +54,7 @@ abstract class Rand $checkAlternatives = (file_exists('/dev/urandom') && is_readable('/dev/urandom')) || class_exists('\\COM', false); if (true === $strong && false === $checkAlternatives) { - throw new Exception\RuntimeException ( + throw new Exception\RuntimeException( 'This PHP environment doesn\'t support secure random number generation. ' . 'Please consider installing the OpenSSL and/or Mcrypt extensions' ); diff --git a/library/Zend/Math/composer.json b/library/Zend/Math/composer.json index d818427e7..86343dcbe 100644 --- a/library/Zend/Math/composer.json +++ b/library/Zend/Math/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Math\\": "" } }, - "target-dir": "Zend/Math", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Memory/composer.json b/library/Zend/Memory/composer.json index 1dd9b8324..ae78a7bf2 100644 --- a/library/Zend/Memory/composer.json +++ b/library/Zend/Memory/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Memory\\": "" } }, - "target-dir": "Zend/Memory", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Mime/Decode.php b/library/Zend/Mime/Decode.php index 7fbdcfb81..db6d21075 100644 --- a/library/Zend/Mime/Decode.php +++ b/library/Zend/Mime/Decode.php @@ -73,7 +73,7 @@ class Decode { $parts = static::splitMime($message, $boundary); if (count($parts) <= 0) { - return null; + return; } $result = array(); $headers = null; // "Declare" variable before the first usage "for reading" @@ -188,7 +188,7 @@ class Decode } return substr($matches[2][$key], 1, -1); } - return null; + return; } $split = array(); diff --git a/library/Zend/Mime/Exception/InvalidArgumentException.php b/library/Zend/Mime/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..4da62c8d9 --- /dev/null +++ b/library/Zend/Mime/Exception/InvalidArgumentException.php @@ -0,0 +1,15 @@ +'); + $properties['id'] = trim($fieldValue, '<>'); break; case 'content-disposition': $properties['disposition'] = $fieldValue; diff --git a/library/Zend/Mime/Mime.php b/library/Zend/Mime/Mime.php index 862581eba..18e348ca2 100644 --- a/library/Zend/Mime/Mime.php +++ b/library/Zend/Mime/Mime.php @@ -188,7 +188,7 @@ class Mime while (strlen($str) > 0) { $currentLine = max(count($lines)-1, 0); $token = static::getNextQuotedPrintableToken($str); - $str = substr($str, strlen($token)); + $str = substr($str, strlen($token)) ?: ''; $tmp .= $token; if ($token == '=20') { diff --git a/library/Zend/Mime/Part.php b/library/Zend/Mime/Part.php index 0271d6f69..e15381ac2 100644 --- a/library/Zend/Mime/Part.php +++ b/library/Zend/Mime/Part.php @@ -34,9 +34,17 @@ class Part * as a string or stream * * @param mixed $content String or Stream containing the content + * @throws Exception\InvalidArgumentException */ - public function __construct($content) + public function __construct($content = '') { + if (! is_string($content) && ! is_resource($content)) { + throw new Exception\InvalidArgumentException(sprintf( + "'%s' must be string or resource", + $content + )); + } + $this->content = $content; if (is_resource($content)) { $this->isStream = true; @@ -44,11 +52,272 @@ class Part } /** - * @todo setters/getters * @todo error checking for setting $type * @todo error checking for setting $encoding */ + /** + * Set type + * @param string $type + * @return self + */ + public function setType($type = Mime::TYPE_OCTETSTREAM) + { + $this->type = $type; + return $this; + } + + /** + * Get type + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set encoding + * @param string $encoding + * @return self + */ + public function setEncoding($encoding = Mime::ENCODING_8BIT) + { + $this->encoding = $encoding; + return $this; + } + + /** + * Get encoding + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Set id + * @param string $id + * @return self + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Get id + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Set disposition + * @param string $disposition + * @return self + */ + public function setDisposition($disposition) + { + $this->disposition = $disposition; + return $this; + } + + /** + * Get disposition + * @return string + */ + public function getDisposition() + { + return $this->disposition; + } + + /** + * Set description + * @param string $description + * @return self + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Get description + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set filename + * @param string $fileName + * @return self + */ + public function setFileName($fileName) + { + $this->filename = $fileName; + return $this; + } + + /** + * Get filename + * @return string + */ + public function getFileName() + { + return $this->filename; + } + + /** + * Set charset + * @param string $type + * @return self + */ + public function setCharset($charset) + { + $this->charset = $charset; + return $this; + } + + /** + * Get charset + * @return string + */ + public function getCharset() + { + return $this->charset; + } + + /** + * Set boundary + * @param string $boundary + * @return self + */ + public function setBoundary($boundary) + { + $this->boundary = $boundary; + return $this; + } + + /** + * Get boundary + * @return string + */ + public function getBoundary() + { + return $this->boundary; + } + + /** + * Set location + * @param string $location + * @return self + */ + public function setLocation($location) + { + $this->location = $location; + return $this; + } + + /** + * Get location + * @return string + */ + public function getLocation() + { + return $this->location; + } + + /** + * Set language + * @param string $language + * @return self + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Get language + * @return string + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Set content + * @param mixed $content String or Stream containing the content + * @throws Exception\InvalidArgumentException + * @return self + */ + public function setContent($content) + { + if (! is_string($content) && ! is_resource($content)) { + throw new Exception\InvalidArgumentException( + "'%s' must be string or resource", + $content + ); + } + $this->content = $content; + if (is_resource($content)) { + $this->isStream = true; + } + + return $this; + } + + /** + * Set isStream + * @param bool $isStream + * @return self + */ + public function setIsStream($isStream = false) + { + $this->isStream = (bool) $isStream; + return $this; + } + + /** + * Get isStream + * @return bool + */ + public function getIsStream() + { + return $this->isStream; + } + + /** + * Set filters + * @param array $filters + * @return self + */ + public function setFilters($filters = array()) + { + $this->filters = $filters; + return $this; + } + + /** + * Get Filters + * @return array + */ + public function getFilters() + { + return $this->filters; + } + /** * check if this part can be read as a stream. * if true, getEncodedStream can be called, otherwise @@ -72,7 +341,7 @@ class Part */ public function getEncodedStream($EOL = Mime::LINEEND) { - if (!$this->isStream) { + if (! $this->isStream) { throw new Exception\RuntimeException('Attempt to get a stream from a string part'); } @@ -92,12 +361,12 @@ class Part ) ); $this->filters[Mime::ENCODING_QUOTEDPRINTABLE] = $filter; - if (!is_resource($filter)) { + if (! is_resource($filter)) { throw new Exception\RuntimeException('Failed to append quoted-printable filter'); } break; case Mime::ENCODING_BASE64: - if (array_key_exists(Mime::ENCODING_BASE64,$this->filters)) { + if (array_key_exists(Mime::ENCODING_BASE64, $this->filters)) { stream_filter_remove($this->filters[Mime::ENCODING_BASE64]); } $filter = stream_filter_append( @@ -110,7 +379,7 @@ class Part ) ); $this->filters[Mime::ENCODING_BASE64] = $filter; - if (!is_resource($filter)) { + if (! is_resource($filter)) { throw new Exception\RuntimeException('Failed to append base64 filter'); } break; diff --git a/library/Zend/Mime/composer.json b/library/Zend/Mime/composer.json index bbbe5fea4..10d1a709b 100644 --- a/library/Zend/Mime/composer.json +++ b/library/Zend/Mime/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Mime\\": "" } }, - "target-dir": "Zend/Mime", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/ModuleManager/Feature/TranslatorPluginProviderInterface.php b/library/Zend/ModuleManager/Feature/TranslatorPluginProviderInterface.php new file mode 100644 index 000000000..eaca51860 --- /dev/null +++ b/library/Zend/ModuleManager/Feature/TranslatorPluginProviderInterface.php @@ -0,0 +1,21 @@ +getCacheDir() . '/module-config-cache.' . $this->getConfigCacheKey().'.php'; + if ($this->getConfigCacheKey()) { + return $this->getCacheDir() . '/module-config-cache.' . $this->getConfigCacheKey().'.php'; + } + + return $this->getCacheDir() . '/module-config-cache.php'; } /** @@ -346,7 +350,11 @@ class ListenerOptions extends AbstractOptions */ public function getModuleMapCacheFile() { - return $this->getCacheDir() . '/module-classmap-cache.'.$this->getModuleMapCacheKey().'.php'; + if ($this->getModuleMapCacheKey()) { + return $this->getCacheDir() . '/module-classmap-cache.' . $this->getModuleMapCacheKey() . '.php'; + } + + return $this->getCacheDir() . '/module-classmap-cache.php'; } /** diff --git a/library/Zend/ModuleManager/Listener/ModuleResolverListener.php b/library/Zend/ModuleManager/Listener/ModuleResolverListener.php index bf8543f26..b058796bc 100644 --- a/library/Zend/ModuleManager/Listener/ModuleResolverListener.php +++ b/library/Zend/ModuleManager/Listener/ModuleResolverListener.php @@ -29,7 +29,6 @@ class ModuleResolverListener extends AbstractListener return false; } - $module = new $class; - return $module; + return new $class; } } diff --git a/library/Zend/ModuleManager/ModuleManager.php b/library/Zend/ModuleManager/ModuleManager.php index 7823052cf..4a4143fc2 100644 --- a/library/Zend/ModuleManager/ModuleManager.php +++ b/library/Zend/ModuleManager/ModuleManager.php @@ -225,7 +225,7 @@ class ModuleManager implements ModuleManagerInterface public function getModule($moduleName) { if (!isset($this->loadedModules[$moduleName])) { - return null; + return; } return $this->loadedModules[$moduleName]; } diff --git a/library/Zend/ModuleManager/composer.json b/library/Zend/ModuleManager/composer.json index 0e7bc7c5c..6c8ce16e7 100644 --- a/library/Zend/ModuleManager/composer.json +++ b/library/Zend/ModuleManager/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\ModuleManager\\": "" } }, - "target-dir": "Zend/ModuleManager", "require": { "php": ">=5.3.23", "zendframework/zend-eventmanager": "self.version", diff --git a/library/Zend/Mvc/Application.php b/library/Zend/Mvc/Application.php index d4d8f02ee..096b9cf8b 100644 --- a/library/Zend/Mvc/Application.php +++ b/library/Zend/Mvc/Application.php @@ -66,6 +66,7 @@ class Application implements protected $defaultListeners = array( 'RouteListener', 'DispatchListener', + 'HttpMethodListener', 'ViewManager', 'SendResponseListener', ); diff --git a/library/Zend/Mvc/Controller/AbstractActionController.php b/library/Zend/Mvc/Controller/AbstractActionController.php index f0cfb03fe..e604e308e 100644 --- a/library/Zend/Mvc/Controller/AbstractActionController.php +++ b/library/Zend/Mvc/Controller/AbstractActionController.php @@ -12,7 +12,6 @@ namespace Zend\Mvc\Controller; use Zend\Http\Response as HttpResponse; use Zend\Mvc\Exception; use Zend\Mvc\MvcEvent; -use Zend\View\Model\ConsoleModel; use Zend\View\Model\ViewModel; /** @@ -21,7 +20,7 @@ use Zend\View\Model\ViewModel; abstract class AbstractActionController extends AbstractController { /** - * @var string + * {@inheritDoc} */ protected $eventIdentifier = __CLASS__; @@ -88,30 +87,24 @@ abstract class AbstractActionController extends AbstractController } /** - * Create an HTTP view model representing a "not found" page + * @deprecated please use the {@see \Zend\Mvc\Controller\Plugin\CreateHttpNotFoundModel} plugin instead: this + * method will be removed in release 2.5 or later. * - * @param HttpResponse $response - * @return ViewModel + * {@inheritDoc} */ protected function createHttpNotFoundModel(HttpResponse $response) { - $response->setStatusCode(404); - return new ViewModel(array( - 'content' => 'Page not found', - )); + return $this->__call('createHttpNotFoundModel', array($response)); } /** - * Create a console view model representing a "not found" action + * @deprecated please use the {@see \Zend\Mvc\Controller\Plugin\CreateConsoleNotFoundModel} plugin instead: this + * method will be removed in release 2.5 or later. * - * @param \Zend\Stdlib\ResponseInterface $response - * @return ConsoleModel + * {@inheritDoc} */ protected function createConsoleNotFoundModel($response) { - $viewModel = new ConsoleModel(); - $viewModel->setErrorLevel(1); - $viewModel->setResult('Page not found'); - return $viewModel; + return $this->__call('createConsoleNotFoundModel', array($response)); } } diff --git a/library/Zend/Mvc/Controller/AbstractController.php b/library/Zend/Mvc/Controller/AbstractController.php index a3616d937..0a2cc03a0 100644 --- a/library/Zend/Mvc/Controller/AbstractController.php +++ b/library/Zend/Mvc/Controller/AbstractController.php @@ -29,8 +29,8 @@ use Zend\Stdlib\ResponseInterface as Response; * Convenience methods for pre-built plugins (@see __call): * * @method \Zend\View\Model\ModelInterface acceptableViewModelSelector(array $matchAgainst = null, bool $returnDefault = true, \Zend\Http\Header\Accept\FieldValuePart\AbstractFieldValuePart $resultReference = null) - * @method bool|array|\Zend\Http\Response fileprg(\Zend\Form\Form $form, $redirect = null, $redirectToUrl = false) - * @method bool|array|\Zend\Http\Response filePostRedirectGet(\Zend\Form\Form $form, $redirect = null, $redirectToUrl = false) + * @method bool|array|\Zend\Http\Response fileprg(\Zend\Form\FormInterface $form, $redirect = null, $redirectToUrl = false) + * @method bool|array|\Zend\Http\Response filePostRedirectGet(\Zend\Form\FormInterface $form, $redirect = null, $redirectToUrl = false) * @method \Zend\Mvc\Controller\Plugin\FlashMessenger flashMessenger() * @method \Zend\Mvc\Controller\Plugin\Forward forward() * @method mixed|null identity() @@ -40,6 +40,8 @@ use Zend\Stdlib\ResponseInterface as Response; * @method \Zend\Http\Response|array postRedirectGet(string $redirect = null, bool $redirectToUrl = false) * @method \Zend\Mvc\Controller\Plugin\Redirect redirect() * @method \Zend\Mvc\Controller\Plugin\Url url() + * @method \Zend\View\Model\ConsoleModel createConsoleNotFoundModel() + * @method \Zend\View\Model\ViewModel createHttpNotFoundModel() */ abstract class AbstractController implements Dispatchable, @@ -78,7 +80,7 @@ abstract class AbstractController implements protected $serviceLocator; /** - * @var string + * @var null|string|string[] */ protected $eventIdentifier; @@ -158,13 +160,19 @@ abstract class AbstractController implements */ public function setEventManager(EventManagerInterface $events) { - $events->setIdentifiers(array( - 'Zend\Stdlib\DispatchableInterface', - __CLASS__, - get_class($this), - $this->eventIdentifier, - substr(get_class($this), 0, strpos(get_class($this), '\\')) + $className = get_class($this); + + $nsPos = strpos($className, '\\') ?: 0; + $events->setIdentifiers(array_merge( + array( + __CLASS__, + $className, + substr($className, 0, $nsPos) + ), + array_values(class_implements($className)), + (array) $this->eventIdentifier )); + $this->events = $events; $this->attachDefaultListeners(); diff --git a/library/Zend/Mvc/Controller/AbstractRestfulController.php b/library/Zend/Mvc/Controller/AbstractRestfulController.php index 75850cb73..f763294bb 100644 --- a/library/Zend/Mvc/Controller/AbstractRestfulController.php +++ b/library/Zend/Mvc/Controller/AbstractRestfulController.php @@ -23,7 +23,7 @@ abstract class AbstractRestfulController extends AbstractController const CONTENT_TYPE_JSON = 'json'; /** - * @var string + * {@inheritDoc} */ protected $eventIdentifier = __CLASS__; @@ -116,7 +116,7 @@ abstract class AbstractRestfulController extends AbstractController * * @return mixed */ - public function deleteList() + public function deleteList($data) { $this->response->setStatusCode(405); @@ -347,6 +347,8 @@ abstract class AbstractRestfulController extends AbstractController // DELETE case 'delete': $id = $this->getIdentifier($routeMatch, $request); + $data = $this->processBodyContent($request); + if ($id !== false) { $action = 'delete'; $return = $this->delete($id); @@ -354,7 +356,7 @@ abstract class AbstractRestfulController extends AbstractController } $action = 'deleteList'; - $return = $this->deleteList(); + $return = $this->deleteList($data); break; // GET case 'get': diff --git a/library/Zend/Mvc/Controller/Plugin/AcceptableViewModelSelector.php b/library/Zend/Mvc/Controller/Plugin/AcceptableViewModelSelector.php index 582c45313..2049d8f07 100644 --- a/library/Zend/Mvc/Controller/Plugin/AcceptableViewModelSelector.php +++ b/library/Zend/Mvc/Controller/Plugin/AcceptableViewModelSelector.php @@ -134,7 +134,7 @@ class AcceptableViewModelSelector extends AbstractPlugin $headers = $request->getHeaders(); if ((!$matchAgainst && !$this->defaultMatchAgainst) || !$headers->has('accept')) { - return null; + return; } if (!$matchAgainst) { @@ -151,7 +151,7 @@ class AcceptableViewModelSelector extends AbstractPlugin /** @var $accept \Zend\Http\Header\Accept */ $accept = $headers->get('Accept'); if (($res = $accept->match($matchAgainstString)) === false) { - return null; + return; } return $res; diff --git a/library/Zend/Mvc/Controller/Plugin/CreateConsoleNotFoundModel.php b/library/Zend/Mvc/Controller/Plugin/CreateConsoleNotFoundModel.php new file mode 100644 index 000000000..9cc02a266 --- /dev/null +++ b/library/Zend/Mvc/Controller/Plugin/CreateConsoleNotFoundModel.php @@ -0,0 +1,30 @@ +setErrorLevel(1); + $viewModel->setResult('Page not found'); + + return $viewModel; + } +} diff --git a/library/Zend/Mvc/Controller/Plugin/CreateHttpNotFoundModel.php b/library/Zend/Mvc/Controller/Plugin/CreateHttpNotFoundModel.php new file mode 100644 index 000000000..c87b5c14c --- /dev/null +++ b/library/Zend/Mvc/Controller/Plugin/CreateHttpNotFoundModel.php @@ -0,0 +1,30 @@ +setStatusCode(404); + + return new ViewModel(array('content' => 'Page not found')); + } +} diff --git a/library/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php b/library/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php index df54816bc..48822b608 100644 --- a/library/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php +++ b/library/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php @@ -256,7 +256,7 @@ class FilePostRedirectGet extends AbstractPlugin return $value; } } - return null; + return; } ); } @@ -277,13 +277,13 @@ class FilePostRedirectGet extends AbstractPlugin $messages = $input->getMessages(); if (is_array($value) && $input instanceof FileInput && empty($messages)) { $rawValue = $input->getRawValue(); - if ( (isset($rawValue['error']) && $rawValue['error'] === UPLOAD_ERR_NO_FILE) + if ((isset($rawValue['error']) && $rawValue['error'] === UPLOAD_ERR_NO_FILE) || (isset($rawValue[0]['error']) && $rawValue[0]['error'] === UPLOAD_ERR_NO_FILE) ) { return $value; } } - return null; + return; } ); } diff --git a/library/Zend/Mvc/Controller/Plugin/FlashMessenger.php b/library/Zend/Mvc/Controller/Plugin/FlashMessenger.php index 9799119d9..02908123c 100644 --- a/library/Zend/Mvc/Controller/Plugin/FlashMessenger.php +++ b/library/Zend/Mvc/Controller/Plugin/FlashMessenger.php @@ -151,20 +151,25 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta * Add a message * * @param string $message + * @param null|string $namespace + * @param null|int $hops * @return FlashMessenger Provides a fluent interface */ - public function addMessage($message) + public function addMessage($message, $namespace = null, $hops = 1) { $container = $this->getContainer(); - $namespace = $this->getNamespace(); - if (!$this->messageAdded) { - $this->getMessagesFromContainer(); - $container->setExpirationHops(1, null); + if (null === $namespace) { + $namespace = $this->getNamespace(); } - if (!isset($container->{$namespace}) - || !($container->{$namespace} instanceof SplQueue) + if (! $this->messageAdded) { + $this->getMessagesFromContainer(); + $container->setExpirationHops($hops, null); + } + + if (! isset($container->{$namespace}) + || ! $container->{$namespace} instanceof SplQueue ) { $container->{$namespace} = new SplQueue(); } @@ -184,10 +189,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function addInfoMessage($message) { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_INFO); - $this->addMessage($message); - $this->setNamespace($namespace); + $this->addMessage($message, self::NAMESPACE_INFO); return $this; } @@ -200,10 +202,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function addSuccessMessage($message) { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_SUCCESS); - $this->addMessage($message); - $this->setNamespace($namespace); + $this->addMessage($message, self::NAMESPACE_SUCCESS); return $this; } @@ -216,10 +215,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function addWarningMessage($message) { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_WARNING); - $this->addMessage($message); - $this->setNamespace($namespace); + $this->addMessage($message, self::NAMESPACE_WARNING); return $this; } @@ -232,10 +228,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function addErrorMessage($message) { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_ERROR); - $this->addMessage($message); - $this->setNamespace($namespace); + $this->addMessage($message, self::NAMESPACE_ERROR); return $this; } @@ -243,13 +236,18 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta /** * Whether a specific namespace has messages * + * @param string $namespace * @return bool */ - public function hasMessages() + public function hasMessages($namespace = null) { + if (null === $namespace) { + $namespace = $this->getNamespace(); + } + $this->getMessagesFromContainer(); - return isset($this->messages[$this->getNamespace()]); + return isset($this->messages[$namespace]); } /** @@ -259,12 +257,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasInfoMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_INFO); - $hasMessages = $this->hasMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasMessages(self::NAMESPACE_INFO); } /** @@ -274,12 +267,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasSuccessMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_SUCCESS); - $hasMessages = $this->hasMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasMessages(self::NAMESPACE_SUCCESS); } /** @@ -289,12 +277,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasWarningMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_WARNING); - $hasMessages = $this->hasMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasMessages(self::NAMESPACE_WARNING); } /** @@ -304,23 +287,23 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasErrorMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_ERROR); - $hasMessages = $this->hasMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasMessages(self::NAMESPACE_ERROR); } /** * Get messages from a specific namespace * + * @param string $namespace * @return array */ - public function getMessages() + public function getMessages($namespace = null) { - if ($this->hasMessages()) { - return $this->messages[$this->getNamespace()]->toArray(); + if (null === $namespace) { + $namespace = $this->getNamespace(); + } + + if ($this->hasMessages($namespace)) { + return $this->messages[$namespace]->toArray(); } return array(); @@ -333,12 +316,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getInfoMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_INFO); - $messages = $this->getMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getMessages(self::NAMESPACE_INFO); } /** @@ -348,12 +326,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getSuccessMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_SUCCESS); - $messages = $this->getMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getMessages(self::NAMESPACE_SUCCESS); } /** @@ -363,12 +336,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getWarningMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_WARNING); - $messages = $this->getMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getMessages(self::NAMESPACE_WARNING); } /** @@ -378,23 +346,23 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getErrorMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_ERROR); - $messages = $this->getMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getMessages(self::NAMESPACE_ERROR); } /** * Clear all messages from the previous request & current namespace * + * @param string $namespace * @return bool True if messages were cleared, false if none existed */ - public function clearMessages() + public function clearMessages($namespace = null) { - if ($this->hasMessages()) { - unset($this->messages[$this->getNamespace()]); + if (null === $namespace) { + $namespace = $this->getNamespace(); + } + + if ($this->hasMessages($namespace)) { + unset($this->messages[$namespace]); return true; } @@ -410,12 +378,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function clearMessagesFromNamespace($namespaceToClear) { - $namespace = $this->getNamespace(); - $this->setNamespace($namespaceToClear); - $cleared = $this->clearMessages(); - $this->setNamespace($namespace); - - return $cleared; + return $this->clearMessages($namespaceToClear); } /** @@ -439,12 +402,15 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta * Check to see if messages have been added to the current * namespace within this request * + * @param string $namespace * @return bool */ - public function hasCurrentMessages() + public function hasCurrentMessages($namespace = null) { $container = $this->getContainer(); - $namespace = $this->getNamespace(); + if (null === $namespace) { + $namespace = $this->getNamespace(); + } return isset($container->{$namespace}); } @@ -457,12 +423,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasCurrentInfoMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_INFO); - $hasMessages = $this->hasCurrentMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasCurrentMessages(self::NAMESPACE_INFO); } /** @@ -473,12 +434,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasCurrentSuccessMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_SUCCESS); - $hasMessages = $this->hasCurrentMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasCurrentMessages(self::NAMESPACE_SUCCESS); } /** @@ -489,12 +445,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasCurrentWarningMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_WARNING); - $hasMessages = $this->hasCurrentMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasCurrentMessages(self::NAMESPACE_WARNING); } /** @@ -505,25 +456,24 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function hasCurrentErrorMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_ERROR); - $hasMessages = $this->hasCurrentMessages(); - $this->setNamespace($namespace); - - return $hasMessages; + return $this->hasCurrentMessages(self::NAMESPACE_ERROR); } /** * Get messages that have been added to the current * namespace within this request * + * @param string $namespace * @return array */ - public function getCurrentMessages() + public function getCurrentMessages($namespace = null) { - if ($this->hasCurrentMessages()) { - $container = $this->getContainer(); + if (null === $namespace) { $namespace = $this->getNamespace(); + } + + if ($this->hasCurrentMessages($namespace)) { + $container = $this->getContainer(); return $container->{$namespace}->toArray(); } @@ -539,12 +489,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getCurrentInfoMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_INFO); - $messages = $this->getCurrentMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getCurrentMessages(self::NAMESPACE_INFO); } /** @@ -555,12 +500,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getCurrentSuccessMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_SUCCESS); - $messages = $this->getCurrentMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getCurrentMessages(self::NAMESPACE_SUCCESS); } /** @@ -571,12 +511,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getCurrentWarningMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_WARNING); - $messages = $this->getCurrentMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getCurrentMessages(self::NAMESPACE_WARNING); } /** @@ -587,12 +522,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getCurrentErrorMessages() { - $namespace = $this->getNamespace(); - $this->setNamespace(self::NAMESPACE_ERROR); - $messages = $this->getCurrentMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getCurrentMessages(self::NAMESPACE_ERROR); } /** @@ -604,24 +534,23 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getCurrentMessagesFromNamespace($namespaceToGet) { - $namespace = $this->getNamespace(); - $this->setNamespace($namespaceToGet); - $messages = $this->getCurrentMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getCurrentMessages($namespaceToGet); } /** * Clear messages from the current request and current namespace * + * @param string $namespace * @return bool True if current messages were cleared, false if none existed. */ - public function clearCurrentMessages() + public function clearCurrentMessages($namespace = null) { - if ($this->hasCurrentMessages()) { - $container = $this->getContainer(); + if (null === $namespace) { $namespace = $this->getNamespace(); + } + + if ($this->hasCurrentMessages($namespace)) { + $container = $this->getContainer(); unset($container->{$namespace}); return true; @@ -638,12 +567,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function clearCurrentMessagesFromNamespace($namespaceToClear) { - $namespace = $this->getNamespace(); - $this->setNamespace($namespaceToClear); - $cleared = $this->clearCurrentMessages(); - $this->setNamespace($namespace); - - return $cleared; + return $this->clearCurrentMessages($namespaceToClear); } /** @@ -707,12 +631,7 @@ class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Counta */ public function getMessagesFromNamespace($namespaceToGet) { - $namespace = $this->getNamespace(); - $this->setNamespace($namespaceToGet); - $messages = $this->getMessages(); - $this->setNamespace($namespace); - - return $messages; + return $this->getMessages($namespaceToGet); } /** diff --git a/library/Zend/Mvc/Controller/Plugin/Forward.php b/library/Zend/Mvc/Controller/Plugin/Forward.php index 264ddb6c6..ec793b8f8 100644 --- a/library/Zend/Mvc/Controller/Plugin/Forward.php +++ b/library/Zend/Mvc/Controller/Plugin/Forward.php @@ -192,7 +192,7 @@ class Forward extends AbstractPlugin } foreach ($classArray as $class) { - if (is_a($currentCallback, $class)) { + if ($currentCallback instanceof $class) { $sharedEvents->detach($id, $currentEvent); $results[$id][$eventName][] = $currentEvent; } diff --git a/library/Zend/Mvc/Controller/Plugin/Identity.php b/library/Zend/Mvc/Controller/Plugin/Identity.php index 98618e6d5..a420b191a 100644 --- a/library/Zend/Mvc/Controller/Plugin/Identity.php +++ b/library/Zend/Mvc/Controller/Plugin/Identity.php @@ -9,7 +9,7 @@ namespace Zend\Mvc\Controller\Plugin; -use Zend\Authentication\AuthenticationService; +use Zend\Authentication\AuthenticationServiceInterface; use Zend\Mvc\Exception; /** @@ -18,12 +18,12 @@ use Zend\Mvc\Exception; class Identity extends AbstractPlugin { /** - * @var AuthenticationService + * @var AuthenticationServiceInterface */ protected $authenticationService; /** - * @return AuthenticationService + * @return AuthenticationServiceInterface */ public function getAuthenticationService() { @@ -31,9 +31,9 @@ class Identity extends AbstractPlugin } /** - * @param AuthenticationService $authenticationService + * @param AuthenticationServiceInterface $authenticationService */ - public function setAuthenticationService(AuthenticationService $authenticationService) + public function setAuthenticationService(AuthenticationServiceInterface $authenticationService) { $this->authenticationService = $authenticationService; } @@ -48,11 +48,11 @@ class Identity extends AbstractPlugin */ public function __invoke() { - if (!$this->authenticationService instanceof AuthenticationService) { - throw new Exception\RuntimeException('No AuthenticationService instance provided'); + if (!$this->authenticationService instanceof AuthenticationServiceInterface) { + throw new Exception\RuntimeException('No AuthenticationServiceInterface instance provided'); } if (!$this->authenticationService->hasIdentity()) { - return null; + return; } return $this->authenticationService->getIdentity(); } diff --git a/library/Zend/Mvc/Controller/PluginManager.php b/library/Zend/Mvc/Controller/PluginManager.php index 6d96cf096..35d101ca8 100644 --- a/library/Zend/Mvc/Controller/PluginManager.php +++ b/library/Zend/Mvc/Controller/PluginManager.php @@ -45,6 +45,8 @@ class PluginManager extends AbstractPluginManager 'postredirectget' => 'Zend\Mvc\Controller\Plugin\PostRedirectGet', 'redirect' => 'Zend\Mvc\Controller\Plugin\Redirect', 'url' => 'Zend\Mvc\Controller\Plugin\Url', + 'createhttpnotfoundmodel' => 'Zend\Mvc\Controller\Plugin\CreateHttpNotFoundModel', + 'createconsolenotfoundmodel' => 'Zend\Mvc\Controller\Plugin\CreateConsoleNotFoundModel', ); /** diff --git a/library/Zend/Mvc/DispatchListener.php b/library/Zend/Mvc/DispatchListener.php index a27562422..63b1a39fb 100644 --- a/library/Zend/Mvc/DispatchListener.php +++ b/library/Zend/Mvc/DispatchListener.php @@ -10,8 +10,8 @@ namespace Zend\Mvc; use ArrayObject; +use Zend\EventManager\AbstractListenerAggregate; use Zend\EventManager\EventManagerInterface; -use Zend\EventManager\ListenerAggregateInterface; use Zend\Mvc\Exception\InvalidControllerException; use Zend\Stdlib\ArrayUtils; @@ -37,13 +37,8 @@ use Zend\Stdlib\ArrayUtils; * The return value of dispatching the controller is placed into the result * property of the MvcEvent, and returned. */ -class DispatchListener implements ListenerAggregateInterface +class DispatchListener extends AbstractListenerAggregate { - /** - * @var \Zend\Stdlib\CallbackHandler[] - */ - protected $listeners = array(); - /** * Attach listeners to an event manager * @@ -58,21 +53,6 @@ class DispatchListener implements ListenerAggregateInterface } } - /** - * Detach listeners from an event manager - * - * @param EventManagerInterface $events - * @return void - */ - public function detach(EventManagerInterface $events) - { - foreach ($this->listeners as $index => $listener) { - if ($events->detach($listener)) { - unset($this->listeners[$index]); - } - } - } - /** * Listen to the "dispatch" event * diff --git a/library/Zend/Mvc/HttpMethodListener.php b/library/Zend/Mvc/HttpMethodListener.php new file mode 100644 index 000000000..0ba698434 --- /dev/null +++ b/library/Zend/Mvc/HttpMethodListener.php @@ -0,0 +1,127 @@ +setEnabled($enabled); + + if (! empty($allowedMethods)) { + $this->setAllowedMethods($allowedMethods); + } + } + + /** + * {@inheritdoc} + */ + public function attach(EventManagerInterface $events) + { + if (! $this->isEnabled()) { + return; + } + + $this->listeners[] = $events->attach( + MvcEvent::EVENT_ROUTE, + array($this, 'onRoute'), + 10000 + ); + } + + /** + * @param MvcEvent $e + * @return void|HttpResponse + */ + public function onRoute(MvcEvent $e) + { + $request = $e->getRequest(); + $response = $e->getResponse(); + + if (! $request instanceof HttpRequest || ! $response instanceof HttpResponse) { + return; + } + + $method = $request->getMethod(); + + if (in_array($method, $this->getAllowedMethods())) { + return; + } + + $response->setStatusCode(405); + + return $response; + } + + /** + * @return array + */ + public function getAllowedMethods() + { + return $this->allowedMethods; + } + + /** + * @param array $allowedMethods + */ + public function setAllowedMethods(array $allowedMethods) + { + foreach ($allowedMethods as &$value) { + $value = strtoupper($value); + } + $this->allowedMethods = $allowedMethods; + } + + /** + * @return bool + */ + public function isEnabled() + { + return $this->enabled; + } + + /** + * @param bool $enabled + */ + public function setEnabled($enabled) + { + $this->enabled = (bool) $enabled; + } +} diff --git a/library/Zend/Mvc/ModuleRouteListener.php b/library/Zend/Mvc/ModuleRouteListener.php index 659645ea9..e55a85a4b 100644 --- a/library/Zend/Mvc/ModuleRouteListener.php +++ b/library/Zend/Mvc/ModuleRouteListener.php @@ -9,19 +9,14 @@ namespace Zend\Mvc; +use Zend\EventManager\AbstractListenerAggregate; use Zend\EventManager\EventManagerInterface; -use Zend\EventManager\ListenerAggregateInterface; -class ModuleRouteListener implements ListenerAggregateInterface +class ModuleRouteListener extends AbstractListenerAggregate { const MODULE_NAMESPACE = '__NAMESPACE__'; const ORIGINAL_CONTROLLER = '__CONTROLLER__'; - /** - * @var \Zend\Stdlib\CallbackHandler[] - */ - protected $listeners = array(); - /** * Attach to an event manager * @@ -33,21 +28,6 @@ class ModuleRouteListener implements ListenerAggregateInterface $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, array($this, 'onRoute'), $priority); } - /** - * Detach all our listeners from the event manager - * - * @param EventManagerInterface $events - * @return void - */ - public function detach(EventManagerInterface $events) - { - foreach ($this->listeners as $index => $listener) { - if ($events->detach($listener)) { - unset($this->listeners[$index]); - } - } - } - /** * Listen to the "route" event and determine if the module namespace should * be prepended to the controller name. diff --git a/library/Zend/Mvc/ResponseSender/ConsoleResponseSender.php b/library/Zend/Mvc/ResponseSender/ConsoleResponseSender.php index 0ed967738..4aaa39841 100644 --- a/library/Zend/Mvc/ResponseSender/ConsoleResponseSender.php +++ b/library/Zend/Mvc/ResponseSender/ConsoleResponseSender.php @@ -43,7 +43,7 @@ class ConsoleResponseSender implements ResponseSenderInterface } $this->sendContent($event); - $errorLevel = (int) $response->getMetadata('errorLevel',0); + $errorLevel = (int) $response->getMetadata('errorLevel', 0); $event->stopPropagation(true); exit($errorLevel); } diff --git a/library/Zend/Mvc/RouteListener.php b/library/Zend/Mvc/RouteListener.php index 646925d0c..e86878ecb 100644 --- a/library/Zend/Mvc/RouteListener.php +++ b/library/Zend/Mvc/RouteListener.php @@ -9,16 +9,11 @@ namespace Zend\Mvc; +use Zend\EventManager\AbstractListenerAggregate; use Zend\EventManager\EventManagerInterface; -use Zend\EventManager\ListenerAggregateInterface; -class RouteListener implements ListenerAggregateInterface +class RouteListener extends AbstractListenerAggregate { - /** - * @var \Zend\Stdlib\CallbackHandler[] - */ - protected $listeners = array(); - /** * Attach to an event manager * @@ -30,21 +25,6 @@ class RouteListener implements ListenerAggregateInterface $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, array($this, 'onRoute')); } - /** - * Detach all our listeners from the event manager - * - * @param EventManagerInterface $events - * @return void - */ - public function detach(EventManagerInterface $events) - { - foreach ($this->listeners as $index => $listener) { - if ($events->detach($listener)) { - unset($this->listeners[$index]); - } - } - } - /** * Listen to the "route" event and attempt to route the request * diff --git a/library/Zend/Mvc/Router/Console/Catchall.php b/library/Zend/Mvc/Router/Console/Catchall.php index 8f796c465..def9e0eea 100644 --- a/library/Zend/Mvc/Router/Console/Catchall.php +++ b/library/Zend/Mvc/Router/Console/Catchall.php @@ -98,7 +98,7 @@ class Catchall implements RouteInterface public function match(Request $request) { if (!$request instanceof ConsoleRequest) { - return null; + return; } return new RouteMatch($this->defaults); diff --git a/library/Zend/Mvc/Router/Console/Simple.php b/library/Zend/Mvc/Router/Console/Simple.php index 18fb6945b..7367bc226 100644 --- a/library/Zend/Mvc/Router/Console/Simple.php +++ b/library/Zend/Mvc/Router/Console/Simple.php @@ -133,7 +133,7 @@ class Simple implements RouteInterface public function match(Request $request, $pathOffset = null) { if (!$request instanceof ConsoleRequest) { - return null; + return; } $params = $request->getParams()->toArray(); @@ -142,7 +142,7 @@ class Simple implements RouteInterface if (null !== $matches) { return new RouteMatch($matches); } - return null; + return; } /** diff --git a/library/Zend/Mvc/Router/Http/Chain.php b/library/Zend/Mvc/Router/Http/Chain.php index a4f337334..32e206138 100644 --- a/library/Zend/Mvc/Router/Http/Chain.php +++ b/library/Zend/Mvc/Router/Http/Chain.php @@ -102,7 +102,7 @@ class Chain extends TreeRouteStack implements RouteInterface public function match(Request $request, $pathOffset = null, array $options = array()) { if (!method_exists($request, 'getUri')) { - return null; + return; } if ($pathOffset === null) { @@ -125,7 +125,7 @@ class Chain extends TreeRouteStack implements RouteInterface $subMatch = $route->match($request, $pathOffset, $options); if ($subMatch === null) { - return null; + return; } $match->merge($subMatch); @@ -133,7 +133,7 @@ class Chain extends TreeRouteStack implements RouteInterface } if ($mustTerminate && $pathOffset !== $pathLength) { - return null; + return; } return $match; @@ -156,11 +156,13 @@ class Chain extends TreeRouteStack implements RouteInterface $this->assembledParams = array(); - end($this->routes); - $lastRouteKey = key($this->routes); + $routes = ArrayUtils::iteratorToArray($this->routes); + + end($routes); + $lastRouteKey = key($routes); $path = ''; - foreach ($this->routes as $key => $route) { + foreach ($routes as $key => $route) { $chainOptions = $options; $hasChild = isset($options['has_child']) ? $options['has_child'] : false; diff --git a/library/Zend/Mvc/Router/Http/Hostname.php b/library/Zend/Mvc/Router/Http/Hostname.php index dab4da843..03b24baf0 100644 --- a/library/Zend/Mvc/Router/Http/Hostname.php +++ b/library/Zend/Mvc/Router/Http/Hostname.php @@ -115,7 +115,9 @@ class Hostname implements RouteInterface $level = 0; while ($currentPos < $length) { - preg_match('(\G(?P[a-z0-9-.]*)(?P[:{\[\]]|$))', $def, $matches, 0, $currentPos); + if (!preg_match('(\G(?P[a-z0-9-.]*)(?P[:{\[\]]|$))', $def, $matches, 0, $currentPos)) { + throw new Exception\RuntimeException('Matched hostname literal contains a disallowed character'); + } $currentPos += strlen($matches[0]); @@ -266,7 +268,7 @@ class Hostname implements RouteInterface public function match(Request $request) { if (!method_exists($request, 'getUri')) { - return null; + return; } $uri = $request->getUri(); @@ -275,7 +277,7 @@ class Hostname implements RouteInterface $result = preg_match('(^' . $this->regex . '$)', $host, $matches); if (!$result) { - return null; + return; } $params = array(); diff --git a/library/Zend/Mvc/Router/Http/Literal.php b/library/Zend/Mvc/Router/Http/Literal.php index 2cab258d7..83087f16b 100644 --- a/library/Zend/Mvc/Router/Http/Literal.php +++ b/library/Zend/Mvc/Router/Http/Literal.php @@ -83,7 +83,7 @@ class Literal implements RouteInterface public function match(Request $request, $pathOffset = null) { if (!method_exists($request, 'getUri')) { - return null; + return; } $uri = $request->getUri(); @@ -96,14 +96,14 @@ class Literal implements RouteInterface } } - return null; + return; } if ($path === $this->route) { return new RouteMatch($this->defaults, strlen($this->route)); } - return null; + return; } /** diff --git a/library/Zend/Mvc/Router/Http/Method.php b/library/Zend/Mvc/Router/Http/Method.php index 40694893f..c3b04cf95 100644 --- a/library/Zend/Mvc/Router/Http/Method.php +++ b/library/Zend/Mvc/Router/Http/Method.php @@ -82,7 +82,7 @@ class Method implements RouteInterface public function match(Request $request) { if (!method_exists($request, 'getMethod')) { - return null; + return; } $requestVerb = strtoupper($request->getMethod()); @@ -93,7 +93,7 @@ class Method implements RouteInterface return new RouteMatch($this->defaults); } - return null; + return; } /** diff --git a/library/Zend/Mvc/Router/Http/Part.php b/library/Zend/Mvc/Router/Http/Part.php index bbe92f916..21ddef6da 100644 --- a/library/Zend/Mvc/Router/Http/Part.php +++ b/library/Zend/Mvc/Router/Http/Part.php @@ -169,7 +169,7 @@ class Part extends TreeRouteStack implements RouteInterface } } - return null; + return; } /** diff --git a/library/Zend/Mvc/Router/Http/Regex.php b/library/Zend/Mvc/Router/Http/Regex.php index fe3e77c20..c7ce161cb 100644 --- a/library/Zend/Mvc/Router/Http/Regex.php +++ b/library/Zend/Mvc/Router/Http/Regex.php @@ -104,7 +104,7 @@ class Regex implements RouteInterface public function match(Request $request, $pathOffset = null) { if (!method_exists($request, 'getUri')) { - return null; + return; } $uri = $request->getUri(); @@ -117,7 +117,7 @@ class Regex implements RouteInterface } if (!$result) { - return null; + return; } $matchedLength = strlen($matches[0]); diff --git a/library/Zend/Mvc/Router/Http/Scheme.php b/library/Zend/Mvc/Router/Http/Scheme.php index 5ca68af8e..aefd3b0b4 100644 --- a/library/Zend/Mvc/Router/Http/Scheme.php +++ b/library/Zend/Mvc/Router/Http/Scheme.php @@ -82,14 +82,14 @@ class Scheme implements RouteInterface public function match(Request $request) { if (!method_exists($request, 'getUri')) { - return null; + return; } $uri = $request->getUri(); $scheme = $uri->getScheme(); if ($scheme !== $this->scheme) { - return null; + return; } return new RouteMatch($this->defaults); diff --git a/library/Zend/Mvc/Router/Http/Segment.php b/library/Zend/Mvc/Router/Http/Segment.php index dc8be858c..cd152ac7f 100644 --- a/library/Zend/Mvc/Router/Http/Segment.php +++ b/library/Zend/Mvc/Router/Http/Segment.php @@ -344,7 +344,7 @@ class Segment implements RouteInterface public function match(Request $request, $pathOffset = null, array $options = array()) { if (!method_exists($request, 'getUri')) { - return null; + return; } $uri = $request->getUri(); @@ -373,7 +373,7 @@ class Segment implements RouteInterface } if (!$result) { - return null; + return; } $matchedLength = strlen($matches[0]); diff --git a/library/Zend/Mvc/Router/Http/TreeRouteStack.php b/library/Zend/Mvc/Router/Http/TreeRouteStack.php index 091be6974..1742210d3 100644 --- a/library/Zend/Mvc/Router/Http/TreeRouteStack.php +++ b/library/Zend/Mvc/Router/Http/TreeRouteStack.php @@ -235,7 +235,7 @@ class TreeRouteStack extends SimpleRouteStack return $this->prototypes[$name]; } - return null; + return; } /** @@ -250,7 +250,7 @@ class TreeRouteStack extends SimpleRouteStack public function match(Request $request, $pathOffset = null, array $options = array()) { if (!method_exists($request, 'getUri')) { - return null; + return; } if ($this->baseUrl === null && method_exists($request, 'getBaseUrl')) { @@ -291,7 +291,7 @@ class TreeRouteStack extends SimpleRouteStack } } - return null; + return; } /** @@ -371,9 +371,21 @@ class TreeRouteStack extends SimpleRouteStack $uri->setScheme($this->requestUri->getScheme()); } - return $uri->setPath($path)->normalize()->toString(); + $uri->setPath($path); + + if (!isset($options['normalize_path']) || $options['normalize_path']) { + $uri->normalize(); + } + + return $uri->toString(); } elseif (!$uri->isAbsolute() && $uri->isValidRelative()) { - return $uri->setPath($path)->normalize()->toString(); + $uri->setPath($path); + + if (!isset($options['normalize_path']) || $options['normalize_path']) { + $uri->normalize(); + } + + return $uri->toString(); } return $path; diff --git a/library/Zend/Mvc/Router/Http/Wildcard.php b/library/Zend/Mvc/Router/Http/Wildcard.php index 871f91f2d..5580dfd42 100644 --- a/library/Zend/Mvc/Router/Http/Wildcard.php +++ b/library/Zend/Mvc/Router/Http/Wildcard.php @@ -74,7 +74,10 @@ class Wildcard implements RouteInterface if ($options instanceof Traversable) { $options = ArrayUtils::iteratorToArray($options); } elseif (!is_array($options)) { - throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options'); + throw new Exception\InvalidArgumentException(sprintf( + '%s expects an array or Traversable set of options', + __METHOD__ + )); } if (!isset($options['key_value_delimiter'])) { @@ -103,25 +106,25 @@ class Wildcard implements RouteInterface public function match(Request $request, $pathOffset = null) { if (!method_exists($request, 'getUri')) { - return null; + return; } $uri = $request->getUri(); - $path = $uri->getPath(); + $path = $uri->getPath() ?: ''; if ($path === '/') { $path = ''; } if ($pathOffset !== null) { - $path = substr($path, $pathOffset); + $path = substr($path, $pathOffset) ?: ''; } $matches = array(); $params = explode($this->paramDelimiter, $path); if (count($params) > 1 && ($params[0] !== '' || end($params) === '')) { - return null; + return; } if ($this->keyValueDelimiter === $this->paramDelimiter) { diff --git a/library/Zend/Mvc/Router/SimpleRouteStack.php b/library/Zend/Mvc/Router/SimpleRouteStack.php index f8652f172..361386043 100644 --- a/library/Zend/Mvc/Router/SimpleRouteStack.php +++ b/library/Zend/Mvc/Router/SimpleRouteStack.php @@ -303,7 +303,7 @@ class SimpleRouteStack implements RouteStackInterface } } - return null; + return; } /** diff --git a/library/Zend/Mvc/SendResponseListener.php b/library/Zend/Mvc/SendResponseListener.php index 380d03998..147261404 100644 --- a/library/Zend/Mvc/SendResponseListener.php +++ b/library/Zend/Mvc/SendResponseListener.php @@ -9,10 +9,10 @@ namespace Zend\Mvc; +use Zend\EventManager\AbstractListenerAggregate; use Zend\EventManager\EventManager; use Zend\EventManager\EventManagerAwareInterface; use Zend\EventManager\EventManagerInterface; -use Zend\EventManager\ListenerAggregateInterface; use Zend\Mvc\ResponseSender\ConsoleResponseSender; use Zend\Mvc\ResponseSender\HttpResponseSender; use Zend\Mvc\ResponseSender\PhpEnvironmentResponseSender; @@ -20,15 +20,9 @@ use Zend\Mvc\ResponseSender\SendResponseEvent; use Zend\Mvc\ResponseSender\SimpleStreamResponseSender; use Zend\Stdlib\ResponseInterface as Response; -class SendResponseListener implements - EventManagerAwareInterface, - ListenerAggregateInterface +class SendResponseListener extends AbstractListenerAggregate implements + EventManagerAwareInterface { - /** - * @var \Zend\Stdlib\CallbackHandler[] - */ - protected $listeners = array(); - /** * @var SendResponseEvent */ @@ -82,21 +76,6 @@ class SendResponseListener implements $this->listeners[] = $events->attach(MvcEvent::EVENT_FINISH, array($this, 'sendResponse'), -10000); } - /** - * Detach aggregate listeners from the specified event manager - * - * @param EventManagerInterface $events - * @return void - */ - public function detach(EventManagerInterface $events) - { - foreach ($this->listeners as $index => $listener) { - if ($events->detach($listener)) { - unset($this->listeners[$index]); - } - } - } - /** * Send the response * diff --git a/library/Zend/Mvc/Service/FormAnnotationBuilderFactory.php b/library/Zend/Mvc/Service/FormAnnotationBuilderFactory.php new file mode 100644 index 000000000..873b68a39 --- /dev/null +++ b/library/Zend/Mvc/Service/FormAnnotationBuilderFactory.php @@ -0,0 +1,61 @@ +get('FormElementManager'); + $formElementManager->injectFactory($annotationBuilder); + + $config = $serviceLocator->get('Config'); + if (isset($config['form_annotation_builder'])) { + $config = $config['form_annotation_builder']; + + if (isset($config['annotations'])) { + foreach ((array) $config['annotations'] as $fullyQualifiedClassName) { + $annotationBuilder->getAnnotationParser()->registerAnnotation($fullyQualifiedClassName); + } + } + + if (isset($config['listeners'])) { + foreach ((array) $config['listeners'] as $listenerName) { + $listener = $serviceLocator->get($listenerName); + if (!($listener instanceof ListenerAggregateInterface)) { + throw new RuntimeException(sprintf('Invalid event listener (%s) provided', $listenerName)); + } + $listener->attach($annotationBuilder->getEventManager()); + } + } + + if (isset($config['preserve_defined_order'])) { + $annotationBuilder->setPreserveDefinedOrder($config['preserve_defined_order']); + } + } + + return $annotationBuilder; + } +} diff --git a/library/Zend/Mvc/Service/HttpMethodListenerFactory.php b/library/Zend/Mvc/Service/HttpMethodListenerFactory.php new file mode 100644 index 000000000..46ea25eeb --- /dev/null +++ b/library/Zend/Mvc/Service/HttpMethodListenerFactory.php @@ -0,0 +1,40 @@ +get('config'); + + if (! isset($config['http_methods_listener'])) { + return new HttpMethodListener(); + } + + $listenerConfig = $config['http_methods_listener']; + $enabled = array_key_exists('enabled', $listenerConfig) + ? $listenerConfig['enabled'] + : true; + $allowedMethods = (isset($listenerConfig['allowed_methods']) && is_array($listenerConfig['allowed_methods'])) + ? $listenerConfig['allowed_methods'] + : null; + + return new HttpMethodListener($enabled, $allowedMethods); + } +} diff --git a/library/Zend/Mvc/Service/InjectTemplateListenerFactory.php b/library/Zend/Mvc/Service/InjectTemplateListenerFactory.php new file mode 100644 index 000000000..e0bac2e1f --- /dev/null +++ b/library/Zend/Mvc/Service/InjectTemplateListenerFactory.php @@ -0,0 +1,38 @@ +get('Config'); + + if (isset($config['view_manager']['controller_map']) + && (is_array($config['view_manager']['controller_map'])) + ) { + $listener->setControllerMap($config['view_manager']['controller_map']); + } + + return $listener; + } +} diff --git a/library/Zend/Mvc/Service/ModuleManagerFactory.php b/library/Zend/Mvc/Service/ModuleManagerFactory.php index 2532658c2..ae2bd4d5c 100644 --- a/library/Zend/Mvc/Service/ModuleManagerFactory.php +++ b/library/Zend/Mvc/Service/ModuleManagerFactory.php @@ -121,6 +121,12 @@ class ModuleManagerFactory implements FactoryInterface 'Zend\ModuleManager\Feature\LogWriterProviderInterface', 'getLogWriterConfig' ); + $serviceListener->addServiceManager( + 'TranslatorPluginManager', + 'translator_plugins', + 'Zend\ModuleManager\Feature\TranslatorPluginProviderInterface', + 'getTranslatorPluginConfig' + ); $events = $serviceLocator->get('EventManager'); $events->attach($defaultListeners); diff --git a/library/Zend/Mvc/Service/ServiceListenerFactory.php b/library/Zend/Mvc/Service/ServiceListenerFactory.php index 2d3acb46c..0bf1ea095 100644 --- a/library/Zend/Mvc/Service/ServiceListenerFactory.php +++ b/library/Zend/Mvc/Service/ServiceListenerFactory.php @@ -37,7 +37,9 @@ class ServiceListenerFactory implements FactoryInterface 'invokables' => array( 'DispatchListener' => 'Zend\Mvc\DispatchListener', 'RouteListener' => 'Zend\Mvc\RouteListener', - 'SendResponseListener' => 'Zend\Mvc\SendResponseListener' + 'SendResponseListener' => 'Zend\Mvc\SendResponseListener', + 'ViewJsonRenderer' => 'Zend\View\Renderer\JsonRenderer', + 'ViewFeedRenderer' => 'Zend\View\Renderer\FeedRenderer', ), 'factories' => array( 'Application' => 'Zend\Mvc\Service\ApplicationFactory', @@ -52,10 +54,13 @@ class ServiceListenerFactory implements FactoryInterface 'DiServiceInitializer' => 'Zend\Mvc\Service\DiServiceInitializerFactory', 'DiStrictAbstractServiceFactory' => 'Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory', 'FilterManager' => 'Zend\Mvc\Service\FilterManagerFactory', + 'FormAnnotationBuilder' => 'Zend\Mvc\Service\FormAnnotationBuilderFactory', 'FormElementManager' => 'Zend\Mvc\Service\FormElementManagerFactory', 'HttpRouter' => 'Zend\Mvc\Service\RouterFactory', + 'HttpMethodListener' => 'Zend\Mvc\Service\HttpMethodListenerFactory', 'HttpViewManager' => 'Zend\Mvc\Service\HttpViewManagerFactory', 'HydratorManager' => 'Zend\Mvc\Service\HydratorManagerFactory', + 'InjectTemplateListener' => 'Zend\Mvc\Service\InjectTemplateListenerFactory', 'InputFilterManager' => 'Zend\Mvc\Service\InputFilterManagerFactory', 'LogProcessorManager' => 'Zend\Mvc\Service\LogProcessorManagerFactory', 'LogWriterManager' => 'Zend\Mvc\Service\LogWriterManagerFactory', @@ -66,28 +71,30 @@ class ServiceListenerFactory implements FactoryInterface 'Router' => 'Zend\Mvc\Service\RouterFactory', 'RoutePluginManager' => 'Zend\Mvc\Service\RoutePluginManagerFactory', 'SerializerAdapterManager' => 'Zend\Mvc\Service\SerializerAdapterPluginManagerFactory', + 'TranslatorPluginManager' => 'Zend\Mvc\Service\TranslatorPluginManagerFactory', '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', + 'ViewPrefixPathStackResolver' => 'Zend\Mvc\Service\ViewPrefixPathStackResolverFactory', ), 'aliases' => array( - 'Configuration' => 'Config', - 'Console' => 'ConsoleAdapter', - 'Di' => 'DependencyInjector', - 'Zend\Di\LocatorInterface' => 'DependencyInjector', - 'Zend\Mvc\Controller\PluginManager' => 'ControllerPluginManager', - 'Zend\View\Resolver\TemplateMapResolver' => 'ViewTemplateMapResolver', - 'Zend\View\Resolver\TemplatePathStack' => 'ViewTemplatePathStack', - 'Zend\View\Resolver\AggregateResolver' => 'ViewResolver', - 'Zend\View\Resolver\ResolverInterface' => 'ViewResolver', - 'ControllerManager' => 'ControllerLoader' + 'Configuration' => 'Config', + 'Console' => 'ConsoleAdapter', + 'Di' => 'DependencyInjector', + 'Zend\Di\LocatorInterface' => 'DependencyInjector', + 'Zend\Form\Annotation\FormAnnotationBuilder' => 'FormAnnotationBuilder', + 'Zend\Mvc\Controller\PluginManager' => 'ControllerPluginManager', + 'Zend\Mvc\View\Http\InjectTemplateListener' => 'InjectTemplateListener', + 'Zend\View\Resolver\TemplateMapResolver' => 'ViewTemplateMapResolver', + 'Zend\View\Resolver\TemplatePathStack' => 'ViewTemplatePathStack', + 'Zend\View\Resolver\AggregateResolver' => 'ViewResolver', + 'Zend\View\Resolver\ResolverInterface' => 'ViewResolver', + 'ControllerManager' => 'ControllerLoader', ), 'abstract_factories' => array( 'Zend\Form\FormAbstractServiceFactory', diff --git a/library/Zend/Mvc/Service/TranslatorPluginManagerFactory.php b/library/Zend/Mvc/Service/TranslatorPluginManagerFactory.php new file mode 100644 index 000000000..2dee23cb1 --- /dev/null +++ b/library/Zend/Mvc/Service/TranslatorPluginManagerFactory.php @@ -0,0 +1,15 @@ +setPluginManager($serviceLocator->get('TranslatorPluginManager')); $serviceLocator->setService('Zend\I18n\Translator\TranslatorInterface', $i18nTranslator); return new MvcTranslator($i18nTranslator); } diff --git a/library/Zend/Mvc/Service/ViewHelperManagerFactory.php b/library/Zend/Mvc/Service/ViewHelperManagerFactory.php index 969fca2f5..cb2054115 100644 --- a/library/Zend/Mvc/Service/ViewHelperManagerFactory.php +++ b/library/Zend/Mvc/Service/ViewHelperManagerFactory.php @@ -80,13 +80,26 @@ class ViewHelperManagerFactory extends AbstractPluginManagerFactory $plugins->setFactory('basepath', function () use ($serviceLocator) { $config = $serviceLocator->has('Config') ? $serviceLocator->get('Config') : array(); $basePathHelper = new ViewHelper\BasePath; + + if (Console::isConsole() + && isset($config['view_manager']) + && isset($config['view_manager']['base_path_console']) + ) { + $basePathHelper->setBasePath($config['view_manager']['base_path_console']); + + return $basePathHelper; + } + if (isset($config['view_manager']) && isset($config['view_manager']['base_path'])) { $basePathHelper->setBasePath($config['view_manager']['base_path']); - } else { - $request = $serviceLocator->get('Request'); - if (is_callable(array($request, 'getBasePath'))) { - $basePathHelper->setBasePath($request->getBasePath()); - } + + return $basePathHelper; + } + + $request = $serviceLocator->get('Request'); + + if (is_callable(array($request, 'getBasePath'))) { + $basePathHelper->setBasePath($request->getBasePath()); } return $basePathHelper; diff --git a/library/Zend/Mvc/Service/ViewJsonRendererFactory.php b/library/Zend/Mvc/Service/ViewJsonRendererFactory.php deleted file mode 100644 index d1c4ee446..000000000 --- a/library/Zend/Mvc/Service/ViewJsonRendererFactory.php +++ /dev/null @@ -1,29 +0,0 @@ -get('Config'); + $prefixes = array(); + + if (isset($config['view_manager']['prefix_template_path_stack'])) { + $prefixes = $config['view_manager']['prefix_template_path_stack']; + } + + return new PrefixPathStackResolver($prefixes); + } +} diff --git a/library/Zend/Mvc/Service/ViewResolverFactory.php b/library/Zend/Mvc/Service/ViewResolverFactory.php index fdb8f1e2f..e57e6c392 100644 --- a/library/Zend/Mvc/Service/ViewResolverFactory.php +++ b/library/Zend/Mvc/Service/ViewResolverFactory.php @@ -21,14 +21,28 @@ class ViewResolverFactory implements FactoryInterface * Creates a Zend\View\Resolver\AggregateResolver and attaches the template * map resolver and path stack resolver * - * @param ServiceLocatorInterface $serviceLocator + * @param ServiceLocatorInterface $serviceLocator * @return ViewResolver\AggregateResolver */ public function createService(ServiceLocatorInterface $serviceLocator) { $resolver = new ViewResolver\AggregateResolver(); - $resolver->attach($serviceLocator->get('ViewTemplateMapResolver')); - $resolver->attach($serviceLocator->get('ViewTemplatePathStack')); + + /* @var $mapResolver \Zend\View\Resolver\ResolverInterface */ + $mapResolver = $serviceLocator->get('ViewTemplateMapResolver'); + /* @var $pathResolver \Zend\View\Resolver\ResolverInterface */ + $pathResolver = $serviceLocator->get('ViewTemplatePathStack'); + /* @var $prefixPathStackResolver \Zend\View\Resolver\ResolverInterface */ + $prefixPathStackResolver = $serviceLocator->get('ViewPrefixPathStackResolver'); + + $resolver + ->attach($mapResolver) + ->attach($pathResolver) + ->attach($prefixPathStackResolver) + ->attach(new ViewResolver\RelativeFallbackResolver($mapResolver)) + ->attach(new ViewResolver\RelativeFallbackResolver($pathResolver)) + ->attach(new ViewResolver\RelativeFallbackResolver($prefixPathStackResolver)); + return $resolver; } } diff --git a/library/Zend/Mvc/View/Console/ExceptionStrategy.php b/library/Zend/Mvc/View/Console/ExceptionStrategy.php index f4f21ff51..360684a3d 100644 --- a/library/Zend/Mvc/View/Console/ExceptionStrategy.php +++ b/library/Zend/Mvc/View/Console/ExceptionStrategy.php @@ -196,7 +196,8 @@ EOT; ':file', ':line', ':stack', - ),array( + ), + array( get_class($previousException), $previousException->getMessage(), $previousException->getCode(), @@ -219,7 +220,7 @@ EOT; ':line', ':stack', ':previous', - ),array( + ), array( get_class($exception), $exception->getMessage(), $exception->getCode(), @@ -240,7 +241,7 @@ EOT; ':line', ':stack', ':previous', - ),array( + ), array( '', '', '', diff --git a/library/Zend/Mvc/View/Console/ViewManager.php b/library/Zend/Mvc/View/Console/ViewManager.php index 2fabf2513..0d0b23107 100644 --- a/library/Zend/Mvc/View/Console/ViewManager.php +++ b/library/Zend/Mvc/View/Console/ViewManager.php @@ -25,20 +25,16 @@ class ViewManager extends BaseViewManager * algorithms, as well as to ensure we pick up the Console variants * of several listeners and strategies. * - * @param $event + * @param \Zend\Mvc\MvcEvent $event * @return void */ public function onBootstrap($event) { - $application = $event->getApplication(); - $services = $application->getServiceManager(); - $config = $services->get('Config'); - $events = $application->getEventManager(); - $sharedEvents = $events->getSharedManager(); - - $this->config = isset($config['view_manager']) && (is_array($config['view_manager']) || $config['view_manager'] instanceof ArrayAccess) - ? $config['view_manager'] - : array(); + $application = $event->getApplication(); + $services = $application->getServiceManager(); + $events = $application->getEventManager(); + $sharedEvents = $events->getSharedManager(); + $this->config = $this->loadConfig($services->get('Config')); $this->services = $services; $this->event = $event; @@ -148,4 +144,27 @@ class ViewManager extends BaseViewManager return $this->routeNotFoundStrategy; } + + /** + * Extract view manager configuration from the application's configuration + * + * @param array|ArrayAccess $configService + * + * @return array + */ + private function loadConfig($configService) + { + $config = array(); + + // override when console config is provided, otherwise use the standard definition + if (isset($configService['console']['view_manager'])) { + $config = $configService['console']['view_manager']; + } elseif (isset($configService['view_manager'])) { + $config = $configService['view_manager']; + } + + return ($config instanceof ArrayAccess || is_array($config)) + ? $config + : array(); + } } diff --git a/library/Zend/Mvc/View/Http/InjectTemplateListener.php b/library/Zend/Mvc/View/Http/InjectTemplateListener.php index 1decc4c38..644a07417 100644 --- a/library/Zend/Mvc/View/Http/InjectTemplateListener.php +++ b/library/Zend/Mvc/View/Http/InjectTemplateListener.php @@ -32,6 +32,13 @@ class InjectTemplateListener extends AbstractListenerAggregate */ protected $controllerMap = array(); + /** + * Flag to force the use of the route match controller param + * + * @var boolean + */ + protected $preferRouteMatchController = false; + /** * {@inheritDoc} */ @@ -66,8 +73,10 @@ class InjectTemplateListener extends AbstractListenerAggregate if (is_object($controller)) { $controller = get_class($controller); } - if (!$controller) { - $controller = $routeMatch->getParam('controller', ''); + + $routeMatchController = $routeMatch->getParam('controller', ''); + if (!$controller || ($this->preferRouteMatchController && $routeMatchController)) { + $controller = $routeMatchController; } $template = $this->mapController($controller); @@ -122,6 +131,10 @@ class InjectTemplateListener extends AbstractListenerAggregate */ public function mapController($controller) { + if (! is_string($controller)) { + return false; + } + foreach ($this->controllerMap as $namespace => $replacement) { if ( // Allow disabling rule by setting value to false since config @@ -137,7 +150,7 @@ class InjectTemplateListener extends AbstractListenerAggregate // Map namespace to $replacement if its value is string if (is_string($replacement)) { $map = rtrim($replacement, '/') . '/'; - $controller = substr($controller, strlen($namespace) + 1); + $controller = substr($controller, strlen($namespace) + 1) ?: ''; } //strip Controller namespace(s) (but not classname) @@ -227,4 +240,23 @@ class InjectTemplateListener extends AbstractListenerAggregate return $controller; } + + /** + * Sets the flag to instruct the listener to prefer the route match controller param + * over the class name + * + * @param boolean $preferRouteMatchController + */ + public function setPreferRouteMatchController($preferRouteMatchController) + { + $this->preferRouteMatchController = (bool) $preferRouteMatchController; + } + + /** + * @return boolean + */ + public function isPreferRouteMatchController() + { + return $this->preferRouteMatchController; + } } diff --git a/library/Zend/Mvc/View/Http/ViewManager.php b/library/Zend/Mvc/View/Http/ViewManager.php index 3216d0256..d6c85583b 100644 --- a/library/Zend/Mvc/View/Http/ViewManager.php +++ b/library/Zend/Mvc/View/Http/ViewManager.php @@ -332,11 +332,7 @@ class ViewManager extends AbstractListenerAggregate public function getInjectTemplateListener() { - $listener = new InjectTemplateListener(); - if (isset($this->config['controller_map'])) { - $listener->setControllerMap($this->config['controller_map']); - } - return $listener; + return $this->services->get('Zend\Mvc\View\Http\InjectTemplateListener'); } /** diff --git a/library/Zend/Mvc/composer.json b/library/Zend/Mvc/composer.json index 68483df13..aa4c3e746 100644 --- a/library/Zend/Mvc/composer.json +++ b/library/Zend/Mvc/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Mvc\\": "" } }, - "target-dir": "Zend/Mvc", "require": { "php": ">=5.3.23", "zendframework/zend-eventmanager": "self.version", diff --git a/library/Zend/Navigation/AbstractContainer.php b/library/Zend/Navigation/AbstractContainer.php index 718c85556..596ee22b1 100644 --- a/library/Zend/Navigation/AbstractContainer.php +++ b/library/Zend/Navigation/AbstractContainer.php @@ -303,7 +303,7 @@ abstract class AbstractContainer implements Countable, RecursiveIterator } } - return null; + return; } /** @@ -502,7 +502,7 @@ abstract class AbstractContainer implements Countable, RecursiveIterator return $this->pages[$hash]; } - return null; + return; } // Countable interface: diff --git a/library/Zend/Navigation/Page/AbstractPage.php b/library/Zend/Navigation/Page/AbstractPage.php index f178d26db..ca784d6f4 100644 --- a/library/Zend/Navigation/Page/AbstractPage.php +++ b/library/Zend/Navigation/Page/AbstractPage.php @@ -1001,7 +1001,7 @@ abstract class AbstractPage extends AbstractContainer return $this->properties[$property]; } - return null; + return; } // Magic overloads: diff --git a/library/Zend/Navigation/Service/AbstractNavigationFactory.php b/library/Zend/Navigation/Service/AbstractNavigationFactory.php index 650b603c3..08fc8aece 100644 --- a/library/Zend/Navigation/Service/AbstractNavigationFactory.php +++ b/library/Zend/Navigation/Service/AbstractNavigationFactory.php @@ -73,6 +73,7 @@ abstract class AbstractNavigationFactory implements FactoryInterface /** * @param ServiceLocatorInterface $serviceLocator * @param array|\Zend\Config\Config $pages + * @return null|array * @throws \Zend\Navigation\Exception\InvalidArgumentException */ protected function preparePages(ServiceLocatorInterface $serviceLocator, $pages) @@ -122,10 +123,14 @@ abstract class AbstractNavigationFactory implements FactoryInterface * @param RouteMatch $routeMatch * @param Router $router * @param null|Request $request - * @return mixed + * @return array */ - protected function injectComponents(array $pages, RouteMatch $routeMatch = null, Router $router = null, $request = null) - { + protected function injectComponents( + array $pages, + RouteMatch $routeMatch = null, + Router $router = null, + $request = null + ) { foreach ($pages as &$page) { $hasUri = isset($page['uri']); $hasMvc = isset($page['action']) || isset($page['controller']) || isset($page['route']); diff --git a/library/Zend/Navigation/Service/NavigationAbstractServiceFactory.php b/library/Zend/Navigation/Service/NavigationAbstractServiceFactory.php new file mode 100644 index 000000000..23849f26d --- /dev/null +++ b/library/Zend/Navigation/Service/NavigationAbstractServiceFactory.php @@ -0,0 +1,122 @@ +get('Zend\Navigation\Special') to retrieve a navigation instance with this configuration. + */ +final class NavigationAbstractServiceFactory implements AbstractFactoryInterface +{ + /** + * Top-level configuration key indicating navigation configuration + * + * @var string + */ + const CONFIG_KEY = 'navigation'; + + /** + * Service manager factory prefix + * + * @var string + */ + const SERVICE_PREFIX = 'Zend\Navigation\\'; + + /** + * Normalized name prefix + */ + const NAME_PREFIX = 'zendnavigation'; + + /** + * Navigation configuration + * + * @var array + */ + protected $config; + + /** + * Can we create a navigation by the requested name? + * + * @param ServiceLocatorInterface $serviceLocator + * @param string $name Service name (as resolved by ServiceManager) + * @param string $requestedName Name by which service was requested, must start with Zend\Navigation\ + * @return bool + */ + public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) + { + if (0 !== strpos($name, self::NAME_PREFIX)) { + return false; + } + $config = $this->getConfig($serviceLocator); + + return (!empty($config[$this->getConfigName($name)])); + } + + /** + * Create a navigation container + * + * @param ServiceLocatorInterface $serviceLocator + * @param string $name Service name (as resolved by ServiceManager) + * @param string $requestedName Name by which service was requested + * @return Navigation + */ + public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) + { + $config = $this->getConfig($serviceLocator); + $factory = new ConstructedNavigationFactory($config[$this->getConfigName($name)]); + return $factory->createService($serviceLocator); + } + + /** + * Get navigation configuration, if any + * + * @param ServiceLocatorInterface $services + * @return array + */ + protected function getConfig(ServiceLocatorInterface $services) + { + if ($this->config !== null) { + return $this->config; + } + + if (!$services->has('Config')) { + $this->config = array(); + return $this->config; + } + + $config = $services->get('Config'); + if (!isset($config[self::CONFIG_KEY]) + || !is_array($config[self::CONFIG_KEY]) + ) { + $this->config = array(); + return $this->config; + } + + $this->config = $config[self::CONFIG_KEY]; + return $this->config; + } + + /** + * Extract config name from service name + * + * @param string $name + * @return string + */ + protected function getConfigName($name) + { + return substr($name, strlen(self::NAME_PREFIX)); + } +} diff --git a/library/Zend/Navigation/composer.json b/library/Zend/Navigation/composer.json index 8c0ec78fc..72f69219e 100644 --- a/library/Zend/Navigation/composer.json +++ b/library/Zend/Navigation/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Navigation\\": "" } }, - "target-dir": "Zend/Navigation", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Paginator/Adapter/DbSelect.php b/library/Zend/Paginator/Adapter/DbSelect.php index 4739569b8..baae58567 100644 --- a/library/Zend/Paginator/Adapter/DbSelect.php +++ b/library/Zend/Paginator/Adapter/DbSelect.php @@ -18,29 +18,38 @@ use Zend\Db\ResultSet\ResultSetInterface; class DbSelect implements AdapterInterface { + const ROW_COUNT_COLUMN_NAME = 'C'; + /** * @var Sql */ - protected $sql = null; + protected $sql; /** * Database query * * @var Select */ - protected $select = null; + protected $select; + + /** + * Database count query + * + * @var Select|null + */ + protected $countSelect; /** * @var ResultSet */ - protected $resultSetPrototype = null; + protected $resultSetPrototype; /** * Total item count * * @var int */ - protected $rowCount = null; + protected $rowCount; /** * Constructor. @@ -48,11 +57,18 @@ class DbSelect implements AdapterInterface * @param Select $select The select query * @param Adapter|Sql $adapterOrSqlObject DB adapter or Sql object * @param null|ResultSetInterface $resultSetPrototype + * @param null|Select $countSelect + * * @throws Exception\InvalidArgumentException */ - public function __construct(Select $select, $adapterOrSqlObject, ResultSetInterface $resultSetPrototype = null) - { + public function __construct( + Select $select, + $adapterOrSqlObject, + ResultSetInterface $resultSetPrototype = null, + Select $countSelect = null + ) { $this->select = $select; + $this->countSelect = $countSelect; if ($adapterOrSqlObject instanceof Adapter) { $adapterOrSqlObject = new Sql($adapterOrSqlObject); @@ -87,7 +103,7 @@ class DbSelect implements AdapterInterface $resultSet = clone $this->resultSetPrototype; $resultSet->initialize($result); - return $resultSet; + return iterator_to_array($resultSet); } /** @@ -101,21 +117,38 @@ class DbSelect implements AdapterInterface return $this->rowCount; } + $select = $this->getSelectCount(); + + $statement = $this->sql->prepareStatementForSqlObject($select); + $result = $statement->execute(); + $row = $result->current(); + + $this->rowCount = (int) $row[self::ROW_COUNT_COLUMN_NAME]; + + return $this->rowCount; + } + + /** + * Returns select query for count + * + * @return Select + */ + protected function getSelectCount() + { + if ($this->countSelect) { + return $this->countSelect; + } + $select = clone $this->select; $select->reset(Select::LIMIT); $select->reset(Select::OFFSET); $select->reset(Select::ORDER); $countSelect = new Select; - $countSelect->columns(array('c' => new Expression('COUNT(1)'))); + + $countSelect->columns(array(self::ROW_COUNT_COLUMN_NAME => new Expression('COUNT(1)'))); $countSelect->from(array('original_select' => $select)); - $statement = $this->sql->prepareStatementForSqlObject($countSelect); - $result = $statement->execute(); - $row = $result->current(); - - $this->rowCount = $row['c']; - - return $this->rowCount; + return $countSelect; } } diff --git a/library/Zend/Paginator/Adapter/Null.php b/library/Zend/Paginator/Adapter/Null.php index a1a9cfcf5..3ea9e5641 100644 --- a/library/Zend/Paginator/Adapter/Null.php +++ b/library/Zend/Paginator/Adapter/Null.php @@ -9,51 +9,22 @@ namespace Zend\Paginator\Adapter; -class Null implements AdapterInterface +class Null extends NullFill { /** - * Item count - * - * @var int - */ - protected $count = null; - - /** - * Constructor. - * - * @param int $count Total item count (Optional) + * {@inheritdoc} */ public function __construct($count = 0) { - $this->count = $count; - } + trigger_error( + sprintf( + 'The class %s has been deprecated; please use %s\\NullFill', + __CLASS__, + __NAMESPACE__ + ), + E_USER_DEPRECATED + ); - /** - * Returns an array of items for a page. - * - * @param int $offset Page offset - * @param int $itemCountPerPage Number of items per page - * @return array - */ - public function getItems($offset, $itemCountPerPage) - { - if ($offset >= $this->count()) { - return array(); - } - - $remainItemCount = $this->count() - $offset; - $currentItemCount = $remainItemCount > $itemCountPerPage ? $itemCountPerPage : $remainItemCount; - - return array_fill(0, $currentItemCount, null); - } - - /** - * Returns the total number of rows in the array. - * - * @return int - */ - public function count() - { - return $this->count; + parent::__construct($count); } } diff --git a/library/Zend/Paginator/Adapter/NullFill.php b/library/Zend/Paginator/Adapter/NullFill.php new file mode 100644 index 000000000..9786964ce --- /dev/null +++ b/library/Zend/Paginator/Adapter/NullFill.php @@ -0,0 +1,59 @@ +count = $count; + } + + /** + * Returns an array of items for a page. + * + * @param int $offset Page offset + * @param int $itemCountPerPage Number of items per page + * @return array + */ + public function getItems($offset, $itemCountPerPage) + { + if ($offset >= $this->count()) { + return array(); + } + + $remainItemCount = $this->count() - $offset; + $currentItemCount = $remainItemCount > $itemCountPerPage ? $itemCountPerPage : $remainItemCount; + + return array_fill(0, $currentItemCount, null); + } + + /** + * Returns the total number of rows in the array. + * + * @return int + */ + public function count() + { + return $this->count; + } +} diff --git a/library/Zend/Paginator/Adapter/Service/DbSelectFactory.php b/library/Zend/Paginator/Adapter/Service/DbSelectFactory.php index 41a2a1847..662881c59 100644 --- a/library/Zend/Paginator/Adapter/Service/DbSelectFactory.php +++ b/library/Zend/Paginator/Adapter/Service/DbSelectFactory.php @@ -9,33 +9,41 @@ namespace Zend\Paginator\Adapter\Service; +use Zend\Paginator\Adapter\DbSelect; use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\MutableCreationOptionsInterface; use Zend\ServiceManager\ServiceLocatorInterface; -class DbSelectFactory implements FactoryInterface +class DbSelectFactory implements + FactoryInterface, + MutableCreationOptionsInterface { /** * Adapter options + * * @var array */ protected $creationOptions; /** - * Construct with adapter options - * @param array $creationOptions + * {@inheritDoc} */ - public function __construct(array $creationOptions) + public function setCreationOptions(array $creationOptions) { $this->creationOptions = $creationOptions; } /** - * @param ServiceLocatorInterface $serviceLocator + * {@inheritDoc} + * * @return \Zend\Paginator\Adapter\DbSelect */ public function createService(ServiceLocatorInterface $serviceLocator) { - $class = new \ReflectionClass('Zend\Paginator\Adapter\DbSelect'); - return $class->newInstanceArgs($this->creationOptions); + return new DbSelect( + $this->creationOptions[0], + $this->creationOptions[1], + isset($this->creationOptions[2]) ? $this->creationOptions[2] : null + ); } } diff --git a/library/Zend/Paginator/AdapterPluginManager.php b/library/Zend/Paginator/AdapterPluginManager.php index d9c070795..ad5e7a385 100644 --- a/library/Zend/Paginator/AdapterPluginManager.php +++ b/library/Zend/Paginator/AdapterPluginManager.php @@ -20,6 +20,19 @@ use Zend\ServiceManager\AbstractPluginManager; */ class AdapterPluginManager extends AbstractPluginManager { + /** + * Default aliases + * + * Primarily for ensuring previously defined adapters select their + * current counterparts. + * + * @var array + */ + protected $aliases = array( + 'null' => 'nullfill', + 'Zend\Paginator\Adapter\Null' => 'nullfill', + ); + /** * Default set of adapters * @@ -28,7 +41,7 @@ class AdapterPluginManager extends AbstractPluginManager protected $invokableClasses = array( 'array' => 'Zend\Paginator\Adapter\ArrayAdapter', 'iterator' => 'Zend\Paginator\Adapter\Iterator', - 'null' => 'Zend\Paginator\Adapter\Null', + 'nullfill' => 'Zend\Paginator\Adapter\NullFill', ); /** diff --git a/library/Zend/Paginator/Paginator.php b/library/Zend/Paginator/Paginator.php index 03b73caa4..376b615aa 100644 --- a/library/Zend/Paginator/Paginator.php +++ b/library/Zend/Paginator/Paginator.php @@ -140,7 +140,7 @@ class Paginator implements Countable, IteratorAggregate /** * Pages * - * @var array + * @var \stdClass */ protected $pages = null; @@ -372,11 +372,8 @@ class Paginator implements Countable, IteratorAggregate $cacheIterator = static::$cache->getIterator(); $cacheIterator->setMode(CacheIterator::CURRENT_AS_KEY); foreach ($cacheIterator as $key) { - $tags = static::$cache->getTags($key); - if ($tags && in_array($this->_getCacheInternalId(), $tags)) { - if (substr($key, 0, $prefixLength) == self::CACHE_TAG_PREFIX) { - static::$cache->removeItem($this->_getCacheId((int)substr($key, $prefixLength))); - } + if (substr($key, 0, $prefixLength) == self::CACHE_TAG_PREFIX) { + static::$cache->removeItem($this->_getCacheId((int)substr($key, $prefixLength))); } } } else { @@ -617,7 +614,6 @@ class Paginator implements Countable, IteratorAggregate if ($this->cacheEnabled()) { $cacheId = $this->_getCacheId($pageNumber); static::$cache->setItem($cacheId, $items); - static::$cache->setTags($cacheId, array($this->_getCacheInternalId())); } return $items; @@ -665,7 +661,7 @@ class Paginator implements Countable, IteratorAggregate * Returns the page collection. * * @param string $scrollingStyle Scrolling style - * @return array + * @return \stdClass */ public function getPages($scrollingStyle = null) { @@ -710,11 +706,8 @@ class Paginator implements Countable, IteratorAggregate $cacheIterator = static::$cache->getIterator(); $cacheIterator->setMode(CacheIterator::CURRENT_AS_VALUE); foreach ($cacheIterator as $key => $value) { - $tags = static::$cache->getTags($key); - if ($tags && in_array($this->_getCacheInternalId(), $tags)) { - if (substr($key, 0, $prefixLength) == self::CACHE_TAG_PREFIX) { - $data[(int) substr($key, $prefixLength)] = $value; - } + if (substr($key, 0, $prefixLength) == self::CACHE_TAG_PREFIX) { + $data[(int) substr($key, $prefixLength)] = $value; } } } @@ -917,10 +910,13 @@ class Paginator implements Countable, IteratorAggregate // Item numbers if ($this->getCurrentItems() !== null) { $pages->currentItemCount = $this->getCurrentItemCount(); - $pages->itemCountPerPage = $this->getItemCountPerPage(); $pages->totalItemCount = $this->getTotalItemCount(); - $pages->firstItemNumber = (($currentPageNumber - 1) * $this->getItemCountPerPage()) + 1; - $pages->lastItemNumber = $pages->firstItemNumber + $pages->currentItemCount - 1; + $pages->firstItemNumber = $pages->totalItemCount + ? (($currentPageNumber - 1) * $pages->itemCountPerPage) + 1 + : 0; + $pages->lastItemNumber = $pages->totalItemCount + ? $pages->firstItemNumber + $pages->currentItemCount - 1 + : 0; } return $pages; diff --git a/library/Zend/Paginator/PaginatorIterator.php b/library/Zend/Paginator/PaginatorIterator.php new file mode 100644 index 000000000..1c8b1eae7 --- /dev/null +++ b/library/Zend/Paginator/PaginatorIterator.php @@ -0,0 +1,124 @@ +paginator = $paginator; + } + + /** + * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * @return mixed Can return any type. + */ + public function current() + { + return $this->getInnerIterator()->current(); + } + + /** + * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + */ + public function next() + { + $innerIterator = $this->getInnerIterator(); + $innerIterator->next(); + + if ($innerIterator->valid()) { + return; + } + + $page = $this->paginator->getCurrentPageNumber(); + $nextPage = $page + 1; + $this->paginator->setCurrentPageNumber($nextPage); + + $page = $this->paginator->getCurrentPageNumber(); + if ($page !== $nextPage) { + $this->valid = false; + } + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + */ + public function key() + { + $innerKey = $this->getInnerIterator()->key(); + $innerKey += 1; //Zend\Paginator\Paginator normalizes 0 to 1 + + $page = $this->paginator->getCurrentPageNumber(); + return ($this->paginator->getAbsoluteItemNumber( + $innerKey, + $this->paginator->getCurrentPageNumber() + )) - 1; + } + + /** + * 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() + { + if (count($this->paginator) < 1) { + $this->valid = false; + } + return $this->valid; + } + + /** + * 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->paginator->setCurrentPageNumber(1); + $this->valid = true; + } + + /** + * Returns the inner iterator for the current entry. + * @link http://php.net/manual/en/outeriterator.getinneriterator.php + * @return \Iterator The inner iterator for the current entry. + */ + public function getInnerIterator() + { + return $this->paginator->getCurrentItems(); + } +} diff --git a/library/Zend/Paginator/composer.json b/library/Zend/Paginator/composer.json index a94257517..927d539f7 100644 --- a/library/Zend/Paginator/composer.json +++ b/library/Zend/Paginator/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Paginator\\": "" } }, - "target-dir": "Zend/Paginator", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Permissions/Acl/Acl.php b/library/Zend/Permissions/Acl/Acl.php index 571e37bb8..1b7887b07 100644 --- a/library/Zend/Permissions/Acl/Acl.php +++ b/library/Zend/Permissions/Acl/Acl.php @@ -829,7 +829,7 @@ class Acl implements AclInterface } } - return null; + return; } /** @@ -868,7 +868,7 @@ class Acl implements AclInterface $dfs['stack'][] = $roleParent; } - return null; + return; } /** @@ -908,7 +908,7 @@ class Acl implements AclInterface } } - return null; + return; } /** @@ -957,7 +957,7 @@ class Acl implements AclInterface $dfs['stack'][] = $roleParent; } - return null; + return; } /** @@ -985,7 +985,7 @@ class Acl implements AclInterface { // get the rules for the $resource and $role if (null === ($rules = $this->getRules($resource, $role))) { - return null; + return; } // follow $privilege @@ -993,10 +993,10 @@ class Acl implements AclInterface if (isset($rules['allPrivileges'])) { $rule = $rules['allPrivileges']; } else { - return null; + return; } } elseif (!isset($rules['byPrivilegeId'][$privilege])) { - return null; + return; } else { $rule = $rules['byPrivilegeId'][$privilege]; } @@ -1015,7 +1015,7 @@ class Acl implements AclInterface if (null === $rule['assert'] || $assertionValue) { return $rule['type']; } elseif (null !== $resource || null !== $role || null !== $privilege) { - return null; + return; } elseif (self::TYPE_ALLOW === $rule['type']) { return self::TYPE_DENY; } diff --git a/library/Zend/Permissions/Acl/Assertion/CallbackAssertion.php b/library/Zend/Permissions/Acl/Assertion/CallbackAssertion.php new file mode 100644 index 000000000..df30528e4 --- /dev/null +++ b/library/Zend/Permissions/Acl/Assertion/CallbackAssertion.php @@ -0,0 +1,59 @@ +callback = $callback; + } + + /** + * Returns true if and only if the assertion conditions are met. + * + * This method is passed the ACL, Role, Resource, and privilege to which the + * authorization query applies. + * + * If the $role, $resource, or $privilege parameters are null, it means + * that the query applies to all Roles, Resources, or privileges, + * respectively. + * + * @param Acl $acl + * @param RoleInterface $role + * @param ResourceInterface $resource + * @param string $privilege + * + * @return bool + */ + public function assert( + Acl $acl, + RoleInterface $role = null, + ResourceInterface $resource = null, + $privilege = null + ) { + return (bool) call_user_func($this->callback, $acl, $role, $resource, $privilege); + } +} diff --git a/library/Zend/Permissions/Acl/composer.json b/library/Zend/Permissions/Acl/composer.json index ffe94f984..a7f370def 100644 --- a/library/Zend/Permissions/Acl/composer.json +++ b/library/Zend/Permissions/Acl/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Permissions\\Acl\\": "" } }, - "target-dir": "Zend/Permissions/Acl", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Permissions/Rbac/Assertion/CallbackAssertion.php b/library/Zend/Permissions/Rbac/Assertion/CallbackAssertion.php new file mode 100644 index 000000000..b3a64a1e5 --- /dev/null +++ b/library/Zend/Permissions/Rbac/Assertion/CallbackAssertion.php @@ -0,0 +1,45 @@ +callback = $callback; + } + + /** + * Assertion method - must return a boolean. + * + * Returns the result of the composed callback. + * + * @param Rbac $rbac + * @return bool + */ + public function assert(Rbac $rbac) + { + return (bool) call_user_func($this->callback, $rbac); + } +} diff --git a/library/Zend/Permissions/Rbac/Rbac.php b/library/Zend/Permissions/Rbac/Rbac.php index 8ed79a8ec..aa550e424 100644 --- a/library/Zend/Permissions/Rbac/Rbac.php +++ b/library/Zend/Permissions/Rbac/Rbac.php @@ -141,24 +141,18 @@ class Rbac extends AbstractIterator { 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' - ); + return (bool) $assert->assert($this); } + + if (is_callable($assert)) { + return (bool) $assert($this); + } + + 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; + return $this->getRole($role)->hasPermission($permission); } } diff --git a/library/Zend/Permissions/Rbac/composer.json b/library/Zend/Permissions/Rbac/composer.json index e70e6c13c..a7d45d8cc 100644 --- a/library/Zend/Permissions/Rbac/composer.json +++ b/library/Zend/Permissions/Rbac/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Permissions\\Rbac\\": "" } }, - "target-dir": "Zend/Permissions/Rbac", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/ProgressBar/composer.json b/library/Zend/ProgressBar/composer.json index c0cefdc87..93df8738b 100644 --- a/library/Zend/ProgressBar/composer.json +++ b/library/Zend/ProgressBar/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\ProgressBar\\": "" } }, - "target-dir": "Zend/ProgressBar", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Serializer/Adapter/IgBinary.php b/library/Zend/Serializer/Adapter/IgBinary.php index d821c403b..ddc561264 100644 --- a/library/Zend/Serializer/Adapter/IgBinary.php +++ b/library/Zend/Serializer/Adapter/IgBinary.php @@ -69,7 +69,7 @@ class IgBinary extends AbstractAdapter public function unserialize($serialized) { if ($serialized === static::$serializedNull) { - return null; + return; } ErrorHandler::start(); diff --git a/library/Zend/Serializer/Adapter/Wddx.php b/library/Zend/Serializer/Adapter/Wddx.php index 4d1ba3f83..907d30e90 100644 --- a/library/Zend/Serializer/Adapter/Wddx.php +++ b/library/Zend/Serializer/Adapter/Wddx.php @@ -125,7 +125,7 @@ class Wddx extends AbstractAdapter //$simpleXml = new \SimpleXMLElement($wddx); libxml_disable_entity_loader($oldLibxmlDisableEntityLoader); if (isset($simpleXml->data[0]->null[0])) { - return null; // valid null + return; // valid null } throw new Exception\RuntimeException('Unserialization failed: Invalid wddx packet'); } catch (\Exception $e) { diff --git a/library/Zend/Serializer/composer.json b/library/Zend/Serializer/composer.json index c36b3ab56..fa453bd95 100644 --- a/library/Zend/Serializer/composer.json +++ b/library/Zend/Serializer/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Serializer\\": "" } }, - "target-dir": "Zend/Serializer", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version", diff --git a/library/Zend/Server/Method/Prototype.php b/library/Zend/Server/Method/Prototype.php index 851cda9a6..3b36b7297 100644 --- a/library/Zend/Server/Method/Prototype.php +++ b/library/Zend/Server/Method/Prototype.php @@ -146,7 +146,7 @@ class Prototype public function getParameter($index) { if (!is_string($index) && !is_numeric($index)) { - return null; + return; } if (array_key_exists($index, $this->parameterNameMap)) { $index = $this->parameterNameMap[$index]; @@ -154,7 +154,7 @@ class Prototype if (array_key_exists($index, $this->parameters)) { return $this->parameters[$index]; } - return null; + return; } /** diff --git a/library/Zend/Server/Reflection.php b/library/Zend/Server/Reflection.php index 28eb04d8d..ab9332afc 100644 --- a/library/Zend/Server/Reflection.php +++ b/library/Zend/Server/Reflection.php @@ -38,7 +38,7 @@ class Reflection { if (is_object($class)) { $reflection = new \ReflectionObject($class); - } elseif (class_exists($class)) { + } elseif (is_string($class) && class_exists($class)) { $reflection = new \ReflectionClass($class); } else { throw new Reflection\Exception\InvalidArgumentException('Invalid class or object passed to attachClass()'); @@ -71,7 +71,10 @@ class Reflection public static function reflectFunction($function, $argv = false, $namespace = '') { if (!is_string($function) || !function_exists($function)) { - throw new Reflection\Exception\InvalidArgumentException('Invalid function "' . $function . '" passed to reflectFunction'); + throw new Reflection\Exception\InvalidArgumentException(sprintf( + 'Invalid function "%s" passed to reflectFunction', + $function + )); } if ($argv && !is_array($argv)) { diff --git a/library/Zend/Server/Reflection/AbstractFunction.php b/library/Zend/Server/Reflection/AbstractFunction.php index cb37bf94c..9ba6abd6b 100644 --- a/library/Zend/Server/Reflection/AbstractFunction.php +++ b/library/Zend/Server/Reflection/AbstractFunction.php @@ -330,7 +330,7 @@ abstract class AbstractFunction return $this->config[$key]; } - return null; + return; } /** diff --git a/library/Zend/Server/Reflection/ReflectionClass.php b/library/Zend/Server/Reflection/ReflectionClass.php index 8f191bc1f..aa76e482d 100644 --- a/library/Zend/Server/Reflection/ReflectionClass.php +++ b/library/Zend/Server/Reflection/ReflectionClass.php @@ -104,7 +104,7 @@ class ReflectionClass return $this->config[$key]; } - return null; + return; } /** diff --git a/library/Zend/Server/composer.json b/library/Zend/Server/composer.json index 5391d38a1..fda84138c 100644 --- a/library/Zend/Server/composer.json +++ b/library/Zend/Server/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Server\\": "" } }, - "target-dir": "Zend/Server", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version", diff --git a/library/Zend/ServiceManager/AbstractPluginManager.php b/library/Zend/ServiceManager/AbstractPluginManager.php index 791a314f9..4f1341456 100644 --- a/library/Zend/ServiceManager/AbstractPluginManager.php +++ b/library/Zend/ServiceManager/AbstractPluginManager.php @@ -9,6 +9,8 @@ namespace Zend\ServiceManager; +use Exception as BaseException; + /** * ServiceManager implementation for managing plugins * @@ -55,7 +57,7 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo * Add a default initializer to ensure the plugin is valid after instance * creation. * - * @param null|ConfigInterface $configuration + * @param null|ConfigInterface $configuration */ public function __construct(ConfigInterface $configuration = null) { @@ -74,7 +76,7 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo * Checks that the filter loaded is either a valid callback or an instance * of FilterInterface. * - * @param mixed $plugin + * @param mixed $plugin * @return void * @throws Exception\RuntimeException if invalid */ @@ -88,21 +90,44 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo * constructor if not null and a non-empty array. * * @param string $name - * @param array $options - * @param bool $usePeeringServiceManagers + * @param array $options + * @param bool $usePeeringServiceManagers + * * @return object + * + * @throws Exception\ServiceNotFoundException + * @throws Exception\ServiceNotCreatedException + * @throws Exception\RuntimeException */ public function get($name, $options = array(), $usePeeringServiceManagers = true) { + $isAutoInvokable = false; + // Allow specifying a class name directly; registers as an invokable class if (!$this->has($name) && $this->autoAddInvokableClass && class_exists($name)) { + $isAutoInvokable = true; + $this->setInvokableClass($name, $name); } $this->creationOptions = $options; - $instance = parent::get($name, $usePeeringServiceManagers); + + try { + $instance = parent::get($name, $usePeeringServiceManagers); + } catch (Exception\ServiceNotFoundException $exception) { + $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception); + } catch (Exception\ServiceNotCreatedException $exception) { + $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception); + } + $this->creationOptions = null; - $this->validatePlugin($instance); + + try { + $this->validatePlugin($instance); + } catch (Exception\RuntimeException $exception) { + $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception); + } + return $instance; } @@ -112,9 +137,9 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo * Validates that the service object via validatePlugin() prior to * attempting to register it. * - * @param string $name - * @param mixed $service - * @param bool $shared + * @param string $name + * @param mixed $service + * @param bool $shared * @return AbstractPluginManager * @throws Exception\InvalidServiceNameException */ @@ -124,18 +149,20 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo $this->validatePlugin($service); } parent::setService($name, $service, $shared); + return $this; } /** * Set the main service locator so factories can have access to it to pull deps * - * @param ServiceLocatorInterface $serviceLocator + * @param ServiceLocatorInterface $serviceLocator * @return AbstractPluginManager */ public function setServiceLocator(ServiceLocatorInterface $serviceLocator) { $this->serviceLocator = $serviceLocator; + return $this; } @@ -155,8 +182,8 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo * Overrides parent implementation by passing $creationOptions to the * constructor, if non-null. * - * @param string $canonicalName - * @param string $requestedName + * @param string $canonicalName + * @param string $requestedName * @return null|\stdClass * @throws Exception\ServiceNotCreatedException If resolved class does not exist */ @@ -191,8 +218,8 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo * Overrides parent implementation by passing $creationOptions to the * constructor, if non-null. * - * @param string $canonicalName - * @param string $requestedName + * @param string $canonicalName + * @param string $requestedName * @return mixed * @throws Exception\ServiceNotCreatedException If factory is not callable */ @@ -216,13 +243,11 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo } elseif (is_callable($factory)) { $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName); } else { - throw new Exception\ServiceNotCreatedException( - sprintf( - 'While attempting to create %s%s an invalid factory was registered for this instance type.', - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : '') - ) - ); + throw new Exception\ServiceNotCreatedException(sprintf( + 'While attempting to create %s%s an invalid factory was registered for this instance type.', + $canonicalName, + ($requestedName ? '(alias: ' . $requestedName . ')' : '') + )); } return $instance; @@ -231,9 +256,9 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo /** * Create service via callback * - * @param callable $callable - * @param string $cName - * @param string $rName + * @param callable $callable + * @param string $cName + * @param string $rName * @throws Exception\ServiceNotCreatedException * @throws Exception\ServiceNotFoundException * @throws Exception\CircularDependencyFoundException @@ -258,4 +283,35 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo return parent::createServiceViaCallback($callable, $cName, $rName); } + + /** + * @param string $serviceName + * @param bool $isAutoInvokable + * @param BaseException $exception + * + * @throws BaseException + * @throws Exception\ServiceLocatorUsageException + */ + private function tryThrowingServiceLocatorUsageException( + $serviceName, + $isAutoInvokable, + BaseException $exception + ) { + if ($isAutoInvokable) { + $this->unregisterService($this->canonicalizeName($serviceName)); + } + + $serviceLocator = $this->getServiceLocator(); + + if ($serviceLocator && $serviceLocator->has($serviceName)) { + throw Exception\ServiceLocatorUsageException::fromInvalidPluginManagerRequestedServiceName( + $this, + $serviceLocator, + $serviceName, + $exception + ); + } + + throw $exception; + } } diff --git a/library/Zend/ServiceManager/Exception/ServiceLocatorUsageException.php b/library/Zend/ServiceManager/Exception/ServiceLocatorUsageException.php new file mode 100644 index 000000000..d248047e3 --- /dev/null +++ b/library/Zend/ServiceManager/Exception/ServiceLocatorUsageException.php @@ -0,0 +1,50 @@ +getServiceLocator() in your factory code?', + $serviceName, + get_class($pluginManager), + get_class($previousException), + $serviceName, + get_class($parentLocator) + ), + 0, + $previousException + ); + } +} diff --git a/library/Zend/ServiceManager/MutableCreationOptionsTrait.php b/library/Zend/ServiceManager/MutableCreationOptionsTrait.php new file mode 100644 index 000000000..5f8af8a02 --- /dev/null +++ b/library/Zend/ServiceManager/MutableCreationOptionsTrait.php @@ -0,0 +1,42 @@ +creationOptions = $creationOptions; + } + + /** + * Get creation options + * + * @return array + */ + public function getCreationOptions() + { + return $this->creationOptions; + } +} diff --git a/library/Zend/ServiceManager/Proxy/LazyServiceFactory.php b/library/Zend/ServiceManager/Proxy/LazyServiceFactory.php index 6dcdf3220..806d008d0 100644 --- a/library/Zend/ServiceManager/Proxy/LazyServiceFactory.php +++ b/library/Zend/ServiceManager/Proxy/LazyServiceFactory.php @@ -10,7 +10,6 @@ namespace Zend\ServiceManager\Proxy; use ProxyManager\Factory\LazyLoadingValueHolderFactory; - use ProxyManager\Proxy\LazyLoadingInterface; use Zend\ServiceManager\DelegatorFactoryInterface; use Zend\ServiceManager\Exception; diff --git a/library/Zend/ServiceManager/ServiceManager.php b/library/Zend/ServiceManager/ServiceManager.php index 2ed71d27e..4411343e7 100644 --- a/library/Zend/ServiceManager/ServiceManager.php +++ b/library/Zend/ServiceManager/ServiceManager.php @@ -114,6 +114,11 @@ class ServiceManager implements ServiceLocatorInterface */ protected $canonicalNamesReplacements = array('-' => '', '_' => '', ' ' => '', '\\' => '', '/' => ''); + /** + * @var ServiceLocatorInterface + */ + protected $serviceManagerCaller; + /** * Constructor * @@ -446,7 +451,7 @@ class ServiceManager implements ServiceLocatorInterface if (!isset($this->shared[$cName])) { return $this->shareByDefault(); } - + return $this->shared[$cName]; } @@ -718,10 +723,21 @@ class ServiceManager implements ServiceLocatorInterface } if ($usePeeringServiceManagers) { + $caller = $this->serviceManagerCaller; foreach ($this->peeringServiceManagers as $peeringServiceManager) { + // ignore peering service manager if they are the same instance + if ($caller === $peeringServiceManager) { + continue; + } + + $peeringServiceManager->serviceManagerCaller = $this; + if ($peeringServiceManager->has($name)) { + $peeringServiceManager->serviceManagerCaller = null; return true; } + + $peeringServiceManager->serviceManagerCaller = null; } } @@ -987,11 +1003,8 @@ class ServiceManager implements ServiceLocatorInterface */ protected function retrieveFromPeeringManager($name) { - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - if ($peeringServiceManager->has($name)) { - $this->shared[$name] = $peeringServiceManager->isShared($name); - return $peeringServiceManager->get($name); - } + if (null !== ($service = $this->loopPeeringServiceManagers($name))) { + return $service; } $name = $this->canonicalizeName($name); @@ -1002,14 +1015,43 @@ class ServiceManager implements ServiceLocatorInterface } while ($this->hasAlias($name)); } - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - if ($peeringServiceManager->has($name)) { - $this->shared[$name] = $peeringServiceManager->isShared($name); - return $peeringServiceManager->get($name); - } + if (null !== ($service = $this->loopPeeringServiceManagers($name))) { + return $service; } - return null; + return; + } + + /** + * Loop over peering service managers. + * + * @param string $name + * @return mixed + */ + protected function loopPeeringServiceManagers($name) + { + $caller = $this->serviceManagerCaller; + + foreach ($this->peeringServiceManagers as $peeringServiceManager) { + // ignore peering service manager if they are the same instance + if ($caller === $peeringServiceManager) { + continue; + } + + // pass this instance to peering service manager + $peeringServiceManager->serviceManagerCaller = $this; + + if ($peeringServiceManager->has($name)) { + $this->shared[$name] = $peeringServiceManager->isShared($name); + $instance = $peeringServiceManager->get($name); + $peeringServiceManager->serviceManagerCaller = null; + return $instance; + } + + $peeringServiceManager->serviceManagerCaller = null; + } + + return; } /** @@ -1101,7 +1143,7 @@ class ServiceManager implements ServiceLocatorInterface ); } } - return null; + return; } /** diff --git a/library/Zend/ServiceManager/composer.json b/library/Zend/ServiceManager/composer.json index d843f4929..59cc60558 100644 --- a/library/Zend/ServiceManager/composer.json +++ b/library/Zend/ServiceManager/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\ServiceManager\\": "" } }, - "target-dir": "Zend/ServiceManager", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Session/AbstractContainer.php b/library/Zend/Session/AbstractContainer.php index 39327d110..9c48c080e 100644 --- a/library/Zend/Session/AbstractContainer.php +++ b/library/Zend/Session/AbstractContainer.php @@ -425,7 +425,7 @@ abstract class AbstractContainer extends ArrayObject public function offsetGet($key) { if (!$this->offsetExists($key)) { - return null; + return; } $storage = $this->getStorage(); $name = $this->getName(); @@ -528,7 +528,7 @@ abstract class AbstractContainer extends ArrayObject // Map item keys => timestamp $expires = array_flip($expires); - $expires = array_map(function ($value) use ($ts) { + $expires = array_map(function () use ($ts) { return $ts; }, $expires); @@ -579,7 +579,7 @@ abstract class AbstractContainer extends ArrayObject // Map item keys => timestamp $expires = array_flip($expires); - $expires = array_map(function ($value) use ($hops, $ts) { + $expires = array_map(function () use ($hops, $ts) { return array('hops' => $hops, 'ts' => $ts); }, $expires); diff --git a/library/Zend/Session/AbstractManager.php b/library/Zend/Session/AbstractManager.php index 145841a91..51eda67d1 100644 --- a/library/Zend/Session/AbstractManager.php +++ b/library/Zend/Session/AbstractManager.php @@ -48,16 +48,26 @@ abstract class AbstractManager implements Manager */ protected $saveHandler; + /** + * @var array + */ + protected $validators; + /** * Constructor * - * @param Config|null $config - * @param Storage|null $storage + * @param Config|null $config + * @param Storage|null $storage * @param SaveHandler|null $saveHandler + * @param array $validators * @throws Exception\RuntimeException */ - public function __construct(Config $config = null, Storage $storage = null, SaveHandler $saveHandler = null) - { + public function __construct( + Config $config = null, + Storage $storage = null, + SaveHandler $saveHandler = null, + array $validators = array() + ) { // init config if ($config === null) { if (!class_exists($this->defaultConfigClass)) { @@ -106,6 +116,8 @@ abstract class AbstractManager implements Manager if ($saveHandler !== null) { $this->saveHandler = $saveHandler; } + + $this->validators = $validators; } /** diff --git a/library/Zend/Session/Config/SessionConfig.php b/library/Zend/Session/Config/SessionConfig.php index 3328a6c9f..3c96268ee 100644 --- a/library/Zend/Session/Config/SessionConfig.php +++ b/library/Zend/Session/Config/SessionConfig.php @@ -85,7 +85,7 @@ class SessionConfig extends StandardConfig break; } - $result = ini_set($key, $storageValue); + $result = ini_set($key, (string) $storageValue); if (false === $result) { throw new Exception\InvalidArgumentException( "'{$key}' is not a valid sessions-related ini setting." diff --git a/library/Zend/Session/Config/StandardConfig.php b/library/Zend/Session/Config/StandardConfig.php index 5ff2c2469..a5dd2f16f 100644 --- a/library/Zend/Session/Config/StandardConfig.php +++ b/library/Zend/Session/Config/StandardConfig.php @@ -173,7 +173,7 @@ class StandardConfig implements ConfigInterface return $value; } - return null; + return; } /** @@ -213,7 +213,7 @@ class StandardConfig implements ConfigInterface */ public function getStorageOption($storageOption) { - return null; + return; } /** diff --git a/library/Zend/Session/SaveHandler/DbTableGateway.php b/library/Zend/Session/SaveHandler/DbTableGateway.php index 77d0e4dd2..e568fc734 100644 --- a/library/Zend/Session/SaveHandler/DbTableGateway.php +++ b/library/Zend/Session/SaveHandler/DbTableGateway.php @@ -128,7 +128,7 @@ class DbTableGateway implements SaveHandlerInterface $this->options->getNameColumn() => $this->sessionName, )); - if ($row = $rows->current()) { + if ($rows->current()) { return (bool) $this->tableGateway->update($data, array( $this->options->getIdColumn() => $id, $this->options->getNameColumn() => $this->sessionName, diff --git a/library/Zend/Session/SaveHandler/MongoDBOptions.php b/library/Zend/Session/SaveHandler/MongoDBOptions.php index d915b6829..9e9a99707 100644 --- a/library/Zend/Session/SaveHandler/MongoDBOptions.php +++ b/library/Zend/Session/SaveHandler/MongoDBOptions.php @@ -76,11 +76,32 @@ class MongoDBOptions extends AbstractOptions { parent::__construct($options); - if ($this->saveOptions === array('w' => 1) && version_compare(phpversion('mongo'), '1.3.0', '<')) { + $mongoVersion = phpversion('mongo') ?: '0.0.0'; + if ($this->saveOptions === array('w' => 1) && version_compare($mongoVersion, '1.3.0', '<')) { $this->saveOptions = array('safe' => true); } } + /** + * Override AbstractOptions::__set + * + * Validates value if save options are being set. + * + * @param string $key + * @param mixed $value + */ + public function __set($key, $value) + { + if (strtolower($key) !== 'saveoptions') { + return parent::__set($key, $value); + } + + if (! is_array($value)) { + throw new InvalidArgumentException('Expected array for save options'); + } + $this->setSaveOptions($value); + } + /** * Set database name * diff --git a/library/Zend/Session/Service/SessionManagerFactory.php b/library/Zend/Session/Service/SessionManagerFactory.php index 864d8649c..712990d18 100644 --- a/library/Zend/Session/Service/SessionManagerFactory.php +++ b/library/Zend/Session/Service/SessionManagerFactory.php @@ -65,6 +65,7 @@ class SessionManagerFactory implements FactoryInterface $config = null; $storage = null; $saveHandler = null; + $validators = array(); $managerConfig = $this->defaultManagerConfig; if ($services->has('Zend\Session\Config\ConfigInterface')) { @@ -103,8 +104,6 @@ class SessionManagerFactory implements FactoryInterface } } - $manager = new SessionManager($config, $storage, $saveHandler); - // Get session manager configuration, if any, and merge with default configuration if ($services->has('Config')) { $configService = $services->get('Config'); @@ -113,16 +112,14 @@ class SessionManagerFactory implements FactoryInterface ) { $managerConfig = array_merge($managerConfig, $configService['session_manager']); } - // Attach validators to session manager, if any + if (isset($managerConfig['validators'])) { - $chain = $manager->getValidatorChain(); - foreach ($managerConfig['validators'] as $validator) { - $validator = new $validator(); - $chain->attach('session.validate', array($validator, 'isValid')); - } + $validators = $managerConfig['validators']; } } + $manager = new SessionManager($config, $storage, $saveHandler, $validators); + // If configuration enables the session manager as the default manager for container // instances, do so. if (isset($managerConfig['enable_default_container_manager']) diff --git a/library/Zend/Session/SessionManager.php b/library/Zend/Session/SessionManager.php index 77219f645..f36ff79b0 100644 --- a/library/Zend/Session/SessionManager.php +++ b/library/Zend/Session/SessionManager.php @@ -41,14 +41,19 @@ class SessionManager extends AbstractManager /** * Constructor * - * @param Config\ConfigInterface|null $config - * @param Storage\StorageInterface|null $storage + * @param Config\ConfigInterface|null $config + * @param Storage\StorageInterface|null $storage * @param SaveHandler\SaveHandlerInterface|null $saveHandler + * @param array $validators * @throws Exception\RuntimeException */ - public function __construct(Config\ConfigInterface $config = null, Storage\StorageInterface $storage = null, SaveHandler\SaveHandlerInterface $saveHandler = null) - { - parent::__construct($config, $storage, $saveHandler); + public function __construct( + Config\ConfigInterface $config = null, + Storage\StorageInterface $storage = null, + SaveHandler\SaveHandlerInterface $saveHandler = null, + array $validators = array() + ) { + parent::__construct($config, $storage, $saveHandler, $validators); register_shutdown_function(array($this, 'writeClose')); } @@ -93,7 +98,10 @@ class SessionManager extends AbstractManager $this->registerSaveHandler($saveHandler); } - $oldSessionData = $_SESSION; + $oldSessionData = array(); + if (isset($_SESSION)) { + $oldSessionData = $_SESSION; + } session_start(); @@ -116,11 +124,37 @@ class SessionManager extends AbstractManager $storage->init($_SESSION); } + $this->initializeValidatorChain(); + if (!$this->isValid()) { throw new Exception\RuntimeException('Session validation failed'); } } + /** + * Create validators, insert reference value and add them to the validator chain + */ + protected function initializeValidatorChain() + { + $validatorChain = $this->getValidatorChain(); + $validatorValues = $this->getStorage()->getMetadata('_VALID'); + + foreach ($this->validators as $validator) { + // Ignore validators which are already present in Storage + if (is_array($validatorValues) && array_key_exists($validator, $validatorValues)) { + continue; + } + + $referenceValue = null; + if (is_array($validatorValues) && array_key_exists($validator, $validatorValues)) { + $referenceValue = $validatorValues[$validator]; + } + + $validator = new $validator($referenceValue); + $validatorChain->attach('session.validate', array($validator, 'isValid')); + } + } + /** * Destroy/end a session * @@ -340,7 +374,7 @@ class SessionManager extends AbstractManager public function isValid() { $validator = $this->getValidatorChain(); - $responses = $validator->triggerUntil('session.validate', $this, array($this), function ($test) { + $responses = $validator->trigger('session.validate', $this, array($this), function ($test) { return false === $test; }); if ($responses->stopped()) { diff --git a/library/Zend/Session/Storage/AbstractSessionArrayStorage.php b/library/Zend/Session/Storage/AbstractSessionArrayStorage.php index fd861767a..bdfbf9a9d 100644 --- a/library/Zend/Session/Storage/AbstractSessionArrayStorage.php +++ b/library/Zend/Session/Storage/AbstractSessionArrayStorage.php @@ -133,7 +133,7 @@ abstract class AbstractSessionArrayStorage implements return $_SESSION[$key]; } - return null; + return; } /** diff --git a/library/Zend/Session/Storage/Factory.php b/library/Zend/Session/Storage/Factory.php index 73595fbf8..0d7bf36ed 100644 --- a/library/Zend/Session/Storage/Factory.php +++ b/library/Zend/Session/Storage/Factory.php @@ -60,14 +60,11 @@ abstract class Factory switch (true) { case (in_array('Zend\Session\Storage\AbstractSessionArrayStorage', class_parents($type))): return static::createSessionArrayStorage($type, $options); - break; case ($type === 'Zend\Session\Storage\ArrayStorage'): case (in_array('Zend\Session\Storage\ArrayStorage', class_parents($type))): return static::createArrayStorage($type, $options); - break; case (in_array('Zend\Session\Storage\StorageInterface', class_implements($type))): return new $type($options); - break; default: throw new Exception\InvalidArgumentException(sprintf( 'Unrecognized type "%s" provided; expects a class implementing %s\StorageInterface', diff --git a/library/Zend/Session/composer.json b/library/Zend/Session/composer.json index c3541e784..ca7cb6ebb 100644 --- a/library/Zend/Session/composer.json +++ b/library/Zend/Session/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Session\\": "" } }, - "target-dir": "Zend/Session", "require": { "php": ">=5.3.23", "zendframework/zend-eventmanager": "self.version", diff --git a/library/Zend/Soap/Client.php b/library/Zend/Soap/Client.php index 91c956355..5ec8c7bfa 100644 --- a/library/Zend/Soap/Client.php +++ b/library/Zend/Soap/Client.php @@ -270,14 +270,13 @@ class Client implements ServerClient $this->setTypemap($value); break; - // Not used now - // case 'connection_timeout': - // $this->connectionTimeout = $value; - // break; + case 'connectiontimeout': + case 'connection_timeout': + $this->connectionTimeout = $value; + break; default: throw new Exception\InvalidArgumentException('Unknown SOAP client option'); - break; } } @@ -311,7 +310,7 @@ class Client implements ServerClient $options['local_cert'] = $this->getHttpsCertificate(); $options['passphrase'] = $this->getHttpsCertPassphrase(); $options['compression'] = $this->getCompressionOptions(); - //$options['connection_timeout'] = $this->connectionTimeout; + $options['connection_timeout'] = $this->connectionTimeout; $options['stream_context'] = $this->getStreamContext(); $options['cache_wsdl'] = $this->getWSDLCache(); $options['features'] = $this->getSoapFeatures(); @@ -985,7 +984,7 @@ class Client implements ServerClient * @param int $oneWay * @return mixed */ - public function _doRequest(Client\Common $client, $request, $location,$action, $version, $oneWay = null) + public function _doRequest(Client\Common $client, $request, $location, $action, $version, $oneWay = null) { // Perform request as is if ($oneWay === null) { diff --git a/library/Zend/Soap/Server.php b/library/Zend/Soap/Server.php index dc111d86f..2349bf540 100644 --- a/library/Zend/Soap/Server.php +++ b/library/Zend/Soap/Server.php @@ -448,7 +448,10 @@ class Server implements ZendServerServer foreach ($typeMap as $type) { if (!is_callable($type['from_xml'])) { - throw new Exception\InvalidArgumentException('Invalid from_xml callback for type: ' . $type['type_name']); + throw new Exception\InvalidArgumentException(sprintf( + 'Invalid from_xml callback for type: %s', + $type['type_name'] + )); } if (!is_callable($type['to_xml'])) { throw new Exception\InvalidArgumentException('Invalid to_xml callback for type: ' . $type['type_name']); @@ -590,7 +593,9 @@ class Server implements ZendServerServer public function setClass($class, $namespace = '', $argv = null) { if (isset($this->class)) { - throw new Exception\InvalidArgumentException('A class has already been registered with this soap server instance'); + throw new Exception\InvalidArgumentException( + 'A class has already been registered with this soap server instance' + ); } if (is_object($class)) { @@ -785,7 +790,7 @@ class Server implements ZendServerServer */ public function setReturnResponse($flag = true) { - $this->returnResponse = ($flag) ? true : false; + $this->returnResponse = (bool) $flag; return $this; } @@ -914,7 +919,7 @@ class Server implements ZendServerServer // Restore original error handler restore_error_handler(); - ini_set('display_errors', $displayErrorsOriginalState); + ini_set('display_errors', (string) $displayErrorsOriginalState); // Send a fault, if we have one if ($fault instanceof SoapFault && !$this->returnResponse) { @@ -947,7 +952,7 @@ class Server implements ZendServerServer protected function _initializeSoapErrorContext() { $displayErrorsOriginalState = ini_get('display_errors'); - ini_set('display_errors', false); + ini_set('display_errors', '0'); set_error_handler(array($this, 'handlePhpErrors'), E_USER_ERROR); return $displayErrorsOriginalState; } @@ -976,14 +981,18 @@ class Server implements ZendServerServer foreach ($class as $row) { $this->registerFaultException($row); } - } elseif (is_string($class) && class_exists($class) && (is_subclass_of($class, 'Exception') || 'Exception' === $class)) { + } elseif (is_string($class) + && class_exists($class) + && (is_subclass_of($class, 'Exception') || 'Exception' === $class) + ) { $ref = new ReflectionClass($class); $this->faultExceptions[] = $ref->getName(); $this->faultExceptions = array_unique($this->faultExceptions); } else { throw new Exception\InvalidArgumentException( - 'Argument for Zend\Soap\Server::registerFaultException should be string or array of strings with valid exception names' + 'Argument for Zend\Soap\Server::registerFaultException should be' + . ' string or array of strings with valid exception names' ); } @@ -1075,7 +1084,14 @@ class Server implements ZendServerServer $message = 'Unknown error'; } - $allowedFaultModes = array('VersionMismatch', 'MustUnderstand', 'DataEncodingUnknown', 'Sender', 'Receiver', 'Server'); + $allowedFaultModes = array( + 'VersionMismatch', + 'MustUnderstand', + 'DataEncodingUnknown', + 'Sender', + 'Receiver', + 'Server' + ); if (!in_array($code, $allowedFaultModes)) { $code = 'Receiver'; } diff --git a/library/Zend/Soap/Wsdl.php b/library/Zend/Soap/Wsdl.php index a69416208..225d44a3e 100644 --- a/library/Zend/Soap/Wsdl.php +++ b/library/Zend/Soap/Wsdl.php @@ -713,7 +713,7 @@ class Wsdl return $this->classMap[$type]; } - $type = trim($type,'\\'); + $type = trim($type, '\\'); // remove namespace, $pos = strrpos($type, '\\'); @@ -795,11 +795,9 @@ class Wsdl case 'soapaction': case 'location': return $this->sanitizeUri($value); - break; default: return $value; - break; } } diff --git a/library/Zend/Soap/Wsdl/ComplexTypeStrategy/AbstractComplexTypeStrategy.php b/library/Zend/Soap/Wsdl/ComplexTypeStrategy/AbstractComplexTypeStrategy.php index bdce1f423..5babaeafd 100644 --- a/library/Zend/Soap/Wsdl/ComplexTypeStrategy/AbstractComplexTypeStrategy.php +++ b/library/Zend/Soap/Wsdl/ComplexTypeStrategy/AbstractComplexTypeStrategy.php @@ -54,6 +54,6 @@ abstract class AbstractComplexTypeStrategy implements ComplexTypeStrategyInterfa $soapTypes = $this->getContext()->getTypes(); return $soapTypes[$phpType]; } - return null; + return; } } diff --git a/library/Zend/Soap/composer.json b/library/Zend/Soap/composer.json index 53b0a87de..5ee4c9635 100644 --- a/library/Zend/Soap/composer.json +++ b/library/Zend/Soap/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Soap\\": "" } }, - "target-dir": "Zend/Soap", "require": { "php": ">=5.3.23", "zendframework/zend-server": "self.version", diff --git a/library/Zend/Stdlib/AbstractOptions.php b/library/Zend/Stdlib/AbstractOptions.php index 29a491f6a..aaa1dd299 100644 --- a/library/Zend/Stdlib/AbstractOptions.php +++ b/library/Zend/Stdlib/AbstractOptions.php @@ -100,7 +100,7 @@ abstract class AbstractOptions implements ParameterObjectInterface { $setter = 'set' . str_replace('_', '', $key); - if (method_exists($this, $setter)) { + if (is_callable(array($this, $setter))) { $this->{$setter}($value); return; @@ -108,9 +108,10 @@ abstract class AbstractOptions implements ParameterObjectInterface if ($this->__strictMode__) { throw new Exception\BadMethodCallException(sprintf( - 'The option "%s" does not have a matching "%s" setter method which must be defined', + 'The option "%s" does not have a callable "%s" ("%s") setter method which must be defined', $key, - 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))) + 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))), + $setter )); } } @@ -127,12 +128,12 @@ abstract class AbstractOptions implements ParameterObjectInterface { $getter = 'get' . str_replace('_', '', $key); - if (method_exists($this, $getter)) { + if (is_callable(array($this, $getter))) { return $this->{$getter}(); } throw new Exception\BadMethodCallException(sprintf( - 'The option "%s" does not have a matching "%s" getter method which must be defined', + 'The option "%s" does not have a callable "%s" getter method which must be defined', $key, 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))) )); @@ -146,7 +147,9 @@ abstract class AbstractOptions implements ParameterObjectInterface */ public function __isset($key) { - return null !== $this->__get($key); + $getter = 'get' . str_replace('_', '', $key); + + return method_exists($this, $getter) && null !== $this->__get($key); } /** diff --git a/library/Zend/Stdlib/ArrayUtils.php b/library/Zend/Stdlib/ArrayUtils.php index 8f77bc836..3545054ed 100644 --- a/library/Zend/Stdlib/ArrayUtils.php +++ b/library/Zend/Stdlib/ArrayUtils.php @@ -10,6 +10,8 @@ namespace Zend\Stdlib; use Traversable; +use Zend\Stdlib\ArrayUtils\MergeRemoveKey; +use Zend\Stdlib\ArrayUtils\MergeReplaceKeyInterface; /** * Utility class for testing and manipulation of PHP arrays. @@ -18,6 +20,16 @@ use Traversable; */ abstract class ArrayUtils { + /** + * Compatibility Flag for ArrayUtils::filter + */ + const ARRAY_FILTER_USE_BOTH = 1; + + /** + * Compatibility Flag for ArrayUtils::filter + */ + const ARRAY_FILTER_USE_KEY = 2; + /** * Test whether an array contains one or more string keys * @@ -257,8 +269,12 @@ abstract class ArrayUtils public static function merge(array $a, array $b, $preserveNumericKeys = false) { foreach ($b as $key => $value) { - if (isset($a[$key]) || array_key_exists($key, $a)) { - if (!$preserveNumericKeys && is_int($key)) { + if ($value instanceof MergeReplaceKeyInterface) { + $a[$key] = $value->getData(); + } elseif (isset($a[$key]) || array_key_exists($key, $a)) { + if ($value instanceof MergeRemoveKey) { + unset($a[$key]); + } elseif (!$preserveNumericKeys && is_int($key)) { $a[] = $value; } elseif (is_array($value) && is_array($a[$key])) { $a[$key] = static::merge($a[$key], $value, $preserveNumericKeys); @@ -266,10 +282,54 @@ abstract class ArrayUtils $a[$key] = $value; } } else { - $a[$key] = $value; + if (!$value instanceof MergeRemoveKey) { + $a[$key] = $value; + } } } return $a; } + + /** + * Compatibility Method for array_filter on <5.6 systems + * + * @param array $data + * @param callable $callback + * @param null|int $flag + * @return array + */ + public static function filter(array $data, $callback, $flag = null) + { + if (! is_callable($callback)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Second parameter of %s must be callable', + __METHOD__ + )); + } + + if (version_compare(PHP_VERSION, '5.6.0') >= 0) { + return array_filter($data, $callback, $flag); + } + + $output = array(); + foreach ($data as $key => $value) { + $params = array($value); + + if ($flag === static::ARRAY_FILTER_USE_BOTH) { + $params[] = $key; + } + + if ($flag === static::ARRAY_FILTER_USE_KEY) { + $params = array($key); + } + + $response = call_user_func_array($callback, $params); + if ($response) { + $output[$key] = $value; + } + } + + return $output; + } } diff --git a/library/Zend/Stdlib/ArrayUtils/MergeRemoveKey.php b/library/Zend/Stdlib/ArrayUtils/MergeRemoveKey.php new file mode 100644 index 000000000..7c4d097d9 --- /dev/null +++ b/library/Zend/Stdlib/ArrayUtils/MergeRemoveKey.php @@ -0,0 +1,14 @@ +data = $data; + } + + /** + * {@inheritDoc} + */ + public function getData() + { + return $this->data; + } +} diff --git a/library/Zend/Stdlib/ArrayUtils/MergeReplaceKeyInterface.php b/library/Zend/Stdlib/ArrayUtils/MergeReplaceKeyInterface.php new file mode 100644 index 000000000..725cf11bc --- /dev/null +++ b/library/Zend/Stdlib/ArrayUtils/MergeReplaceKeyInterface.php @@ -0,0 +1,21 @@ +metadata)) { return $this->metadata[$name]; } - return null; + return; } /** diff --git a/library/Zend/Stdlib/Hydrator/ClassMethods.php b/library/Zend/Stdlib/Hydrator/ClassMethods.php index 526a27640..4edb1f4dc 100644 --- a/library/Zend/Stdlib/Hydrator/ClassMethods.php +++ b/library/Zend/Stdlib/Hydrator/ClassMethods.php @@ -19,12 +19,30 @@ use Zend\Stdlib\Hydrator\Filter\HasFilter; use Zend\Stdlib\Hydrator\Filter\IsFilter; use Zend\Stdlib\Hydrator\Filter\MethodMatchFilter; use Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter; +use Zend\Stdlib\Hydrator\NamingStrategy\NamingStrategyInterface; use Zend\Stdlib\Hydrator\NamingStrategy\UnderscoreNamingStrategy; class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface { + /** + * Holds the names of the methods used for hydration, indexed by class::property name, + * false if the hydration method is not callable/usable for hydration purposes + * + * @var string[]|bool[] + */ + private $hydrationMethodsCache = array(); + + /** + * A map of extraction methods to property name to be used during extraction, indexed + * by class name and method name + * + * @var string[][] + */ + private $extractionMethodsCache = array(); + /** * Flag defining whether array keys are underscore-separated (true) or camel case (false) + * * @var bool */ protected $underscoreSeparatedKeys = true; @@ -109,50 +127,61 @@ class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface public function extract($object) { if (!is_object($object)) { - throw new Exception\BadMethodCallException( - sprintf('%s expects the provided $object to be a PHP object)', __METHOD__) - ); + throw new Exception\BadMethodCallException(sprintf( + '%s expects the provided $object to be a PHP object)', + __METHOD__ + )); } - $filter = null; + $objectClass = get_class($object); + + // reset the hydrator's hydrator's cache for this object, as the filter may be per-instance if ($object instanceof FilterProviderInterface) { - $filter = new FilterComposite( - array($object->getFilter()), - array(new MethodMatchFilter('getFilter')) - ); - } else { - $filter = $this->filterComposite; + $this->extractionMethodsCache[$objectClass] = null; } - $attributes = array(); - $methods = get_class_methods($object); + // pass 1 - finding out which properties can be extracted, with which methods (populate hydration cache) + if (! isset($this->extractionMethodsCache[$objectClass])) { + $this->extractionMethodsCache[$objectClass] = array(); + $filter = $this->filterComposite; + $methods = get_class_methods($object); - foreach ($methods as $method) { - if ( - !$filter->filter( - get_class($object) . '::' . $method - ) - ) { - continue; + if ($object instanceof FilterProviderInterface) { + $filter = new FilterComposite( + array($object->getFilter()), + array(new MethodMatchFilter('getFilter')) + ); } - if (!$this->callableMethodFilter->filter(get_class($object) . '::' . $method)) { - continue; - } + foreach ($methods as $method) { + $methodFqn = $objectClass . '::' . $method; - $attribute = $method; - if (preg_match('/^get/', $method)) { - $attribute = substr($method, 3); - if (!property_exists($object, $attribute)) { - $attribute = lcfirst($attribute); + if (! ($filter->filter($methodFqn) && $this->callableMethodFilter->filter($methodFqn))) { + continue; } - } - $attribute = $this->extractName($attribute, $object); - $attributes[$attribute] = $this->extractValue($attribute, $object->$method(), $object); + $attribute = $method; + + if (strpos($method, 'get') === 0) { + $attribute = substr($method, 3); + if (!property_exists($object, $attribute)) { + $attribute = lcfirst($attribute); + } + } + + $this->extractionMethodsCache[$objectClass][$method] = $attribute; + } } - return $attributes; + $values = array(); + + // pass 2 - actually extract data + foreach ($this->extractionMethodsCache[$objectClass] as $methodName => $attributeName) { + $realAttributeName = $this->extractName($attributeName, $object); + $values[$realAttributeName] = $this->extractValue($realAttributeName, $object->$methodName(), $object); + } + + return $values; } /** @@ -168,19 +197,78 @@ class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface public function hydrate(array $data, $object) { if (!is_object($object)) { - throw new Exception\BadMethodCallException( - sprintf('%s expects the provided $object to be a PHP object)', __METHOD__) - ); + throw new Exception\BadMethodCallException(sprintf( + '%s expects the provided $object to be a PHP object)', + __METHOD__ + )); } + $objectClass = get_class($object); + foreach ($data as $property => $value) { - $method = 'set' . ucfirst($this->hydrateName($property, $data)); - if (is_callable(array($object, $method))) { - $value = $this->hydrateValue($property, $value, $data); - $object->$method($value); + $propertyFqn = $objectClass . '::$' . $property; + + if (! isset($this->hydrationMethodsCache[$propertyFqn])) { + $setterName = 'set' . ucfirst($this->hydrateName($property, $data)); + + $this->hydrationMethodsCache[$propertyFqn] = is_callable(array($object, $setterName)) + ? $setterName + : false; + } + + if ($this->hydrationMethodsCache[$propertyFqn]) { + $object->{$this->hydrationMethodsCache[$propertyFqn]}($this->hydrateValue($property, $value, $data)); } } return $object; } + + /** + * {@inheritDoc} + */ + public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR) + { + $this->resetCaches(); + + return parent::addFilter($name, $filter, $condition); + } + + /** + * {@inheritDoc} + */ + public function removeFilter($name) + { + $this->resetCaches(); + + return parent::removeFilter($name); + } + + /** + * {@inheritDoc} + */ + public function setNamingStrategy(NamingStrategyInterface $strategy) + { + $this->resetCaches(); + + return parent::setNamingStrategy($strategy); + } + + /** + * {@inheritDoc} + */ + public function removeNamingStrategy() + { + $this->resetCaches(); + + return parent::removeNamingStrategy(); + } + + /** + * Reset all local hydration/extraction caches + */ + private function resetCaches() + { + $this->hydrationMethodsCache = $this->extractionMethodsCache = array(); + } } diff --git a/library/Zend/Stdlib/Hydrator/DelegatingHydrator.php b/library/Zend/Stdlib/Hydrator/DelegatingHydrator.php new file mode 100644 index 000000000..db234d38a --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/DelegatingHydrator.php @@ -0,0 +1,57 @@ +hydrators = $hydrators; + } + + /** + * {@inheritdoc} + */ + public function hydrate(array $data, $object) + { + return $this->getHydrator($object)->hydrate($data, $object); + } + + /** + * {@inheritdoc} + */ + public function extract($object) + { + return $this->getHydrator($object)->extract($object); + } + + /** + * Gets hydrator of an object + * + * @param object $object + * @return HydratorInterface + */ + protected function getHydrator($object) + { + return $this->hydrators->get(get_class($object)); + } +} diff --git a/library/Zend/Mvc/Service/ViewFeedRendererFactory.php b/library/Zend/Stdlib/Hydrator/DelegatingHydratorFactory.php similarity index 56% rename from library/Zend/Mvc/Service/ViewFeedRendererFactory.php rename to library/Zend/Stdlib/Hydrator/DelegatingHydratorFactory.php index 940478928..c3a0da25e 100644 --- a/library/Zend/Mvc/Service/ViewFeedRendererFactory.php +++ b/library/Zend/Stdlib/Hydrator/DelegatingHydratorFactory.php @@ -3,27 +3,27 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -namespace Zend\Mvc\Service; +namespace Zend\Stdlib\Hydrator; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; -use Zend\View\Renderer\FeedRenderer; -class ViewFeedRendererFactory implements FactoryInterface +class DelegatingHydratorFactory implements FactoryInterface { /** - * Create and return the feed view renderer + * Creates DelegatingHydrator * * @param ServiceLocatorInterface $serviceLocator - * @return FeedRenderer + * @return DelegatingHydrator */ public function createService(ServiceLocatorInterface $serviceLocator) { - $feedRenderer = new FeedRenderer(); - return $feedRenderer; + // Assume that this factory is registered with the HydratorManager, + // and just pass it directly on. + return new DelegatingHydrator($serviceLocator); } } diff --git a/library/Zend/Stdlib/Hydrator/Filter/MethodMatchFilter.php b/library/Zend/Stdlib/Hydrator/Filter/MethodMatchFilter.php index 5ed594ee7..2601a6fb3 100644 --- a/library/Zend/Stdlib/Hydrator/Filter/MethodMatchFilter.php +++ b/library/Zend/Stdlib/Hydrator/Filter/MethodMatchFilter.php @@ -41,8 +41,8 @@ class MethodMatchFilter implements FilterInterface $pos = 0; } if (substr($property, $pos) === $this->method) { - return $this->exclude ? false : true; + return !$this->exclude; } - return $this->exclude ? true : false; + return $this->exclude; } } diff --git a/library/Zend/Stdlib/Hydrator/HydratorPluginManager.php b/library/Zend/Stdlib/Hydrator/HydratorPluginManager.php index 347cce323..1b238e7cc 100644 --- a/library/Zend/Stdlib/Hydrator/HydratorPluginManager.php +++ b/library/Zend/Stdlib/Hydrator/HydratorPluginManager.php @@ -26,6 +26,15 @@ class HydratorPluginManager extends AbstractPluginManager */ protected $shareByDefault = false; + /** + * Default aliases + * + * @var array + */ + protected $aliases = array( + 'delegatinghydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydrator', + ); + /** * Default set of adapters * @@ -38,6 +47,15 @@ class HydratorPluginManager extends AbstractPluginManager 'reflection' => 'Zend\Stdlib\Hydrator\Reflection' ); + /** + * Default factory-based adapters + * + * @var array + */ + protected $factories = array( + 'Zend\Stdlib\Hydrator\DelegatingHydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydratorFactory', + ); + /** * {@inheritDoc} */ diff --git a/library/Zend/Stdlib/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php b/library/Zend/Stdlib/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php new file mode 100644 index 000000000..962303ae1 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php @@ -0,0 +1,51 @@ +extractionMap = $extractionMap; + $this->hydrationMap = array_flip($extractionMap); + } + + /** + * {@inheritDoc} + */ + public function hydrate($name) + { + return isset($this->hydrationMap[$name]) ? $this->hydrationMap[$name] : $name; + } + + /** + * {@inheritDoc} + */ + public function extract($name) + { + return isset($this->extractionMap[$name]) ? $this->extractionMap[$name] : $name; + } +} diff --git a/library/Zend/Stdlib/Hydrator/NamingStrategy/CompositeNamingStrategy.php b/library/Zend/Stdlib/Hydrator/NamingStrategy/CompositeNamingStrategy.php new file mode 100644 index 000000000..0887e9288 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/NamingStrategy/CompositeNamingStrategy.php @@ -0,0 +1,64 @@ +namingStrategies = array_map( + function (NamingStrategyInterface $strategy) { + // this callback is here only to ensure type-safety + return $strategy; + }, + $strategies + ); + + $this->defaultNamingStrategy = $defaultNamingStrategy ?: new IdentityNamingStrategy(); + } + + /** + * {@inheritDoc} + */ + public function extract($name) + { + $strategy = isset($this->namingStrategies[$name]) + ? $this->namingStrategies[$name] + : $this->defaultNamingStrategy; + + return $strategy->extract($name); + } + + /** + * {@inheritDoc} + */ + public function hydrate($name) + { + $strategy = isset($this->namingStrategies[$name]) + ? $this->namingStrategies[$name] + : $this->defaultNamingStrategy; + + return $strategy->hydrate($name); + } +} diff --git a/library/Zend/Stdlib/Hydrator/NamingStrategy/IdentityNamingStrategy.php b/library/Zend/Stdlib/Hydrator/NamingStrategy/IdentityNamingStrategy.php new file mode 100644 index 000000000..ee4b328d3 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/NamingStrategy/IdentityNamingStrategy.php @@ -0,0 +1,29 @@ +mapping = $mapping; + $this->reverse = $reverse ?: $this->flipMapping($mapping); + } + + /** + * Safelly flip mapping array. + * + * @param array $array Array to flip + * @return array Flipped array + * @throws InvalidArgumentException + */ + protected function flipMapping(array $array) + { + array_walk($array, function ($value) { + if (!is_string($value) && !is_int($value)) { + throw new InvalidArgumentException('Mapping array can\'t be flipped because of invalid value'); + } + }); + + return array_flip($array); + } + + /** + * Converts the given name so that it can be extracted by the hydrator. + * + * @param string $name The original name + * @return mixed The hydrated name + */ + public function hydrate($name) + { + if (array_key_exists($name, $this->mapping)) { + return $this->mapping[$name]; + } + + return $name; + } + + /** + * Converts the given name so that it can be hydrated by the hydrator. + * + * @param string $name The original name + * @return mixed The extracted name + */ + public function extract($name) + { + if (array_key_exists($name, $this->reverse)) { + return $this->reverse[$name]; + } + + return $name; + } +} diff --git a/library/Zend/Stdlib/Hydrator/NamingStrategy/UnderscoreNamingStrategy.php b/library/Zend/Stdlib/Hydrator/NamingStrategy/UnderscoreNamingStrategy.php index e76e7b04f..023b4eec7 100644 --- a/library/Zend/Stdlib/Hydrator/NamingStrategy/UnderscoreNamingStrategy.php +++ b/library/Zend/Stdlib/Hydrator/NamingStrategy/UnderscoreNamingStrategy.php @@ -13,9 +13,15 @@ use Zend\Filter\FilterChain; class UnderscoreNamingStrategy implements NamingStrategyInterface { + /** + * @var FilterChain|null + */ protected static $camelCaseToUnderscoreFilter; - protected static $underscoreToCamelCaseFilter; + /** + * @var FilterChain|null + */ + protected static $underscoreToStudlyCaseFilter; /** * Remove underscores and capitalize letters @@ -25,7 +31,7 @@ class UnderscoreNamingStrategy implements NamingStrategyInterface */ public function hydrate($name) { - return lcfirst($this->getUnderscoreToCamelCaseFilter()->filter($name)); + return $this->getUnderscoreToStudlyCaseFilter()->filter($name); } /** @@ -42,16 +48,17 @@ class UnderscoreNamingStrategy implements NamingStrategyInterface /** * @return FilterChain */ - protected function getUnderscoreToCamelCaseFilter() + protected function getUnderscoreToStudlyCaseFilter() { - if (static::$underscoreToCamelCaseFilter instanceof FilterChain) { - return static::$underscoreToCamelCaseFilter; + if (static::$underscoreToStudlyCaseFilter instanceof FilterChain) { + return static::$underscoreToStudlyCaseFilter; } $filter = new FilterChain(); - $filter->attachByName('WordUnderscoreToCamelCase'); - static::$underscoreToCamelCaseFilter = $filter; - return $filter; + + $filter->attachByName('WordUnderscoreToStudlyCase'); + + return static::$underscoreToStudlyCaseFilter = $filter; } /** @@ -64,9 +71,10 @@ class UnderscoreNamingStrategy implements NamingStrategyInterface } $filter = new FilterChain(); + $filter->attachByName('WordCamelCaseToUnderscore'); $filter->attachByName('StringToLower'); - static::$camelCaseToUnderscoreFilter = $filter; - return $filter; + + return static::$camelCaseToUnderscoreFilter = $filter; } } diff --git a/library/Zend/Stdlib/Hydrator/Strategy/BooleanStrategy.php b/library/Zend/Stdlib/Hydrator/Strategy/BooleanStrategy.php new file mode 100644 index 000000000..3c29231f3 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/Strategy/BooleanStrategy.php @@ -0,0 +1,106 @@ +trueValue = $trueValue; + $this->falseValue = $falseValue; + } + + /** + * Converts the given value so that it can be extracted by the hydrator. + * + * @param bool $value The original value. + * @throws InvalidArgumentException + * @return int|string Returns the value that should be extracted. + */ + public function extract($value) + { + if (!is_bool($value)) { + throw new InvalidArgumentException(sprintf( + 'Unable to extract. Expected bool. %s was given.', + is_object($value) ? get_class($value) : gettype($value) + )); + } + + return $value === true ? $this->trueValue : $this->falseValue; + } + + /** + * Converts the given value so that it can be hydrated by the hydrator. + * + * @param int|string $value The original value. + * @throws InvalidArgumentException + * @return bool Returns the value that should be hydrated. + */ + public function hydrate($value) + { + if (!is_string($value) && !is_int($value)) { + throw new InvalidArgumentException(sprintf( + 'Unable to hydrate. Expected string or int. %s was given.', + is_object($value) ? get_class($value) : gettype($value) + )); + } + + if ($value === $this->trueValue) { + return true; + } + + if ($value === $this->falseValue) { + return false; + } + + throw new InvalidArgumentException(sprintf( + 'Unexpected value %s can\'t be hydrated. Expect %s or %s as Value.', + $value, + $this->trueValue, + $this->falseValue + )); + } +} diff --git a/library/Zend/Stdlib/Hydrator/Strategy/DateTimeFormatterStrategy.php b/library/Zend/Stdlib/Hydrator/Strategy/DateTimeFormatterStrategy.php new file mode 100644 index 000000000..62d92c588 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/Strategy/DateTimeFormatterStrategy.php @@ -0,0 +1,80 @@ +format = (string) $format; + $this->timezone = $timezone; + } + + /** + * {@inheritDoc} + * + * Converts to date time string + * + * @param mixed|DateTime $value + * + * @return mixed|string + */ + public function extract($value) + { + if ($value instanceof DateTime) { + return $value->format($this->format); + } + + return $value; + } + + /** + * Converts date time string to DateTime instance for injecting to object + * + * {@inheritDoc} + * + * @param mixed|string $value + * + * @return mixed|DateTime + */ + public function hydrate($value) + { + if ($value === '' || $value === null) { + return; + } + + if ($this->timezone) { + $hydrated = DateTime::createFromFormat($this->format, $value, $this->timezone); + } else { + $hydrated = DateTime::createFromFormat($this->format, $value); + } + + return $hydrated ?: $value; + } +} diff --git a/library/Zend/Stdlib/Hydrator/Strategy/Exception/ExceptionInterface.php b/library/Zend/Stdlib/Hydrator/Strategy/Exception/ExceptionInterface.php new file mode 100644 index 000000000..c7b576ce3 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/Strategy/Exception/ExceptionInterface.php @@ -0,0 +1,14 @@ +setValueDelimiter($delimiter); + + $this->explodeLimit = ($explodeLimit === null) ? null : (int) $explodeLimit; + } + + /** + * Sets the delimiter string that the values will be split upon + * + * @param string $delimiter + * @return self + */ + private function setValueDelimiter($delimiter) + { + if (!is_string($delimiter)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects Delimiter to be string, %s provided instead', + __METHOD__, + is_object($delimiter) ? get_class($delimiter) : gettype($delimiter) + )); + } + + if (empty($delimiter)) { + throw new Exception\InvalidArgumentException('Delimiter cannot be empty.'); + } + + $this->valueDelimiter = $delimiter; + } + + /** + * {@inheritDoc} + * + * Split a string by delimiter + * + * @param string|null $value + * + * @return string[] + * + * @throws Exception\InvalidArgumentException + */ + public function hydrate($value) + { + if (null === $value) { + return array(); + } + + if (!(is_string($value) || is_numeric($value))) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects argument 1 to be string, %s provided instead', + __METHOD__, + is_object($value) ? get_class($value) : gettype($value) + )); + } + + if ($this->explodeLimit !== null) { + return explode($this->valueDelimiter, $value, $this->explodeLimit); + } + + return explode($this->valueDelimiter, $value); + } + + /** + * {@inheritDoc} + * + * Join array elements with delimiter + * + * @param string[] $value The original value. + * + * @return string|null + */ + public function extract($value) + { + if (!is_array($value)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects argument 1 to be array, %s provided instead', + __METHOD__, + is_object($value) ? get_class($value) : gettype($value) + )); + } + + return empty($value) ? null : implode($this->valueDelimiter, $value); + } +} diff --git a/library/Zend/Stdlib/Hydrator/Strategy/StrategyChain.php b/library/Zend/Stdlib/Hydrator/Strategy/StrategyChain.php new file mode 100644 index 000000000..a9316bbd7 --- /dev/null +++ b/library/Zend/Stdlib/Hydrator/Strategy/StrategyChain.php @@ -0,0 +1,73 @@ +extractionStrategies = array_map( + function (StrategyInterface $strategy) { + // this callback is here only to ensure type-safety + return $strategy; + }, + $extractionStrategies + ); + + $this->hydrationStrategies = array_reverse($extractionStrategies); + } + + /** + * {@inheritDoc} + */ + public function extract($value) + { + foreach ($this->extractionStrategies as $strategy) { + $value = $strategy->extract($value); + } + + return $value; + } + + /** + * {@inheritDoc} + */ + public function hydrate($value) + { + foreach ($this->hydrationStrategies as $strategy) { + $value = $strategy->hydrate($value); + } + + return $value; + } +} diff --git a/library/Zend/Stdlib/Parameters.php b/library/Zend/Stdlib/Parameters.php index f59197cbe..bef834a8a 100644 --- a/library/Zend/Stdlib/Parameters.php +++ b/library/Zend/Stdlib/Parameters.php @@ -86,7 +86,7 @@ class Parameters extends PhpArrayObject implements ParametersInterface if ($this->offsetExists($name)) { return parent::offsetGet($name); } - return null; + return; } /** diff --git a/library/Zend/Stdlib/PriorityList.php b/library/Zend/Stdlib/PriorityList.php index ba206a958..172af68d8 100644 --- a/library/Zend/Stdlib/PriorityList.php +++ b/library/Zend/Stdlib/PriorityList.php @@ -129,7 +129,7 @@ class PriorityList implements Iterator, Countable public function get($name) { if (!isset($this->items[$name])) { - return null; + return; } return $this->items[$name]['data']; @@ -197,6 +197,7 @@ class PriorityList implements Iterator, Countable */ public function current() { + $this->sorted || $this->sort(); $node = current($this->items); return $node ? $node['data'] : false; @@ -207,6 +208,7 @@ class PriorityList implements Iterator, Countable */ public function key() { + $this->sorted || $this->sort(); return key($this->items); } @@ -228,6 +230,14 @@ class PriorityList implements Iterator, Countable return current($this->items) !== false; } + /** + * @return self + */ + public function getIterator() + { + return clone $this; + } + /** * {@inheritDoc} */ diff --git a/library/Zend/Stdlib/PriorityQueue.php b/library/Zend/Stdlib/PriorityQueue.php index 81acaf59f..1baf44e89 100644 --- a/library/Zend/Stdlib/PriorityQueue.php +++ b/library/Zend/Stdlib/PriorityQueue.php @@ -208,7 +208,6 @@ class PriorityQueue implements Countable, IteratorAggregate, Serializable switch ($flag) { case self::EXTR_BOTH: return $this->items; - break; case self::EXTR_PRIORITY: return array_map(function ($item) { return $item['priority']; diff --git a/library/Zend/Stdlib/composer.json b/library/Zend/Stdlib/composer.json index 642622704..dfe178bf9 100644 --- a/library/Zend/Stdlib/composer.json +++ b/library/Zend/Stdlib/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Stdlib\\": "" } }, - "target-dir": "Zend/Stdlib", "require": { "php": ">=5.3.23" }, diff --git a/library/Zend/Tag/Item.php b/library/Zend/Tag/Item.php index 96c2ea5a6..479d5d47b 100644 --- a/library/Zend/Tag/Item.php +++ b/library/Zend/Tag/Item.php @@ -189,6 +189,6 @@ class Item implements TaggableInterface if (isset($this->params[$name])) { return $this->params[$name]; } - return null; + return; } } diff --git a/library/Zend/Tag/composer.json b/library/Zend/Tag/composer.json index baaa1e739..6b20f108d 100644 --- a/library/Zend/Tag/composer.json +++ b/library/Zend/Tag/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Tag\\": "" } }, - "target-dir": "Zend/Tag", "require": { "php": ">=5.3.23", "zendframework/zend-escaper": "self.version", diff --git a/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php b/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php index cccf5203d..a47e1dab8 100644 --- a/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php +++ b/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php @@ -48,7 +48,7 @@ abstract class AbstractControllerTestCase extends PHPUnit_Framework_TestCase * Trace error when exception is throwed in application * @var bool */ - protected $traceError = false; + protected $traceError = true; /** * Reset the application for isolation @@ -230,14 +230,14 @@ abstract class AbstractControllerTestCase extends PHPUnit_Framework_TestCase } } elseif ($method == HttpRequest::METHOD_GET) { $query = array_merge($query, $params); - } elseif ($method == HttpRequest::METHOD_PUT) { + } elseif ($method == HttpRequest::METHOD_PUT || $method == HttpRequest::METHOD_PATCH) { if (count($params) != 0) { $content = http_build_query($params); $request->setContent($content); } } elseif ($params) { trigger_error( - 'Additional params is only supported by GET, POST and PUT HTTP method', + 'Additional params is only supported by GET, POST, PUT and PATCH HTTP method', E_USER_NOTICE ); } diff --git a/library/Zend/Test/PHPUnit/Controller/AbstractHttpControllerTestCase.php b/library/Zend/Test/PHPUnit/Controller/AbstractHttpControllerTestCase.php index 0c7414754..2120ce875 100644 --- a/library/Zend/Test/PHPUnit/Controller/AbstractHttpControllerTestCase.php +++ b/library/Zend/Test/PHPUnit/Controller/AbstractHttpControllerTestCase.php @@ -686,22 +686,30 @@ abstract class AbstractHttpControllerTestCase extends AbstractControllerTestCase private function queryContentContainsAssertion($path, $match, $useXpath = false) { $result = $this->query($path, $useXpath); + if ($result->count() == 0) { throw new PHPUnit_Framework_ExpectationFailedException(sprintf( 'Failed asserting node DENOTED BY %s EXISTS', $path )); } + + $nodeValues = array(); + foreach ($result as $node) { if ($node->nodeValue == $match) { $this->assertEquals($match, $node->nodeValue); return; } + + $nodeValues[] = $node->nodeValue; } + throw new PHPUnit_Framework_ExpectationFailedException(sprintf( - 'Failed asserting node denoted by %s CONTAINS content "%s"', + 'Failed asserting node denoted by %s CONTAINS content "%s", Contents: [%s]', $path, - $match + $match, + implode(',', $nodeValues) )); } diff --git a/library/Zend/Test/composer.json b/library/Zend/Test/composer.json index f107cefb8..488c451cd 100644 --- a/library/Zend/Test/composer.json +++ b/library/Zend/Test/composer.json @@ -8,14 +8,13 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Test\\": "" } }, - "target-dir": "Zend/Test", "require": { "php": ">=5.3.23", - "phpunit/PHPUnit": "3.7.*", + "phpunit/PHPUnit": "~4.0", "zendframework/zend-console": "self.version", "zendframework/zend-dom": "self.version", "zendframework/zend-eventmanager": "self.version", diff --git a/library/Zend/Text/Figlet/Figlet.php b/library/Zend/Text/Figlet/Figlet.php index 98161e86d..5bf9b54fe 100644 --- a/library/Zend/Text/Figlet/Figlet.php +++ b/library/Zend/Text/Figlet/Figlet.php @@ -831,12 +831,12 @@ class Figlet if ($this->previousCharWidth < 2 || $this->currentCharWidth < 2) { // Disallows overlapping if the previous character or the current // character has a width of one or zero. - return null; + return; } if (($this->smushMode & self::SM_SMUSH) === 0) { // Kerning - return null; + return; } if (($this->smushMode & 63) === 0) { @@ -864,7 +864,7 @@ class Figlet } if ($leftChar === $this->hardBlank && $rightChar === $this->hardBlank) { - return null; + return; } if (($this->smushMode & self::SM_EQUAL) > 0) { @@ -931,7 +931,7 @@ class Figlet } } - return null; + return; } /** @@ -978,8 +978,9 @@ class Figlet $magic = $this->_readMagic($fp); // Get the header + $line = fgets($fp, 1000) ?: ''; $numsRead = sscanf( - fgets($fp, 1000), + $line, '%*c%c %d %*d %d %d %d %d %d', $this->hardBlank, $this->charHeight, @@ -1057,7 +1058,13 @@ class Figlet // At the end fetch all extended characters while (!feof($fp)) { // Get the Unicode - list($uniCode) = explode(' ', fgets($fp, 2048)); + $uniCode = fgets($fp, 2048); + + if (false === $uniCode) { + continue; + } + + list($uniCode) = explode(' ', $uniCode); if (empty($uniCode)) { continue; diff --git a/library/Zend/Text/Figlet/zend-framework.flf b/library/Zend/Text/Figlet/zend-framework.flf index 5d7445cf4..8b4ddc8be 100644 --- a/library/Zend/Text/Figlet/zend-framework.flf +++ b/library/Zend/Text/Figlet/zend-framework.flf @@ -17,7 +17,7 @@ Version: 1.0 obtain it through the world-wide-web, please send an email to license@zend.com so we can send you a copy immediately. - Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) ------------------------------------------------------------------------------- diff --git a/library/Zend/Text/Table/Row.php b/library/Zend/Text/Table/Row.php index 21dfbbf02..b0c0936f1 100644 --- a/library/Zend/Text/Table/Row.php +++ b/library/Zend/Text/Table/Row.php @@ -78,7 +78,7 @@ class Row public function getColumn($index) { if (!isset($this->columns[$index])) { - return null; + return; } return $this->columns[$index]; diff --git a/library/Zend/Text/composer.json b/library/Zend/Text/composer.json index 7f7cafb7f..2fd1684f2 100644 --- a/library/Zend/Text/composer.json +++ b/library/Zend/Text/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Text\\": "" } }, - "target-dir": "Zend/Text", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version", diff --git a/library/Zend/Uri/Http.php b/library/Zend/Uri/Http.php index 9c10a1df6..6095e497e 100644 --- a/library/Zend/Uri/Http.php +++ b/library/Zend/Uri/Http.php @@ -47,59 +47,49 @@ class Http extends Uri */ protected $password; - /** - * Check if the URI is a valid HTTP URI - * - * This applies additional HTTP specific validation rules beyond the ones - * required by the generic URI syntax - * - * @return bool - * @see Uri::isValid() - */ - public function isValid() - { - return parent::isValid(); - } - /** * Get the username part (before the ':') of the userInfo URI part * - * @return null|string + * @return string|null */ public function getUser() { - if (null !== $this->user) { - return $this->user; - } - - $this->parseUserInfo(); return $this->user; } /** * Get the password part (after the ':') of the userInfo URI part * - * @return string + * @return string|null */ public function getPassword() { - if (null !== $this->password) { - return $this->password; - } - - $this->parseUserInfo(); return $this->password; } + /** + * Get the User-info (usually user:password) part + * + * @return string|null + */ + public function getUserInfo() + { + return $this->userInfo; + } + /** * Set the username part (before the ':') of the userInfo URI part * - * @param string $user - * @return Http + * @param string|null $user + * + * @return self */ public function setUser($user) { - $this->user = $user; + $this->user = null === $user ? null : (string) $user; + + $this->buildUserInfo(); + return $this; } @@ -107,11 +97,33 @@ class Http extends Uri * Set the password part (after the ':') of the userInfo URI part * * @param string $password - * @return Http + * + * @return self */ public function setPassword($password) { - $this->password = $password; + $this->password = null === $password ? null : (string) $password; + + $this->buildUserInfo(); + + return $this; + } + + /** + * Set the URI User-info part (usually user:password) + * + * @param string|null $userInfo + * + * @return self + * + * @throws Exception\InvalidUriPartException If the schema definition does not have this part + */ + public function setUserInfo($userInfo) + { + $this->userInfo = null === $userInfo ? null : (string) $userInfo; + + $this->parseUserInfo(); + return $this; } @@ -142,19 +154,37 @@ class Http extends Uri { // No user information? we're done if (null === $this->userInfo) { + $this->setUser(null); + $this->setPassword(null); + return; } // If no ':' separator, we only have a username if (false === strpos($this->userInfo, ':')) { $this->setUser($this->userInfo); + $this->setPassword(null); return; } // Split on the ':', and set both user and password - list($user, $password) = explode(':', $this->userInfo, 2); - $this->setUser($user); - $this->setPassword($password); + list($this->user, $this->password) = explode(':', $this->userInfo, 2); + } + + /** + * Build the user info based on user and password + * + * Builds the user info based on the given user and password values + * + * @return void + */ + protected function buildUserInfo() + { + if (null !== $this->password) { + $this->userInfo = $this->user . ':' . $this->password; + } else { + $this->userInfo = $this->user; + } } /** diff --git a/library/Zend/Uri/Uri.php b/library/Zend/Uri/Uri.php index f6ab7f175..bbb7eb5c5 100644 --- a/library/Zend/Uri/Uri.php +++ b/library/Zend/Uri/Uri.php @@ -36,18 +36,18 @@ class Uri implements UriInterface * Place 1 or 0 in the different positions for enable or disable the part. * Finally use a hexadecimal representation. */ - const HOST_IPV4 = 0x01; //00001 - const HOST_IPV6 = 0x02; //00010 - const HOST_IPVFUTURE = 0x04; //00100 - const HOST_IPVANY = 0x07; //00111 - const HOST_DNS = 0x08; //01000 - const HOST_DNS_OR_IPV4 = 0x09; //01001 - const HOST_DNS_OR_IPV6 = 0x0A; //01010 - const HOST_DNS_OR_IPV4_OR_IPV6 = 0x0B; //01011 - const HOST_DNS_OR_IPVANY = 0x0F; //01111 - const HOST_REGNAME = 0x10; //10000 - const HOST_DNS_OR_IPV4_OR_IPV6_OR_REGNAME = 0x13; //10011 - const HOST_ALL = 0x1F; //11111 + const HOST_IPV4 = 0x01; //00001 + const HOST_IPV6 = 0x02; //00010 + const HOST_IPVFUTURE = 0x04; //00100 + const HOST_IPVANY = 0x07; //00111 + const HOST_DNS = 0x08; //01000 + const HOST_DNS_OR_IPV4 = 0x09; //01001 + const HOST_DNS_OR_IPV6 = 0x0A; //01010 + const HOST_DNS_OR_IPV4_OR_IPV6 = 0x0B; //01011 + const HOST_DNS_OR_IPVANY = 0x0F; //01111 + const HOST_REGNAME = 0x10; //10000 + const HOST_DNS_OR_IPV4_OR_IPV6_OR_REGNAME = 0x1B; //11011 + const HOST_ALL = 0x1F; //11111 /** * URI scheme @@ -284,7 +284,7 @@ class Uri implements UriInterface // Capture scheme if (($scheme = self::parseScheme($uri)) !== null) { $this->setScheme($scheme); - $uri = substr($uri, strlen($scheme) + 1); + $uri = substr($uri, strlen($scheme) + 1) ?: ''; } // Capture authority part @@ -507,7 +507,6 @@ class Uri implements UriInterface return $this; } - /** * Convert the link to a relative link by substracting a base URI * @@ -1073,7 +1072,7 @@ class Uri implements UriInterface return $match[1]; } - return null; + return; } /** @@ -1102,11 +1101,19 @@ class Uri implements UriInterface break; case ($path == '/..'): $path = '/'; - $output = substr($output, 0, strrpos($output, '/', -1)); + $lastSlashPos = strrpos($output, '/', -1); + if (false === $lastSlashPos) { + break; + } + $output = substr($output, 0, $lastSlashPos); break; case (substr($path, 0, 4) == '/../'): $path = '/' . substr($path, 4); - $output = substr($output, 0, strrpos($output, '/', -1)); + $lastSlashPos = strrpos($output, '/', -1); + if (false === $lastSlashPos) { + break; + } + $output = substr($output, 0, $lastSlashPos); break; case (substr($path, 0, 3) == '/./'): $path = substr($path, 2); @@ -1265,7 +1272,7 @@ class Uri implements UriInterface && isset(static::$defaultPorts[$scheme]) && ($port == static::$defaultPorts[$scheme]) ) { - return null; + return; } return $port; diff --git a/library/Zend/Uri/UriFactory.php b/library/Zend/Uri/UriFactory.php index f2b4b1df4..3641cdb28 100644 --- a/library/Zend/Uri/UriFactory.php +++ b/library/Zend/Uri/UriFactory.php @@ -9,7 +9,6 @@ namespace Zend\Uri; - /** * URI Factory Class * @@ -75,7 +74,7 @@ abstract class UriFactory return static::$schemeClasses[$scheme]; } - return null; + return; } /** @@ -111,11 +110,13 @@ abstract class UriFactory $class = static::$schemeClasses[$scheme]; $uri = new $class($uri); if (! $uri instanceof UriInterface) { - throw new Exception\InvalidArgumentException(sprintf( - 'class "%s" registered for scheme "%s" does not implement Zend\Uri\UriInterface', - $class, - $scheme - )); + throw new Exception\InvalidArgumentException( + sprintf( + 'class "%s" registered for scheme "%s" does not implement Zend\Uri\UriInterface', + $class, + $scheme + ) + ); } } diff --git a/library/Zend/Uri/UriInterface.php b/library/Zend/Uri/UriInterface.php index 040a894c2..6f13f6782 100644 --- a/library/Zend/Uri/UriInterface.php +++ b/library/Zend/Uri/UriInterface.php @@ -76,8 +76,6 @@ interface UriInterface */ public function normalize(); - - /** * Convert the link to a relative link by substracting a base URI * diff --git a/library/Zend/Uri/composer.json b/library/Zend/Uri/composer.json index 536ae1b59..1d4001446 100644 --- a/library/Zend/Uri/composer.json +++ b/library/Zend/Uri/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Uri\\": "" } }, - "target-dir": "Zend/Uri", "require": { "php": ">=5.3.23", "zendframework/zend-escaper": "self.version", diff --git a/library/Zend/Validator/AbstractValidator.php b/library/Zend/Validator/AbstractValidator.php index 79d9c0f56..93af2cab4 100644 --- a/library/Zend/Validator/AbstractValidator.php +++ b/library/Zend/Validator/AbstractValidator.php @@ -279,7 +279,7 @@ abstract class AbstractValidator implements protected function createMessage($messageKey, $value) { if (!isset($this->abstractOptions['messageTemplates'][$messageKey])) { - return null; + return; } $message = $this->abstractOptions['messageTemplates'][$messageKey]; @@ -410,7 +410,7 @@ abstract class AbstractValidator implements public function getTranslator() { if (! $this->isTranslatorEnabled()) { - return null; + return; } if (null === $this->abstractOptions['translator']) { diff --git a/library/Zend/Validator/Barcode/AbstractAdapter.php b/library/Zend/Validator/Barcode/AbstractAdapter.php index 7cca59a19..a2842d849 100644 --- a/library/Zend/Validator/Barcode/AbstractAdapter.php +++ b/library/Zend/Validator/Barcode/AbstractAdapter.php @@ -53,10 +53,10 @@ abstract class AbstractAdapter implements AdapterInterface $found = true; } elseif ($length == 'even') { $count = $fixum % 2; - $found = ($count == 0) ? true : false; + $found = (0 == $count); } elseif ($length == 'odd') { $count = $fixum % 2; - $found = ($count == 1) ? true : false; + $found = (1 == $count); } return $found; diff --git a/library/Zend/Validator/Barcode/Code128.php b/library/Zend/Validator/Barcode/Code128.php index b8e3ee2d3..06a0b5e60 100644 --- a/library/Zend/Validator/Barcode/Code128.php +++ b/library/Zend/Validator/Barcode/Code128.php @@ -37,13 +37,13 @@ class Code128 extends AbstractAdapter 32 => '@', 33 => 'A', 34 => 'B', 35 => 'C', 36 => 'D', 37 => 'E', 38 => 'F', 39 => 'G', 40 => 'H', 41 => 'I', 42 => 'J', 43 => 'K', 44 => 'L', 45 => 'M', 46 => 'N', 47 => 'O', 48 => 'P', 49 => 'Q', 50 => 'R', 51 => 'S', 52 => 'T', 53 => 'U', 54 => 'V', 55 => 'W', - 56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\',61 => ']', 62 => '^', 63 => '_', + 56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\', 61 => ']', 62 => '^', 63 => '_', 64 =>0x00, 65 =>0x01, 66 =>0x02, 67 =>0x03, 68 =>0x04, 69 =>0x05, 70 =>0x06, 71 =>0x07, 72 =>0x08, 73 =>0x09, 74 =>0x0A, 75 =>0x0B, 76 =>0x0C, 77 =>0x0D, 78 =>0x0E, 79 =>0x0F, 80 =>0x10, 81 =>0x11, 82 =>0x12, 83 =>0x13, 84 =>0x14, 85 =>0x15, 86 =>0x16, 87 =>0x17, 88 =>0x18, 89 =>0x19, 90 =>0x1A, 91 =>0x1B, 92 =>0x1C, 93 =>0x1D, 94 =>0x1E, 95 =>0x1F, - 96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â',100 => 'ä',101 => 'à',102 => 'å',103 => '‡', - 104 => 'ˆ',105 => '‰',106 => 'Š'), + 96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', + 104 => 'ˆ', 105 => '‰', 106 => 'Š'), 'B' => array( 0 => ' ', 1 => '!', 2 => '"', 3 => '#', 4 => '$', 5 => '%', 6 => '&', 7 => "'", 8 => '(', 9 => ')', 10 => '*', 11 => '+', 12 => ',', 13 => '-', 14 => '.', 15 => '/', @@ -52,13 +52,13 @@ class Code128 extends AbstractAdapter 32 => '@', 33 => 'A', 34 => 'B', 35 => 'C', 36 => 'D', 37 => 'E', 38 => 'F', 39 => 'G', 40 => 'H', 41 => 'I', 42 => 'J', 43 => 'K', 44 => 'L', 45 => 'M', 46 => 'N', 47 => 'O', 48 => 'P', 49 => 'Q', 50 => 'R', 51 => 'S', 52 => 'T', 53 => 'U', 54 => 'V', 55 => 'W', - 56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\',61 => ']', 62 => '^', 63 => '_', + 56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\', 61 => ']', 62 => '^', 63 => '_', 64 => '`', 65 => 'a', 66 => 'b', 67 => 'c', 68 => 'd', 69 => 'e', 70 => 'f', 71 => 'g', 72 => 'h', 73 => 'i', 74 => 'j', 75 => 'k', 76 => 'l', 77 => 'm', 78 => 'n', 79 => 'o', 80 => 'p', 81 => 'q', 82 => 'r', 83 => 's', 84 => 't', 85 => 'u', 86 => 'v', 87 => 'w', 88 => 'x', 89 => 'y', 90 => 'z', 91 => '{', 92 => '|', 93 => '}', 94 => '~', 95 =>0x7F, - 96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â',100 => 'ä',101 => 'à',102 => 'å',103 => '‡', - 104 => 'ˆ',105 => '‰',106 => 'Š'), + 96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', + 104 => 'ˆ', 105 => '‰', 106 => 'Š'), 'C' => array( 0 => '00', 1 => '01', 2 => '02', 3 => '03', 4 => '04', 5 => '05', 6 => '06', 7 => '07', 8 => '08', 9 => '09', 10 => '10', 11 => '11', 12 => '12', 13 => '13', 14 => '14', 15 => '15', @@ -72,7 +72,7 @@ class Code128 extends AbstractAdapter 72 => '72', 73 => '73', 74 => '74', 75 => '75', 76 => '76', 77 => '77', 78 => '78', 79 => '79', 80 => '80', 81 => '81', 82 => '82', 83 => '83', 84 => '84', 85 => '85', 86 => '86', 87 => '87', 88 => '88', 89 => '89', 90 => '90', 91 => '91', 92 => '92', 93 => '93', 94 => '94', 95 => '95', - 96 => '96', 97 => '97', 98 => '98', 99 => '99',100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', + 96 => '96', 97 => '97', 98 => '98', 99 => '99', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡', 104 => 'ˆ', 105 => '‰', 106 => 'Š') )); $this->setChecksum('code128'); @@ -166,7 +166,6 @@ class Code128 extends AbstractAdapter case 'ˆ': case '‰': return false; - break; // Chars after the stop character case 'Š': diff --git a/library/Zend/Validator/Between.php b/library/Zend/Validator/Between.php index 550ee72d7..28101538b 100644 --- a/library/Zend/Validator/Between.php +++ b/library/Zend/Validator/Between.php @@ -56,6 +56,8 @@ class Between extends AbstractValidator * 'inclusive' => boolean, inclusive border values * * @param array|Traversable $options + * + * @throws Exception\InvalidArgumentException */ public function __construct($options = null) { @@ -76,8 +78,10 @@ class Between extends AbstractValidator $options = $temp; } - if (!array_key_exists('min', $options) || !array_key_exists('max', $options)) { - // throw new Exception\InvalidArgumentException("Missing option. 'min' and 'max' has to be given"); + if (count($options) !== 2 + && (!array_key_exists('min', $options) || !array_key_exists('max', $options)) + ) { + throw new Exception\InvalidArgumentException("Missing option. 'min' and 'max' have to be given"); } parent::__construct($options); diff --git a/library/Zend/Validator/Csrf.php b/library/Zend/Validator/Csrf.php index 49af145db..ef64ee3c1 100644 --- a/library/Zend/Validator/Csrf.php +++ b/library/Zend/Validator/Csrf.php @@ -121,7 +121,10 @@ class Csrf extends AbstractValidator $tokenId = $this->getTokenIdFromHash($value); $hash = $this->getValidationToken($tokenId); - if ($this->getTokenFromHash($value) !== $this->getTokenFromHash($hash)) { + $tokenFromValue = $this->getTokenFromHash($value); + $tokenFromHash = $this->getTokenFromHash($hash); + + if (!$tokenFromValue || !$tokenFromHash || ($tokenFromValue !== $tokenFromHash)) { $this->error(self::NOT_SAME); return false; } @@ -331,7 +334,7 @@ class Csrf extends AbstractValidator return $this->formatHash($session->tokenList[$tokenId], $tokenId); } - return null; + return; } /** @@ -363,7 +366,7 @@ class Csrf extends AbstractValidator $data = explode('-', $hash); if (! isset($data[1])) { - return null; + return; } return $data[1]; diff --git a/library/Zend/Validator/Date.php b/library/Zend/Validator/Date.php index 456bde8b1..105e33e1a 100644 --- a/library/Zend/Validator/Date.php +++ b/library/Zend/Validator/Date.php @@ -10,6 +10,7 @@ namespace Zend\Validator; use DateTime; +use DateTimeInterface; use Traversable; /** @@ -55,7 +56,6 @@ class Date extends AbstractValidator */ protected $format = self::FORMAT_DEFAULT; - /** * Sets validator options * @@ -127,12 +127,13 @@ class Date extends AbstractValidator */ protected function convertToDateTime($param, $addErrors = true) { - if ($param instanceof DateTime) { + // @TODO: when minimum dependency will be PHP 5.5, we can only keep check against DateTimeInterface + if ($param instanceof DateTime || $param instanceof DateTimeInterface) { return $param; } $type = gettype($param); - if (!in_array($type, array('string', 'integer', 'array'))) { + if (!in_array($type, array('string', 'integer', 'double', 'array'))) { if ($addErrors) { $this->error(self::INVALID); } @@ -154,6 +155,17 @@ class Date extends AbstractValidator return date_create("@$value"); } + /** + * Attempts to convert an double into a DateTime object + * + * @param double $value + * @return bool|DateTime + */ + protected function convertDouble($value) + { + return DateTime::createFromFormat('U', $value); + } + /** * Attempts to convert a string into a DateTime object * diff --git a/library/Zend/Validator/DateStep.php b/library/Zend/Validator/DateStep.php index 83c64505b..67465d34e 100644 --- a/library/Zend/Validator/DateStep.php +++ b/library/Zend/Validator/DateStep.php @@ -215,8 +215,11 @@ class DateStep extends Date $unitKeys = array('years', 'months', 'days', 'hours', 'minutes', 'seconds'); $intervalParts = array_combine($unitKeys, $intervalParts); - // Get absolute time difference - $timeDiff = $valueDate->diff($baseDate, true); + // Get absolute time difference to avoid special cases of missing/added time + $absoluteValueDate = new DateTime($valueDate->format('Y-m-d H:i:s'), new DateTimeZone('UTC')); + $absoluteBaseDate = new DateTime($baseDate->format('Y-m-d H:i:s'), new DateTimeZone('UTC')); + + $timeDiff = $absoluteValueDate->diff($absoluteBaseDate, 1); $diffParts = array_combine($unitKeys, explode('|', $timeDiff->format('%y|%m|%d|%h|%i|%s'))); if (5 === $partCounts["0"]) { diff --git a/library/Zend/Validator/EmailAddress.php b/library/Zend/Validator/EmailAddress.php index a20d99996..c12368665 100644 --- a/library/Zend/Validator/EmailAddress.php +++ b/library/Zend/Validator/EmailAddress.php @@ -334,7 +334,7 @@ class EmailAddress extends AbstractValidator // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*", // "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~" $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e'; - if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->localPart)) { + if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->idnToAscii($this->localPart))) { $result = true; } else { // Try quoted string format (RFC 5321 Chapter 4.1.2) @@ -373,7 +373,7 @@ class EmailAddress extends AbstractValidator { $mxHosts = array(); $weight = array(); - $result = getmxrr($this->hostname, $mxHosts, $weight); + $result = getmxrr($this->idnToAscii($this->hostname), $mxHosts, $weight); if (!empty($mxHosts) && !empty($weight)) { $this->mxRecord = array_combine($mxHosts, $weight); } else { @@ -457,9 +457,12 @@ class EmailAddress extends AbstractValidator */ protected function splitEmailParts($value) { + $value = is_string($value) ? $value : ''; + // Split email address up and disallow '..' - if ((strpos($value, '..') !== false) or - (!preg_match('/^(.+)@([^@]+)$/', $value, $matches))) { + if (strpos($value, '..') !== false + || ! preg_match('/^(.+)@([^@]+)$/', $value, $matches) + ) { return false; } @@ -488,10 +491,10 @@ class EmailAddress extends AbstractValidator } $length = true; - $this->setValue($value); + $this->setValue($this->idnToUtf8($value)); // Split email address up and disallow '..' - if (!$this->splitEmailParts($value)) { + if (!$this->splitEmailParts($this->getValue())) { $this->error(self::INVALID_FORMAT); return false; } @@ -517,4 +520,30 @@ class EmailAddress extends AbstractValidator return false; } + + /** + * Safely convert UTF-8 encoded domain name to ASCII + * @param string $email the UTF-8 encoded email + * @return string + */ + protected function idnToAscii($email) + { + if (extension_loaded('intl')) { + return (idn_to_ascii($email) ?: $email); + } + return $email; + } + + /** + * Safely convert ASCII encoded domain name to UTF-8 + * @param string $email the ASCII encoded email + * @return string + */ + protected function idnToUtf8($email) + { + if (extension_loaded('intl')) { + return idn_to_utf8($email); + } + return $email; + } } diff --git a/library/Zend/Validator/Explode.php b/library/Zend/Validator/Explode.php index 13b3b019c..54177ec29 100644 --- a/library/Zend/Validator/Explode.php +++ b/library/Zend/Validator/Explode.php @@ -159,10 +159,11 @@ class Explode extends AbstractValidator implements ValidatorPluginManagerAwareIn * Returns true if all values validate true * * @param mixed $value + * @param mixed $context Extra "context" to provide the composed validator * @return bool * @throws Exception\RuntimeException */ - public function isValid($value) + public function isValid($value, $context = null) { $this->setValue($value); @@ -195,7 +196,7 @@ class Explode extends AbstractValidator implements ValidatorPluginManagerAwareIn } foreach ($values as $value) { - if (!$validator->isValid($value)) { + if (!$validator->isValid($value, $context)) { $this->abstractOptions['messages'][] = $validator->getMessages(); if ($this->isBreakOnFirstFailure()) { diff --git a/library/Zend/Validator/File/Count.php b/library/Zend/Validator/File/Count.php index a4ce28e00..6a6ba3763 100644 --- a/library/Zend/Validator/File/Count.php +++ b/library/Zend/Validator/File/Count.php @@ -122,7 +122,7 @@ class Count extends AbstractValidator $min = (int) $min; if (($this->getMax() !== null) && ($min > $this->getMax())) { throw new Exception\InvalidArgumentException( - "The minimum must be less than or equal to the maximum file count, but $min > {$this->getMax()}" + "The minimum must be less than or equal to the maximum file count, but {$min} > {$this->getMax()}" ); } @@ -160,7 +160,7 @@ class Count extends AbstractValidator $max = (int) $max; if (($this->getMin() !== null) && ($max < $this->getMin())) { throw new Exception\InvalidArgumentException( - "The maximum must be greater than or equal to the minimum file count, but $max < {$this->getMin()}" + "The maximum must be greater than or equal to the minimum file count, but {$max} < {$this->getMin()}" ); } diff --git a/library/Zend/Validator/File/FilesSize.php b/library/Zend/Validator/File/FilesSize.php index a31011174..c1ea7644d 100644 --- a/library/Zend/Validator/File/FilesSize.php +++ b/library/Zend/Validator/File/FilesSize.php @@ -89,12 +89,24 @@ class FilesSize extends Size { if (is_string($value)) { $value = array($value); + } elseif (is_array($value) && isset($value['tmp_name'])) { + $value = array($value); } $min = $this->getMin(true); $max = $this->getMax(true); $size = $this->getSize(); foreach ($value as $files) { + if (is_array($files)) { + if (!isset($files['tmp_name']) || !isset($files['name'])) { + throw new Exception\InvalidArgumentException( + 'Value array must be in $_FILES format' + ); + } + $file = $files; + $files = $files['tmp_name']; + } + // Is file readable ? if (empty($files) || false === stream_resolve_include_path($files)) { $this->throwError($file, self::NOT_READABLE); diff --git a/library/Zend/Validator/Hostname.php b/library/Zend/Validator/Hostname.php index 95abee9e9..3306fb874 100644 --- a/library/Zend/Validator/Hostname.php +++ b/library/Zend/Validator/Hostname.php @@ -73,6 +73,7 @@ class Hostname extends AbstractValidator * @var array */ protected $validTlds = array( + 'abbott', 'abogado', 'ac', 'academy', @@ -80,6 +81,7 @@ class Hostname extends AbstractValidator 'active', 'actor', 'ad', + 'adult', 'ae', 'aero', 'af', @@ -91,10 +93,13 @@ class Hostname extends AbstractValidator 'allfinanz', 'alsace', 'am', + 'amsterdam', 'an', 'android', 'ao', + 'apartments', 'aq', + 'aquarelle', 'ar', 'archi', 'army', @@ -114,7 +119,10 @@ class Hostname extends AbstractValidator 'az', 'ba', 'band', + 'bank', 'bar', + 'barclaycard', + 'barclays', 'bargains', 'bayern', 'bb', @@ -129,6 +137,7 @@ class Hostname extends AbstractValidator 'bi', 'bid', 'bike', + 'bingo', 'bio', 'biz', 'bj', @@ -141,6 +150,7 @@ class Hostname extends AbstractValidator 'bn', 'bnpparibas', 'bo', + 'boats', 'boo', 'boutique', 'br', @@ -163,6 +173,7 @@ class Hostname extends AbstractValidator 'camera', 'camp', 'cancerresearch', + 'canon', 'capetown', 'capital', 'caravan', @@ -170,20 +181,26 @@ class Hostname extends AbstractValidator 'care', 'career', 'careers', + 'cartier', 'casa', 'cash', + 'casino', 'cat', 'catering', + 'cbn', 'cc', 'cd', 'center', 'ceo', 'cern', 'cf', + 'cfd', 'cg', 'ch', 'channel', + 'chat', 'cheap', + 'chloe', 'christmas', 'chrome', 'church', @@ -218,6 +235,7 @@ class Hostname extends AbstractValidator 'cool', 'coop', 'country', + 'courses', 'cr', 'credit', 'creditcard', @@ -232,10 +250,13 @@ class Hostname extends AbstractValidator 'cy', 'cymru', 'cz', + 'dabur', 'dad', 'dance', 'dating', + 'datsun', 'day', + 'dclk', 'de', 'deals', 'degree', @@ -244,6 +265,8 @@ class Hostname extends AbstractValidator 'dental', 'dentist', 'desi', + 'design', + 'dev', 'diamonds', 'diet', 'digital', @@ -255,7 +278,9 @@ class Hostname extends AbstractValidator 'dm', 'dnp', 'do', + 'docs', 'domains', + 'doosan', 'durban', 'dvag', 'dz', @@ -271,13 +296,16 @@ class Hostname extends AbstractValidator 'engineer', 'engineering', 'enterprises', + 'epson', 'equipment', 'er', + 'erni', 'es', 'esq', 'estate', 'et', 'eu', + 'eurovision', 'eus', 'events', 'everbank', @@ -285,7 +313,10 @@ class Hostname extends AbstractValidator 'expert', 'exposed', 'fail', + 'fan', + 'fans', 'farm', + 'fashion', 'feedback', 'fi', 'finance', @@ -293,16 +324,20 @@ class Hostname extends AbstractValidator 'firmdale', 'fish', 'fishing', + 'fit', 'fitness', 'fj', 'fk', 'flights', 'florist', + 'flowers', 'flsmidth', 'fly', 'fm', 'fo', 'foo', + 'football', + 'forex', 'forsale', 'foundation', 'fr', @@ -314,13 +349,16 @@ class Hostname extends AbstractValidator 'ga', 'gal', 'gallery', + 'garden', 'gb', 'gbiz', 'gd', + 'gdn', 'ge', 'gent', 'gf', 'gg', + 'ggee', 'gh', 'gi', 'gift', @@ -336,6 +374,9 @@ class Hostname extends AbstractValidator 'gmo', 'gmx', 'gn', + 'goldpoint', + 'goo', + 'goog', 'google', 'gop', 'gov', @@ -355,10 +396,12 @@ class Hostname extends AbstractValidator 'gw', 'gy', 'hamburg', + 'hangout', 'haus', 'healthcare', 'help', 'here', + 'hermes', 'hiphop', 'hiv', 'hk', @@ -378,12 +421,14 @@ class Hostname extends AbstractValidator 'ibm', 'id', 'ie', + 'ifm', 'il', 'im', 'immo', 'immobilien', 'in', 'industries', + 'infiniti', 'info', 'ing', 'ink', @@ -395,8 +440,12 @@ class Hostname extends AbstractValidator 'io', 'iq', 'ir', + 'irish', 'is', 'it', + 'iwc', + 'java', + 'jcb', 'je', 'jetzt', 'jm', @@ -406,6 +455,7 @@ class Hostname extends AbstractValidator 'jp', 'juegos', 'kaufen', + 'kddi', 'ke', 'kg', 'kh', @@ -422,18 +472,23 @@ class Hostname extends AbstractValidator 'kred', 'kw', 'ky', + 'kyoto', 'kz', 'la', 'lacaixa', 'land', + 'lat', + 'latrobe', 'lawyer', 'lb', 'lc', 'lds', 'lease', + 'leclerc', 'legal', 'lgbt', 'li', + 'lidl', 'life', 'lighting', 'limited', @@ -442,6 +497,7 @@ class Hostname extends AbstractValidator 'lk', 'loans', 'london', + 'lotte', 'lotto', 'lr', 'ls', @@ -454,11 +510,14 @@ class Hostname extends AbstractValidator 'ly', 'ma', 'madrid', + 'maif', 'maison', 'management', 'mango', 'market', 'marketing', + 'markets', + 'marriott', 'mc', 'md', 'me', @@ -493,6 +552,7 @@ class Hostname extends AbstractValidator 'mr', 'ms', 'mt', + 'mtpc', 'mu', 'museum', 'mv', @@ -516,26 +576,34 @@ class Hostname extends AbstractValidator 'ngo', 'nhk', 'ni', + 'nico', 'ninja', + 'nissan', 'nl', 'no', 'np', 'nr', 'nra', 'nrw', + 'ntt', 'nu', 'nyc', 'nz', 'okinawa', 'om', + 'one', 'ong', 'onl', + 'online', 'ooo', + 'oracle', 'org', 'organic', + 'osaka', 'otsuka', 'ovh', 'pa', + 'page', 'paris', 'partners', 'parts', @@ -549,7 +617,9 @@ class Hostname extends AbstractValidator 'photography', 'photos', 'physio', + 'piaget', 'pics', + 'pictet', 'pictures', 'pink', 'pizza', @@ -561,6 +631,7 @@ class Hostname extends AbstractValidator 'pn', 'pohl', 'poker', + 'porn', 'post', 'pr', 'praxi', @@ -609,27 +680,36 @@ class Hostname extends AbstractValidator 'ryukyu', 'sa', 'saarland', + 'sale', + 'samsung', 'sarl', + 'saxo', 'sb', 'sc', 'sca', 'scb', 'schmidt', + 'school', 'schule', + 'schwarz', 'science', 'scot', 'sd', 'se', 'services', + 'sew', 'sexy', 'sg', 'sh', 'shiksha', 'shoes', + 'shriram', 'si', 'singles', + 'site', 'sj', 'sk', + 'sky', 'sl', 'sm', 'sn', @@ -642,9 +722,13 @@ class Hostname extends AbstractValidator 'soy', 'space', 'spiegel', + 'spreadbetting', 'sr', 'st', + 'study', + 'style', 'su', + 'sucks', 'supplies', 'supply', 'support', @@ -665,11 +749,14 @@ class Hostname extends AbstractValidator 'td', 'technology', 'tel', + 'temasek', + 'tennis', 'tf', 'tg', 'th', 'tienda', 'tips', + 'tires', 'tirol', 'tj', 'tk', @@ -681,13 +768,15 @@ class Hostname extends AbstractValidator 'tokyo', 'tools', 'top', + 'toshiba', 'town', 'toys', - 'tp', 'tr', 'trade', + 'trading', 'training', 'travel', + 'trust', 'tt', 'tui', 'tv', @@ -713,6 +802,7 @@ class Hostname extends AbstractValidator 'vg', 'vi', 'viajes', + 'video', 'villas', 'vision', 'vlaanderen', @@ -742,80 +832,94 @@ class Hostname extends AbstractValidator 'ws', 'wtc', 'wtf', - '测试', - 'परीक्षा', + 'xin', + '佛山', '集团', '在线', '한국', 'ভারত', - 'বাংলা', + '八卦', + 'موقع', '公益', '公司', '移动', '我爱你', - 'испытание', + 'москва', 'қаз', 'онлайн', 'сайт', 'срб', - '테스트', + 'бел', + '淡马锡', + 'орг', '삼성', 'சிங்கப்பூர்', + '商标', + '商店', + '商城', 'дети', - 'טעסט', + 'мкд', '中文网', '中信', '中国', '中國', + '谷歌', 'భారత్', 'ලංකා', - '測試', 'ભારત', 'भारत', - 'آزمایشی', - 'பரிட்சை', + '网店', + 'संगठन', '网络', 'укр', '香港', - 'δοκιμή', - 'إختبار', '台湾', '台灣', + '手机', 'мон', - 'الجزا', + 'الجزائر', 'عمان', 'ایران', 'امارات', 'بازار', - 'پاکستا', 'الاردن', 'بھارت', 'المغرب', 'السعودية', - 'سودان', 'مليسيا', + '政府', 'شبكة', 'გე', + '机构', + '组织机构', 'ไทย', 'سورية', + 'рус', 'рф', 'تونس', 'みんな', + 'グーグル', + '世界', 'ਭਾਰਤ', + '网址', '游戏', + 'vermögensberater', + 'vermögensberatung', + '企业', 'مصر', 'قطر', + '广东', 'இலங்கை', 'இந்தியா', '新加坡', 'فلسطين', - 'テスト', '政务', 'xxx', 'xyz', 'yachts', 'yandex', 'ye', + 'yodobashi', 'yoga', 'yokohama', 'youtube', @@ -824,7 +928,8 @@ class Hostname extends AbstractValidator 'zip', 'zm', 'zone', - 'zw' + 'zuerich', + 'zw', ); /** @@ -843,6 +948,7 @@ class Hostname extends AbstractValidator * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151 + * (.EE) Estonia https://www.iana.org/domains/idn-tables/tables/pl_et-pl_1.0.html * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp @@ -894,6 +1000,7 @@ class Hostname extends AbstractValidator 'COM' => 'Hostname/Com.php', 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), 'DK' => array(1 => '/^[\x{002d}0-9a-zäéöü]{1,63}$/iu'), + 'EE' => array(1 => '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu'), 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'), 'EU' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', @@ -1347,7 +1454,6 @@ class Hostname extends AbstractValidator } } elseif ($this->getAllow() & self::ALLOW_DNS) { $this->error(self::INVALID_HOSTNAME); - $status = false; } // Check for URI Syntax (RFC3986) diff --git a/library/Zend/Validator/Identical.php b/library/Zend/Validator/Identical.php index cbd19158e..ca0efb87e 100644 --- a/library/Zend/Validator/Identical.php +++ b/library/Zend/Validator/Identical.php @@ -9,6 +9,7 @@ namespace Zend\Validator; +use ArrayAccess; use Traversable; use Zend\Stdlib\ArrayUtils; @@ -146,17 +147,25 @@ class Identical extends AbstractValidator * matches that token. * * @param mixed $value - * @param array $context + * @param array|ArrayAccess $context + * @throws Exception\InvalidArgumentException If context is not array or ArrayObject * @return bool - * @throws Exception\RuntimeException if the token doesn't exist in the context array */ - public function isValid($value, array $context = null) + public function isValid($value, $context = null) { $this->setValue($value); $token = $this->getToken(); if (!$this->getLiteral() && $context !== null) { + if (!is_array($context) && !($context instanceof ArrayAccess)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Context passed to %s must be array, ArrayObject or null; received "%s"', + __METHOD__, + is_object($context) ? get_class($context) : gettype($context) + )); + } + if (is_array($token)) { while (is_array($token)) { $key = key($token); diff --git a/library/Zend/Validator/InArray.php b/library/Zend/Validator/InArray.php index f2ac33af3..be271ea0f 100644 --- a/library/Zend/Validator/InArray.php +++ b/library/Zend/Validator/InArray.php @@ -35,7 +35,6 @@ class InArray extends AbstractValidator */ const COMPARE_NOT_STRICT = -1; - /** * @var array */ @@ -111,7 +110,7 @@ class InArray extends AbstractValidator /** * Sets the strict option mode - * InArray::CHECK_STRICT | InArray::CHECK_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY | InArray::CHECK_NOT_STRICT + * InArray::COMPARE_STRICT | InArray::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY | InArray::COMPARE_NOT_STRICT * * @param int $strict * @return InArray Provides a fluent interface @@ -218,7 +217,7 @@ class InArray extends AbstractValidator } } - if (in_array($value, $haystack, $this->strict == self::COMPARE_STRICT ? true : false)) { + if (in_array($value, $haystack, self::COMPARE_STRICT == $this->strict)) { return true; } } diff --git a/library/Zend/Validator/Isbn.php b/library/Zend/Validator/Isbn.php index 48ef5b102..00f7324b8 100644 --- a/library/Zend/Validator/Isbn.php +++ b/library/Zend/Validator/Isbn.php @@ -80,7 +80,7 @@ class Isbn extends AbstractValidator } } - return null; + return; } /** diff --git a/library/Zend/Validator/Step.php b/library/Zend/Validator/Step.php index 84a2b252d..b9e9e1ad9 100644 --- a/library/Zend/Validator/Step.php +++ b/library/Zend/Validator/Step.php @@ -146,7 +146,9 @@ class Step extends AbstractValidator } //find the maximum precision from both input params to give accurate results - $precision = strlen(substr($x, strpos($x, '.')+1)) + strlen(substr($y, strpos($y, '.')+1)); + $xFloatSegment = substr($x, strpos($x, '.') + 1) ?: ''; + $yFloatSegment = substr($y, strpos($y, '.') + 1) ?: ''; + $precision = strlen($xFloatSegment) + strlen($yFloatSegment); return round($x - $y * floor($x / $y), $precision); } diff --git a/library/Zend/Validator/StringLength.php b/library/Zend/Validator/StringLength.php index 1e0b9bcb6..b07a6c31e 100644 --- a/library/Zend/Validator/StringLength.php +++ b/library/Zend/Validator/StringLength.php @@ -88,7 +88,7 @@ class StringLength extends AbstractValidator { if (null !== $this->getMax() && $min > $this->getMax()) { throw new Exception\InvalidArgumentException( - "The minimum must be less than or equal to the maximum length, but $min >" . " " . $this->getMax() + "The minimum must be less than or equal to the maximum length, but {$min} > {$this->getMax()}" ); } @@ -119,7 +119,7 @@ class StringLength extends AbstractValidator $this->options['max'] = null; } elseif ($max < $this->getMin()) { throw new Exception\InvalidArgumentException( - "The maximum must be greater than or equal to the minimum length, but $max < " . $this->getMin() + "The maximum must be greater than or equal to the minimum length, but {$max} < {$this->getMin()}" ); } else { $this->options['max'] = (int) $max; diff --git a/library/Zend/Validator/Timezone.php b/library/Zend/Validator/Timezone.php new file mode 100644 index 000000000..dd1ab7ebc --- /dev/null +++ b/library/Zend/Validator/Timezone.php @@ -0,0 +1,174 @@ + 'location', + self::ABBREVIATION => 'abbreviation', + ); + + /** + * Default value for types; value = 3 + * + * @var array + */ + protected $defaultType = array( + self::LOCATION, + self::ABBREVIATION, + ); + + /** + * @var array + */ + protected $messageTemplates = array( + self::INVALID => 'Invalid timezone given.', + self::INVALID_TIMEZONE_LOCATION => 'Invalid timezone location given.', + self::INVALID_TIMEZONE_ABBREVIATION => 'Invalid timezone abbreviation given.', + ); + + /** + * Options for this validator + * + * @var array + */ + protected $options = array(); + + /** + * Constructor + * + * @param array|int $options OPTIONAL + */ + public function __construct($options = array()) + { + $opts['type'] = $this->defaultType; + + if (is_array($options)) { + if (array_key_exists('type', $options)) { + $opts['type'] = $options['type']; + } + } elseif (! empty($options)) { + $opts['type'] = $options; + } + + // setType called by parent constructor then setOptions method + parent::__construct($opts); + } + + /** + * Set the types + * + * @param int|array $type + * + * @throws Exception\InvalidArgumentException + */ + public function setType($type = null) + { + $type = $this->calculateTypeValue($type); + + if (!is_int($type) || ($type < 1) || ($type > self::ALL)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Unknown type "%s" provided', + (is_string($type) || is_int($type)) + ? $type + : (is_object($type) ? get_class($type) : gettype($type)) + )); + } + + $this->options['type'] = $type; + } + + /** + * Returns true if timezone location or timezone abbreviations is correct. + * + * @param mixed $value + * @return bool + */ + public function isValid($value) + { + if ($value !== null && !is_string($value)) { + $this->error(self::INVALID); + return false; + } + + $type = $this->options['type']; + $this->setValue($value); + + switch (true) { + // Check in locations and abbreviations + case (($type & self::LOCATION) && ($type & self::ABBREVIATION)): + $abbrs = DateTimeZone::listAbbreviations(); + $locations = DateTimeZone::listIdentifiers(); + + if (!array_key_exists($value, $abbrs) && !in_array($value, $locations)) { + $this->error(self::INVALID); + return false; + } + break; + + // Check only in locations + case ($type & self::LOCATION): + $locations = DateTimeZone::listIdentifiers(); + + if (!in_array($value, $locations)) { + $this->error(self::INVALID_TIMEZONE_LOCATION); + return false; + } + break; + + // Check only in abbreviations + case ($type & self::ABBREVIATION): + $abbrs = DateTimeZone::listAbbreviations(); + + if (!array_key_exists($value, $abbrs)) { + $this->error(self::INVALID_TIMEZONE_ABBREVIATION); + return false; + } + break; + } + + return true; + } + + /** + * @param array|int|string $type + * + * @return int + */ + protected function calculateTypeValue($type) + { + $types = (array) $type; + $detected = 0; + + foreach ($types as $value) { + if (is_int($value)) { + $detected |= $value; + } elseif (false !== ($position = array_search($value, $this->constants))) { + $detected |= array_search($value, $this->constants); + } + } + + return $detected; + } +} diff --git a/library/Zend/Validator/ValidatorChain.php b/library/Zend/Validator/ValidatorChain.php index a3b8c5b84..604afbfbe 100644 --- a/library/Zend/Validator/ValidatorChain.php +++ b/library/Zend/Validator/ValidatorChain.php @@ -10,11 +10,17 @@ namespace Zend\Validator; use Countable; +use Zend\Stdlib\PriorityQueue; class ValidatorChain implements Countable, ValidatorInterface { + /** + * Default priority at which validators are added + */ + const DEFAULT_PRIORITY = 1; + /** * @var ValidatorPluginManager */ @@ -23,9 +29,9 @@ class ValidatorChain implements /** * Validator chain * - * @var array + * @var PriorityQueue */ - protected $validators = array(); + protected $validators; /** * Array of validation failure messages @@ -34,6 +40,14 @@ class ValidatorChain implements */ protected $messages = array(); + /** + * Initialize validator chain + */ + public function __construct() + { + $this->validators = new PriorityQueue(); + } + /** * Return the count of attached validators * @@ -88,16 +102,28 @@ class ValidatorChain implements * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain, * if one exists, will not be executed. * - * @param ValidatorInterface $validator - * @param bool $breakChainOnFailure - * @return ValidatorChain Provides a fluent interface + * @param ValidatorInterface $validator + * @param bool $breakChainOnFailure + * @param int $priority Priority at which to enqueue validator; defaults to + * 1 (higher executes earlier) + * + * @throws Exception\InvalidArgumentException + * + * @return self */ - public function attach(ValidatorInterface $validator, $breakChainOnFailure = false) - { - $this->validators[] = array( - 'instance' => $validator, - 'breakChainOnFailure' => (bool) $breakChainOnFailure, + public function attach( + ValidatorInterface $validator, + $breakChainOnFailure = false, + $priority = self::DEFAULT_PRIORITY + ) { + $this->validators->insert( + array( + 'instance' => $validator, + 'breakChainOnFailure' => (bool) $breakChainOnFailure, + ), + $priority ); + return $this; } @@ -107,11 +133,12 @@ class ValidatorChain implements * @deprecated Please use attach() * @param ValidatorInterface $validator * @param bool $breakChainOnFailure + * @param int $priority * @return ValidatorChain Provides a fluent interface */ - public function addValidator(ValidatorInterface $validator, $breakChainOnFailure = false) + public function addValidator(ValidatorInterface $validator, $breakChainOnFailure = false, $priority = self::DEFAULT_PRIORITY) { - return $this->attach($validator, $breakChainOnFailure); + return $this->attach($validator, $breakChainOnFailure, $priority); } /** @@ -126,12 +153,21 @@ class ValidatorChain implements */ public function prependValidator(ValidatorInterface $validator, $breakChainOnFailure = false) { - array_unshift( - $this->validators, + $priority = self::DEFAULT_PRIORITY; + + if (!$this->validators->isEmpty()) { + $queue = $this->validators->getIterator(); + $queue->setExtractFlags(PriorityQueue::EXTR_PRIORITY); + $extractedNode = $queue->extract(); + $priority = $extractedNode[0] + 1; + } + + $this->validators->insert( array( - 'instance' => $validator, - 'breakChainOnFailure' => (bool) $breakChainOnFailure, - ) + 'instance' => $validator, + 'breakChainOnFailure' => (bool) $breakChainOnFailure, + ), + $priority ); return $this; } @@ -140,11 +176,12 @@ class ValidatorChain implements * Use the plugin manager to add a validator by name * * @param string $name - * @param array $options - * @param bool $breakChainOnFailure + * @param array $options + * @param bool $breakChainOnFailure + * @param int $priority * @return ValidatorChain */ - public function attachByName($name, $options = array(), $breakChainOnFailure = false) + public function attachByName($name, $options = array(), $breakChainOnFailure = false, $priority = self::DEFAULT_PRIORITY) { if (isset($options['break_chain_on_failure'])) { $breakChainOnFailure = (bool) $options['break_chain_on_failure']; @@ -154,8 +191,8 @@ class ValidatorChain implements $breakChainOnFailure = (bool) $options['breakchainonfailure']; } - $validator = $this->plugin($name, $options); - $this->attach($validator, $breakChainOnFailure); + $this->attach($this->plugin($name, $options), $breakChainOnFailure, $priority); + return $this; } @@ -224,8 +261,8 @@ class ValidatorChain implements */ public function merge(ValidatorChain $validatorChain) { - foreach ($validatorChain->validators as $validator) { - $this->validators[] = $validator; + foreach ($validatorChain->validators->toArray(PriorityQueue::EXTR_BOTH) as $item) { + $this->attach($item['data']['instance'], $item['data']['breakChainOnFailure'], $item['priority']); } return $this; @@ -244,11 +281,11 @@ class ValidatorChain implements /** * Get all the validators * - * @return array + * @return PriorityQueue */ public function getValidators() { - return $this->validators; + return $this->validators->toArray(PriorityQueue::EXTR_DATA); } /** @@ -262,6 +299,14 @@ class ValidatorChain implements return $this->isValid($value); } + /** + * Deep clone handling + */ + public function __clone() + { + $this->validators = clone $this->validators; + } + /** * Prepare validator chain for serialization * diff --git a/library/Zend/Validator/ValidatorPluginManager.php b/library/Zend/Validator/ValidatorPluginManager.php index e16a76377..90a5c7ab3 100644 --- a/library/Zend/Validator/ValidatorPluginManager.php +++ b/library/Zend/Validator/ValidatorPluginManager.php @@ -14,6 +14,16 @@ use Zend\ServiceManager\ConfigInterface; class ValidatorPluginManager extends AbstractPluginManager { + /** + * Default aliases + * + * @var array + */ + protected $aliases = array( + 'Zend\I18n\Validator\Float'=> 'Zend\I18n\Validator\IsFloat', + 'Zend\I18n\Validator\Int' => 'Zend\I18n\Validator\IsInt', + ); + /** * Default set of validators * @@ -82,17 +92,20 @@ class ValidatorPluginManager extends AbstractPluginManager 'fileupload' => 'Zend\Validator\File\Upload', 'fileuploadfile' => 'Zend\Validator\File\UploadFile', 'filewordcount' => 'Zend\Validator\File\WordCount', - 'float' => 'Zend\I18n\Validator\Float', + 'float' => 'Zend\I18n\Validator\IsFloat', 'greaterthan' => 'Zend\Validator\GreaterThan', 'hex' => 'Zend\Validator\Hex', 'hostname' => 'Zend\Validator\Hostname', 'iban' => 'Zend\Validator\Iban', 'identical' => 'Zend\Validator\Identical', 'inarray' => 'Zend\Validator\InArray', - 'int' => 'Zend\I18n\Validator\Int', + 'int' => 'Zend\I18n\Validator\IsInt', 'ip' => 'Zend\Validator\Ip', 'isbn' => 'Zend\Validator\Isbn', + 'isfloat' => 'Zend\I18n\Validator\IsFloat', 'isinstanceof' => 'Zend\Validator\IsInstanceOf', + 'isint' => 'Zend\I18n\Validator\IsInt', + 'ip' => 'Zend\Validator\Ip', 'lessthan' => 'Zend\Validator\LessThan', 'notempty' => 'Zend\Validator\NotEmpty', 'phonenumber' => 'Zend\I18n\Validator\PhoneNumber', @@ -104,6 +117,7 @@ class ValidatorPluginManager extends AbstractPluginManager 'sitemappriority' => 'Zend\Validator\Sitemap\Priority', 'stringlength' => 'Zend\Validator\StringLength', 'step' => 'Zend\Validator\Step', + 'timezone' => 'Zend\Validator\Timezone', 'uri' => 'Zend\Validator\Uri', ); diff --git a/library/Zend/Validator/composer.json b/library/Zend/Validator/composer.json index 2e99da136..a72cf2688 100644 --- a/library/Zend/Validator/composer.json +++ b/library/Zend/Validator/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Validator\\": "" } }, - "target-dir": "Zend/Validator", "require": { "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" diff --git a/library/Zend/Version/Version.php b/library/Zend/Version/Version.php index 7b27667e1..820d37540 100644 --- a/library/Zend/Version/Version.php +++ b/library/Zend/Version/Version.php @@ -20,7 +20,7 @@ final class Version /** * Zend Framework version identification - see compareVersion() */ - const VERSION = '2.3.4'; + const VERSION = '2.4.0'; /** * Github Service Identifier for version information is retrieved from diff --git a/library/Zend/Version/composer.json b/library/Zend/Version/composer.json index b3fd61e6f..1e587e97c 100644 --- a/library/Zend/Version/composer.json +++ b/library/Zend/Version/composer.json @@ -8,19 +8,16 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\Version\\": "" } }, - "target-dir": "Zend/Version", "require": { "php": ">=5.3.23", "zendframework/zend-json": "self.version" }, "suggest": { - "zendframework/zend-http": "Allows use of Zend\\Http\\Client to check version information" - }, - "suggest": { + "zendframework/zend-http": "Allows use of Zend\\Http\\Client to check version information", "zendframework/zend-json": "To check latest version hosted in GitHub" }, "extra": { diff --git a/library/Zend/View/Helper/Doctype.php b/library/Zend/View/Helper/Doctype.php index 814fcb186..bbda21d96 100644 --- a/library/Zend/View/Helper/Doctype.php +++ b/library/Zend/View/Helper/Doctype.php @@ -205,7 +205,7 @@ class Doctype extends AbstractHelper */ public function isXhtml() { - return (stristr($this->getDoctype(), 'xhtml') ? true : false); + return (bool) stristr($this->getDoctype(), 'xhtml'); } /** @@ -215,7 +215,7 @@ class Doctype extends AbstractHelper */ public function isHtml5() { - return (stristr($this->__invoke(), '') ? true : false); + return (bool) stristr($this->__invoke(), ''); } /** @@ -225,6 +225,6 @@ class Doctype extends AbstractHelper */ public function isRdfa() { - return ($this->isHtml5() || stristr($this->getDoctype(), 'rdfa') ? true : false); + return ($this->isHtml5() || stristr($this->getDoctype(), 'rdfa')); } } diff --git a/library/Zend/View/Helper/FlashMessenger.php b/library/Zend/View/Helper/FlashMessenger.php index 102de9147..72c11f8e5 100644 --- a/library/Zend/View/Helper/FlashMessenger.php +++ b/library/Zend/View/Helper/FlashMessenger.php @@ -41,6 +41,13 @@ class FlashMessenger extends AbstractTranslatorHelper implements ServiceLocatorA protected $messageOpenFormat = '
  • '; protected $messageSeparatorString = '
  • '; + /** + * Flag whether to escape messages + * + * @var bool + */ + protected $autoEscape = true; + /** * Html escape helper * @@ -94,15 +101,16 @@ class FlashMessenger extends AbstractTranslatorHelper implements ServiceLocatorA /** * Render Messages * - * @param string $namespace - * @param array $classes + * @param string $namespace + * @param array $classes + * @param null|bool $autoEscape * @return string */ - public function render($namespace = PluginFlashMessenger::NAMESPACE_DEFAULT, array $classes = array()) + public function render($namespace = PluginFlashMessenger::NAMESPACE_DEFAULT, array $classes = array(), $autoEscape = null) { $flashMessenger = $this->getPluginFlashMessenger(); $messages = $flashMessenger->getMessagesFromNamespace($namespace); - return $this->renderMessages($namespace, $messages, $classes); + return $this->renderMessages($namespace, $messages, $classes, $autoEscape); } /** @@ -112,24 +120,27 @@ class FlashMessenger extends AbstractTranslatorHelper implements ServiceLocatorA * @param array $classes * @return string */ - public function renderCurrent($namespace = PluginFlashMessenger::NAMESPACE_DEFAULT, array $classes = array()) + public function renderCurrent($namespace = PluginFlashMessenger::NAMESPACE_DEFAULT, array $classes = array(), $autoEscape = null) { $flashMessenger = $this->getPluginFlashMessenger(); $messages = $flashMessenger->getCurrentMessagesFromNamespace($namespace); - return $this->renderMessages($namespace, $messages, $classes); + return $this->renderMessages($namespace, $messages, $classes, $autoEscape); } /** * Render Messages * - * @param array $messages - * @param array $classes + * @param string $namespace + * @param array $messages + * @param array $classes + * @param bool|null $autoEscape * @return string */ protected function renderMessages( $namespace = PluginFlashMessenger::NAMESPACE_DEFAULT, array $messages = array(), - array $classes = array() + array $classes = array(), + $autoEscape = null ) { // Prepare classes for opening tag if (empty($classes)) { @@ -140,6 +151,11 @@ class FlashMessenger extends AbstractTranslatorHelper implements ServiceLocatorA } $classes = array($classes); } + + if (null === $autoEscape) { + $autoEscape = $this->getAutoEscape(); + } + // Flatten message array $escapeHtml = $this->getEscapeHtmlHelper(); $messagesToPrint = array(); @@ -147,19 +163,27 @@ class FlashMessenger extends AbstractTranslatorHelper implements ServiceLocatorA $translatorTextDomain = $this->getTranslatorTextDomain(); array_walk_recursive( $messages, - function ($item) use (&$messagesToPrint, $escapeHtml, $translator, $translatorTextDomain) { + function ($item) use (& $messagesToPrint, $escapeHtml, $autoEscape, $translator, $translatorTextDomain) { if ($translator !== null) { $item = $translator->translate( $item, $translatorTextDomain ); } - $messagesToPrint[] = $escapeHtml($item); + + if ($autoEscape) { + $messagesToPrint[] = $escapeHtml($item); + return; + } + + $messagesToPrint[] = $item; } ); + if (empty($messagesToPrint)) { return ''; } + // Generate markup $markup = sprintf($this->getMessageOpenFormat(), ' class="' . implode(' ', $classes) . '"'); $markup .= implode( @@ -170,6 +194,28 @@ class FlashMessenger extends AbstractTranslatorHelper implements ServiceLocatorA return $markup; } + /** + * Set whether or not auto escaping should be used + * + * @param bool $autoEscape + * @return self + */ + public function setAutoEscape($autoEscape = true) + { + $this->autoEscape = (bool) $autoEscape; + return $this; + } + + /** + * Return whether auto escaping is enabled or disabled + * + * return bool + */ + public function getAutoEscape() + { + return $this->autoEscape; + } + /** * Set the string used to close message representation * diff --git a/library/Zend/View/Helper/HeadScript.php b/library/Zend/View/Helper/HeadScript.php index f250f3fc7..743e7ced2 100644 --- a/library/Zend/View/Helper/HeadScript.php +++ b/library/Zend/View/Helper/HeadScript.php @@ -241,9 +241,9 @@ class HeadScript extends Placeholder\Container\AbstractStandalone : $this->getIndent(); if ($this->view) { - $useCdata = $this->view->plugin('doctype')->isXhtml() ? true : false; + $useCdata = $this->view->plugin('doctype')->isXhtml(); } else { - $useCdata = $this->useCdata ? true : false; + $useCdata = $this->useCdata; } $escapeStart = ($useCdata) ? '//isTranslatorEnabled()) { - return null; + return; } return $this->translator; diff --git a/library/Zend/View/Helper/HtmlList.php b/library/Zend/View/Helper/HtmlList.php index 318e6c072..4845461c6 100644 --- a/library/Zend/View/Helper/HtmlList.php +++ b/library/Zend/View/Helper/HtmlList.php @@ -9,6 +9,8 @@ namespace Zend\View\Helper; +use Zend\View\Exception; + /** * Helper for ordered and unordered lists */ @@ -21,10 +23,18 @@ class HtmlList extends AbstractHtmlElement * @param bool $ordered Specifies ordered/unordered list; default unordered * @param array $attribs Attributes for the ol/ul tag. * @param bool $escape Escape the items. + * @throws Exception\InvalidArgumentException * @return string The list XHTML. */ public function __invoke(array $items, $ordered = false, $attribs = false, $escape = true) { + if (empty($items)) { + throw new Exception\InvalidArgumentException(sprintf( + '$items array can not be empty in %s', + __METHOD__ + )); + } + $list = ''; foreach ($items as $item) { diff --git a/library/Zend/View/Helper/HtmlTag.php b/library/Zend/View/Helper/HtmlTag.php new file mode 100644 index 000000000..89dfbe410 --- /dev/null +++ b/library/Zend/View/Helper/HtmlTag.php @@ -0,0 +1,148 @@ + tag (both opening and closing) of a web page, to which some custom + * attributes can be added dynamically. + * + * @author Nikola Posa + */ +class HtmlTag extends AbstractHtmlElement +{ + /** + * Attributes for the tag. + * + * @var array + */ + protected $attributes = array(); + + /** + * Whether to pre-set appropriate attributes in accordance + * with the currently set DOCTYPE. + * + * @var bool + */ + protected $useNamespaces = false; + + /** + * @var bool + */ + private $handledNamespaces = false; + + /** + * Retrieve object instance; optionally add attributes. + * + * @param array $attribs + * @return self + */ + public function __invoke(array $attribs = array()) + { + if (!empty($attribs)) { + $this->setAttributes($attribs); + } + + return $this; + } + + /** + * Set new attribute. + * + * @param string $attrName + * @param string $attrValue + * @return self + */ + public function setAttribute($attrName, $attrValue) + { + $this->attributes[$attrName] = $attrValue; + return $this; + } + + /** + * Add new or overwrite the existing attributes. + * + * @param array $attribs + * @return self + */ + public function setAttributes(array $attribs) + { + foreach ($attribs as $name => $value) { + $this->setAttribute($name, $value); + } + return $this; + } + + /** + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * @param bool $useNamespaces + * @return self + */ + public function setUseNamespaces($useNamespaces) + { + $this->useNamespaces = (bool) $useNamespaces; + return $this; + } + + /** + * @return bool + */ + public function getUseNamespaces() + { + return $this->useNamespaces; + } + + /** + * Render opening tag. + * + * @return string + */ + public function openTag() + { + $this->handleNamespaceAttributes(); + + return sprintf('', $this->htmlAttribs($this->attributes)); + } + + protected function handleNamespaceAttributes() + { + if ($this->useNamespaces && !$this->handledNamespaces) { + if (method_exists($this->view, 'plugin')) { + $doctypeAttributes = array(); + + if ($this->view->plugin('doctype')->isXhtml()) { + $doctypeAttributes = array('xmlns' => 'http://www.w3.org/1999/xhtml'); + } + + if (!empty($doctypeAttributes)) { + $this->attributes = array_merge($doctypeAttributes, $this->attributes); + } + } + + $this->handledNamespaces = true; + } + } + + /** + * Render closing tag. + * + * @return string + */ + public function closeTag() + { + return ''; + } +} diff --git a/library/Zend/View/Helper/Identity.php b/library/Zend/View/Helper/Identity.php index e36863aad..91cc96c29 100644 --- a/library/Zend/View/Helper/Identity.php +++ b/library/Zend/View/Helper/Identity.php @@ -9,7 +9,7 @@ namespace Zend\View\Helper; -use Zend\Authentication\AuthenticationService; +use Zend\Authentication\AuthenticationServiceInterface; use Zend\View\Exception; /** @@ -20,7 +20,7 @@ class Identity extends AbstractHelper /** * AuthenticationService instance * - * @var AuthenticationService + * @var AuthenticationServiceInterface */ protected $authenticationService; @@ -34,12 +34,12 @@ class Identity extends AbstractHelper */ public function __invoke() { - if (!$this->authenticationService instanceof AuthenticationService) { - throw new Exception\RuntimeException('No AuthenticationService instance provided'); + if (!$this->authenticationService instanceof AuthenticationServiceInterface) { + throw new Exception\RuntimeException('No AuthenticationServiceInterface instance provided'); } if (!$this->authenticationService->hasIdentity()) { - return null; + return; } return $this->authenticationService->getIdentity(); @@ -48,10 +48,10 @@ class Identity extends AbstractHelper /** * Set AuthenticationService instance * - * @param AuthenticationService $authenticationService + * @param AuthenticationServiceInterface $authenticationService * @return Identity */ - public function setAuthenticationService(AuthenticationService $authenticationService) + public function setAuthenticationService(AuthenticationServiceInterface $authenticationService) { $this->authenticationService = $authenticationService; return $this; @@ -60,7 +60,7 @@ class Identity extends AbstractHelper /** * Get AuthenticationService instance * - * @return AuthenticationService + * @return AuthenticationServiceInterface */ public function getAuthenticationService() { diff --git a/library/Zend/View/Helper/Navigation/AbstractHelper.php b/library/Zend/View/Helper/Navigation/AbstractHelper.php index 87b603207..7fbe290fa 100644 --- a/library/Zend/View/Helper/Navigation/AbstractHelper.php +++ b/library/Zend/View/Helper/Navigation/AbstractHelper.php @@ -803,7 +803,7 @@ abstract class AbstractHelper extends View\Helper\AbstractHtmlElement implements public function getTranslator() { if (! $this->isTranslatorEnabled()) { - return null; + return; } return $this->translator; diff --git a/library/Zend/View/Helper/Navigation/Links.php b/library/Zend/View/Helper/Navigation/Links.php index 656acd8bd..853530f97 100644 --- a/library/Zend/View/Helper/Navigation/Links.php +++ b/library/Zend/View/Helper/Navigation/Links.php @@ -338,7 +338,7 @@ class Links extends AbstractHelper } } - return null; + return; } /** @@ -492,7 +492,7 @@ class Links extends AbstractHelper switch (count($found)) { case 0: - return null; + return; case 1: return $found[0]; default: @@ -525,7 +525,7 @@ class Links extends AbstractHelper switch (count($found)) { case 0: - return null; + return; case 1: return $found[0]; default: @@ -564,7 +564,7 @@ class Links extends AbstractHelper switch (count($found)) { case 0: - return null; + return; case 1: return $found[0]; default: @@ -711,7 +711,7 @@ class Links extends AbstractHelper } // nothing found - return null; + return; } /** diff --git a/library/Zend/View/Helper/Navigation/Sitemap.php b/library/Zend/View/Helper/Navigation/Sitemap.php index 99d1f4300..bcd7dda92 100644 --- a/library/Zend/View/Helper/Navigation/Sitemap.php +++ b/library/Zend/View/Helper/Navigation/Sitemap.php @@ -208,10 +208,12 @@ class Sitemap extends AbstractHelper $lastmod = date('c', $lastmod); } - if (!$this->getUseSitemapValidators() || - $lastmodValidator->isValid($lastmod)) { + if (!$this->getUseSitemapValidators() + || $lastmodValidator->isValid($lastmod) + ) { + // Cast $lastmod to string in case no validation was used $urlNode->appendChild( - $dom->createElementNS(self::SITEMAP_NS, 'lastmod', $lastmod) + $dom->createElementNS(self::SITEMAP_NS, 'lastmod', (string) $lastmod) ); } } @@ -289,7 +291,7 @@ class Sitemap extends AbstractHelper return $this->xmlEscape($url); } - return null; + return; } /** diff --git a/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php b/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php index aec2f7d0f..b9474fb6a 100644 --- a/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php +++ b/library/Zend/View/Helper/Placeholder/Container/AbstractContainer.php @@ -295,7 +295,7 @@ abstract class AbstractContainer extends ArrayObject return 0; } - return $nextIndex = max($keys) + 1; + return max($keys) + 1; } /** diff --git a/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php b/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php index 8c99c95e5..fdbfa2b1b 100644 --- a/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php +++ b/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php @@ -109,7 +109,7 @@ abstract class AbstractStandalone extends AbstractHelper implements return $container[$key]; } - return null; + return; } /** @@ -184,7 +184,7 @@ abstract class AbstractStandalone extends AbstractHelper implements */ public function setAutoEscape($autoEscape = true) { - $this->autoEscape = ($autoEscape) ? true : false; + $this->autoEscape = (bool) $autoEscape; return $this; } diff --git a/library/Zend/View/Helper/ServerUrl.php b/library/Zend/View/Helper/ServerUrl.php index 2cd80efdb..0e11baa25 100644 --- a/library/Zend/View/Helper/ServerUrl.php +++ b/library/Zend/View/Helper/ServerUrl.php @@ -112,6 +112,10 @@ class ServerUrl extends AbstractHelper } if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT']) { + if ($this->isReversedProxy()) { + $this->setPort(443); + return; + } $this->setPort($_SERVER['SERVER_PORT']); return; } @@ -132,6 +136,7 @@ class ServerUrl extends AbstractHelper case (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true)): case (isset($_SERVER['HTTP_SCHEME']) && ($_SERVER['HTTP_SCHEME'] == 'https')): case (443 === $this->getPort()): + case $this->isReversedProxy(): $scheme = 'https'; break; default: @@ -142,6 +147,11 @@ class ServerUrl extends AbstractHelper $this->setScheme($scheme); } + protected function isReversedProxy() + { + return isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'; + } + /** * Detect if a proxy is in use, and, if so, set the host based on it * diff --git a/library/Zend/View/HelperPluginManager.php b/library/Zend/View/HelperPluginManager.php index 4c67a967c..bb4d1a048 100644 --- a/library/Zend/View/HelperPluginManager.php +++ b/library/Zend/View/HelperPluginManager.php @@ -52,6 +52,7 @@ class HelperPluginManager extends AbstractPluginManager 'escapecss' => 'Zend\View\Helper\EscapeCss', 'escapeurl' => 'Zend\View\Helper\EscapeUrl', 'gravatar' => 'Zend\View\Helper\Gravatar', + 'htmltag' => 'Zend\View\Helper\HtmlTag', 'headlink' => 'Zend\View\Helper\HeadLink', 'headmeta' => 'Zend\View\Helper\HeadMeta', 'headscript' => 'Zend\View\Helper\HeadScript', diff --git a/library/Zend/View/Model/JsonModel.php b/library/Zend/View/Model/JsonModel.php index b16fcd533..a0c4ed77d 100644 --- a/library/Zend/View/Model/JsonModel.php +++ b/library/Zend/View/Model/JsonModel.php @@ -61,9 +61,13 @@ class JsonModel extends ViewModel $variables = ArrayUtils::iteratorToArray($variables); } + $options = array( + 'prettyPrint' => $this->getOption('prettyPrint'), + ); + if (null !== $this->jsonpCallback) { - return $this->jsonpCallback.'('.Json::encode($variables).');'; + return $this->jsonpCallback.'('.Json::encode($variables, false, $options).');'; } - return Json::encode($variables); + return Json::encode($variables, false, $options); } } diff --git a/library/Zend/View/Model/ViewModel.php b/library/Zend/View/Model/ViewModel.php index 9179e5d10..7ec626955 100644 --- a/library/Zend/View/Model/ViewModel.php +++ b/library/Zend/View/Model/ViewModel.php @@ -106,7 +106,7 @@ class ViewModel implements ModelInterface, ClearableModelInterface, RetrievableC public function __get($name) { if (!$this->__isset($name)) { - return null; + return; } $variables = $this->getVariables(); @@ -134,7 +134,7 @@ class ViewModel implements ModelInterface, ClearableModelInterface, RetrievableC public function __unset($name) { if (!$this->__isset($name)) { - return null; + return; } unset($this->variables[$name]); diff --git a/library/Zend/View/Renderer/ConsoleRenderer.php b/library/Zend/View/Renderer/ConsoleRenderer.php index c54da407d..cae7ee0db 100644 --- a/library/Zend/View/Renderer/ConsoleRenderer.php +++ b/library/Zend/View/Renderer/ConsoleRenderer.php @@ -52,7 +52,7 @@ class ConsoleRenderer implements RendererInterface, TreeRendererInterface * * Returns the object instance, as it is its own template engine * - * @return PhpRenderer + * @return ConsoleRenderer */ public function getEngine() { diff --git a/library/Zend/View/Renderer/FeedRenderer.php b/library/Zend/View/Renderer/FeedRenderer.php index 444b8b786..ac8370d20 100644 --- a/library/Zend/View/Renderer/FeedRenderer.php +++ b/library/Zend/View/Renderer/FeedRenderer.php @@ -53,6 +53,7 @@ class FeedRenderer implements RendererInterface public function setResolver(Resolver $resolver) { $this->resolver = $resolver; + return $this; } /** diff --git a/library/Zend/View/Renderer/PhpRenderer.php b/library/Zend/View/Renderer/PhpRenderer.php index 7d6e9d7e0..6a43c643e 100644 --- a/library/Zend/View/Renderer/PhpRenderer.php +++ b/library/Zend/View/Renderer/PhpRenderer.php @@ -131,11 +131,6 @@ class PhpRenderer implements Renderer, TreeRendererInterface */ private $__varsCache = array(); - /** - * @var array Cache for the plugin call - */ - private $__pluginCache = array(); - /** * Constructor. * @@ -392,13 +387,13 @@ class PhpRenderer implements Renderer, TreeRendererInterface */ public function __call($method, $argv) { - if (!isset($this->__pluginCache[$method])) { - $this->__pluginCache[$method] = $this->plugin($method); + $plugin = $this->plugin($method); + + if (is_callable($plugin)) { + return call_user_func_array($plugin, $argv); } - if (is_callable($this->__pluginCache[$method])) { - return call_user_func_array($this->__pluginCache[$method], $argv); - } - return $this->__pluginCache[$method]; + + return $plugin; } /** diff --git a/library/Zend/View/Resolver/AggregateResolver.php b/library/Zend/View/Resolver/AggregateResolver.php index 7163b9dde..90208ea76 100644 --- a/library/Zend/View/Resolver/AggregateResolver.php +++ b/library/Zend/View/Resolver/AggregateResolver.php @@ -99,14 +99,11 @@ class AggregateResolver implements Countable, IteratorAggregate, ResolverInterfa foreach ($this->queue as $resolver) { $resource = $resolver->resolve($name, $renderer); - if (!$resource) { - // No resource found; try next resolver - continue; + if ($resource) { + // Resource found; return it + $this->lastSuccessfulResolver = $resolver; + return $resource; } - - // Resource found; return it - $this->lastSuccessfulResolver = $resolver; - return $resource; } $this->lastLookupFailure = static::FAILURE_NOT_FOUND; diff --git a/library/Zend/View/Resolver/PrefixPathStackResolver.php b/library/Zend/View/Resolver/PrefixPathStackResolver.php new file mode 100644 index 000000000..bd976df29 --- /dev/null +++ b/library/Zend/View/Resolver/PrefixPathStackResolver.php @@ -0,0 +1,58 @@ +prefixes = $prefixes; + } + + /** + * {@inheritDoc} + */ + public function resolve($name, Renderer $renderer = null) + { + foreach ($this->prefixes as $prefix => & $resolver) { + if (strpos($name, $prefix) !== 0) { + continue; + } + + if (! $resolver instanceof ResolverInterface) { + $resolver = new TemplatePathStack(array('script_paths' => (array) $resolver)); + } + + if ($result = $resolver->resolve(substr($name, strlen($prefix)), $renderer)) { + return $result; + } + } + + return; + } +} diff --git a/library/Zend/View/Resolver/RelativeFallbackResolver.php b/library/Zend/View/Resolver/RelativeFallbackResolver.php new file mode 100644 index 000000000..0aac1978c --- /dev/null +++ b/library/Zend/View/Resolver/RelativeFallbackResolver.php @@ -0,0 +1,74 @@ +resolver = $resolver; + } + + /** + * {@inheritDoc} + */ + public function resolve($name, RendererInterface $renderer = null) + { + $plugin = array($renderer, 'plugin'); + + if (! is_callable($plugin)) { + return false; + } + + $helper = call_user_func($plugin, 'view_model'); + + if (! $helper instanceof ViewModelHelper) { + return false; + } + + $currentModel = $helper->getCurrent(); + + if (! $currentModel instanceof ModelInterface) { + return false; + } + + $currentTemplate = $currentModel->getTemplate(); + $position = strrpos($currentTemplate, self::NS_SEPARATOR); + + if (! $position) { + return false; + } + + return $this->resolver->resolve(substr($currentTemplate, 0, $position) . self::NS_SEPARATOR . $name, $renderer); + } +} diff --git a/library/Zend/View/Variables.php b/library/Zend/View/Variables.php index d889b3dda..18444ce91 100644 --- a/library/Zend/View/Variables.php +++ b/library/Zend/View/Variables.php @@ -138,7 +138,7 @@ class Variables extends ArrayObject $key ), E_USER_NOTICE); } - return null; + return; } $return = parent::offsetGet($key); diff --git a/library/Zend/View/composer.json b/library/Zend/View/composer.json index 44bb5c275..dfcce1c87 100644 --- a/library/Zend/View/composer.json +++ b/library/Zend/View/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\View\\": "" } }, - "target-dir": "Zend/View", "require": { "php": ">=5.3.23", "zendframework/zend-eventmanager": "self.version", diff --git a/library/Zend/XmlRpc/AbstractValue.php b/library/Zend/XmlRpc/AbstractValue.php index bc01223ed..35f8a701e 100644 --- a/library/Zend/XmlRpc/AbstractValue.php +++ b/library/Zend/XmlRpc/AbstractValue.php @@ -201,7 +201,7 @@ abstract class AbstractValue return new Value\Boolean($value); case self::XMLRPC_TYPE_STRING: - return new Value\String($value); + return new Value\Text($value); case self::XMLRPC_TYPE_BASE64: return new Value\Base64($value); @@ -306,7 +306,7 @@ abstract class AbstractValue // Fall through to the next case default: // If type isn't identified (or identified as string), it treated as string - return new Value\String($value); + return new Value\Text($value); } } @@ -345,7 +345,7 @@ abstract class AbstractValue $xmlrpcValue = new Value\Boolean($value); break; case self::XMLRPC_TYPE_STRING: - $xmlrpcValue = new Value\String($value); + $xmlrpcValue = new Value\Text($value); break; case self::XMLRPC_TYPE_DATETIME: // The value should already be in an iso8601 format $xmlrpcValue = new Value\DateTime($value); @@ -394,7 +394,6 @@ abstract class AbstractValue // Maybe we want to throw an exception here ? if (!isset($member->value) or !isset($member->name)) { continue; - //throw new Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag'); } $values[(string) $member->name] = static::_xmlStringToNativeXmlRpc($member->value); } diff --git a/library/Zend/XmlRpc/Client.php b/library/Zend/XmlRpc/Client.php index 4dd260f6c..334392ebb 100644 --- a/library/Zend/XmlRpc/Client.php +++ b/library/Zend/XmlRpc/Client.php @@ -79,7 +79,6 @@ class Client implements ServerClient $this->serverAddress = $server; } - /** * Sets the HTTP client object to use for connecting the XML-RPC server. * @@ -91,7 +90,6 @@ class Client implements ServerClient return $this->httpClient = $httpClient; } - /** * Gets the HTTP client object. * @@ -102,7 +100,6 @@ class Client implements ServerClient return $this->httpClient; } - /** * Sets the object used to introspect remote servers * @@ -114,7 +111,6 @@ class Client implements ServerClient return $this->introspector = $introspector; } - /** * Gets the introspection object. * @@ -125,7 +121,6 @@ class Client implements ServerClient return $this->introspector; } - /** * The request of the last method call * @@ -136,7 +131,6 @@ class Client implements ServerClient return $this->lastRequest; } - /** * The response received from the last method call * @@ -147,7 +141,6 @@ class Client implements ServerClient return $this->lastResponse; } - /** * Returns a proxy object for more convenient method calls * diff --git a/library/Zend/XmlRpc/Client/ServerIntrospection.php b/library/Zend/XmlRpc/Client/ServerIntrospection.php index 8172cd88b..d1d2c2a43 100644 --- a/library/Zend/XmlRpc/Client/ServerIntrospection.php +++ b/library/Zend/XmlRpc/Client/ServerIntrospection.php @@ -21,7 +21,6 @@ class ServerIntrospection */ private $system = null; - /** * @param \Zend\XmlRpc\Client $client */ diff --git a/library/Zend/XmlRpc/Client/ServerProxy.php b/library/Zend/XmlRpc/Client/ServerProxy.php index d4154699c..2e4343baf 100644 --- a/library/Zend/XmlRpc/Client/ServerProxy.php +++ b/library/Zend/XmlRpc/Client/ServerProxy.php @@ -28,13 +28,11 @@ class ServerProxy */ private $namespace = ''; - /** * @var array of \Zend\XmlRpc\Client\ServerProxy */ private $cache = array(); - /** * Class constructor * @@ -47,7 +45,6 @@ class ServerProxy $this->namespace = $namespace; } - /** * Get the next successive namespace * @@ -63,7 +60,6 @@ class ServerProxy return $this->cache[$namespace]; } - /** * Call a method in this namespace. * diff --git a/library/Zend/XmlRpc/Fault.php b/library/Zend/XmlRpc/Fault.php index 468a722dc..04a1e5ca3 100644 --- a/library/Zend/XmlRpc/Fault.php +++ b/library/Zend/XmlRpc/Fault.php @@ -92,7 +92,7 @@ class Fault if (empty($message) && isset($this->internal[$code])) { $message = $this->internal[$code]; } elseif (empty($message)) { - $message = 'Unknown error'; + $message = $this->internal[404]; } $this->setMessage($message); } @@ -233,7 +233,7 @@ class Fault if (isset($this->internal[$code])) { $message = $this->internal[$code]; } else { - $message = 'Unknown Error'; + $message = $this->internal[404]; } } diff --git a/library/Zend/XmlRpc/Generator/XmlWriter.php b/library/Zend/XmlRpc/Generator/XmlWriter.php index 69c755674..d493f12ba 100644 --- a/library/Zend/XmlRpc/Generator/XmlWriter.php +++ b/library/Zend/XmlRpc/Generator/XmlWriter.php @@ -33,7 +33,6 @@ class XmlWriter extends AbstractGenerator $this->xmlWriter->startDocument('1.0', $this->encoding); } - /** * Open a new XML element * diff --git a/library/Zend/XmlRpc/Request.php b/library/Zend/XmlRpc/Request.php index 121791919..d91539bde 100644 --- a/library/Zend/XmlRpc/Request.php +++ b/library/Zend/XmlRpc/Request.php @@ -85,7 +85,6 @@ class Request } } - /** * Set encoding to use in request * diff --git a/library/Zend/XmlRpc/Server.php b/library/Zend/XmlRpc/Server.php index 62f876127..0c36a3583 100644 --- a/library/Zend/XmlRpc/Server.php +++ b/library/Zend/XmlRpc/Server.php @@ -257,7 +257,7 @@ class Server extends AbstractServer */ public function setReturnResponse($flag = true) { - $this->returnResponse = ($flag) ? true : false; + $this->returnResponse = (bool) $flag; return $this; } diff --git a/library/Zend/XmlRpc/Server/Fault.php b/library/Zend/XmlRpc/Server/Fault.php index 1bf5b35cc..2b66861b2 100644 --- a/library/Zend/XmlRpc/Server/Fault.php +++ b/library/Zend/XmlRpc/Server/Fault.php @@ -134,10 +134,7 @@ class Fault extends \Zend\XmlRpc\Fault */ public static function attachObserver($class) { - if (!is_string($class) - || !class_exists($class) - || !is_callable(array($class, 'observe')) - ) { + if (!is_string($class) || !class_exists($class) || !is_callable(array($class, 'observe'))) { return false; } diff --git a/library/Zend/XmlRpc/Value/AbstractCollection.php b/library/Zend/XmlRpc/Value/AbstractCollection.php index c394df60f..f4234887a 100644 --- a/library/Zend/XmlRpc/Value/AbstractCollection.php +++ b/library/Zend/XmlRpc/Value/AbstractCollection.php @@ -31,7 +31,6 @@ abstract class AbstractCollection extends AbstractValue } } - /** * Return the value of this object, convert the XML-RPC native collection values into a PHP array * diff --git a/library/Zend/XmlRpc/Value/ArrayValue.php b/library/Zend/XmlRpc/Value/ArrayValue.php index 93e663489..5e8efcc9b 100644 --- a/library/Zend/XmlRpc/Value/ArrayValue.php +++ b/library/Zend/XmlRpc/Value/ArrayValue.php @@ -22,7 +22,6 @@ class ArrayValue extends AbstractCollection parent::__construct($value); } - /** * Generate the XML code that represent an array native MXL-RPC value * diff --git a/library/Zend/XmlRpc/Value/Nil.php b/library/Zend/XmlRpc/Value/Nil.php index e3b33b663..15ac94122 100644 --- a/library/Zend/XmlRpc/Value/Nil.php +++ b/library/Zend/XmlRpc/Value/Nil.php @@ -28,6 +28,6 @@ class Nil extends AbstractScalar */ public function getValue() { - return null; + return; } } diff --git a/library/Zend/XmlRpc/Value/Struct.php b/library/Zend/XmlRpc/Value/Struct.php index c58d23f52..d327f520d 100644 --- a/library/Zend/XmlRpc/Value/Struct.php +++ b/library/Zend/XmlRpc/Value/Struct.php @@ -22,7 +22,6 @@ class Struct extends AbstractCollection parent::__construct($value); } - /** * Generate the XML code that represent struct native MXL-RPC value * diff --git a/library/Zend/XmlRpc/Value/String.php b/library/Zend/XmlRpc/Value/Text.php similarity index 96% rename from library/Zend/XmlRpc/Value/String.php rename to library/Zend/XmlRpc/Value/Text.php index 9a94505cb..a6631ee00 100644 --- a/library/Zend/XmlRpc/Value/String.php +++ b/library/Zend/XmlRpc/Value/Text.php @@ -9,7 +9,7 @@ namespace Zend\XmlRpc\Value; -class String extends AbstractScalar +class Text extends AbstractScalar { /** * Set the value of a string native type diff --git a/library/Zend/XmlRpc/composer.json b/library/Zend/XmlRpc/composer.json index b0131ee25..9a0707501 100644 --- a/library/Zend/XmlRpc/composer.json +++ b/library/Zend/XmlRpc/composer.json @@ -8,11 +8,10 @@ ], "homepage": "https://github.com/zendframework/zf2", "autoload": { - "psr-0": { + "psr-4": { "Zend\\XmlRpc\\": "" } }, - "target-dir": "Zend/XmlRpc", "require": { "php": ">=5.3.23", "zendframework/zend-http": "self.version",