diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 21d57da59..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tools/phptools"] - path = tools/phptools - url = git://github.com/ralphschindler/PHPTools.git diff --git a/.travis/run-tests.sh b/.travis/run-tests.sh deleted file mode 100755 index a84e0ba2a..000000000 --- a/.travis/run-tests.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -travisdir=$(dirname "$0") -testdir="$travisdir/../tests" -testedcomponents=(`cat "$travisdir/tested-components"`) -result=0 - -for tested in "${testedcomponents[@]}" - do - echo "$tested:" - phpunit -c $testdir/phpunit.xml.dist $testdir/$tested - result=$(($result || $?)) -done - -exit $result diff --git a/.travis/skipped-components b/.travis/skipped-components deleted file mode 100644 index 171dfe9d7..000000000 --- a/.travis/skipped-components +++ /dev/null @@ -1,7 +0,0 @@ -Zend/Amf -Zend/Date -Zend/Dojo -Zend/Queue -Zend/Service -Zend/Test -Zend/Wildfire diff --git a/.travis/tested-components b/.travis/tested-components deleted file mode 100644 index b0b943800..000000000 --- a/.travis/tested-components +++ /dev/null @@ -1,61 +0,0 @@ -Zend/Acl -Zend/Authentication -Zend/Barcode -Zend/Cache -Zend/Captcha -Zend/Cloud -Zend/Code -Zend/Config -Zend/Console -Zend/Crypt -Zend/Currency -Zend/Db -Zend/Di -Zend/DocBook -Zend/Dojo -Zend/Dom -Zend/EventManager -Zend/Feed -Zend/File -Zend/Filter -Zend/Form -Zend/GData -Zend/Http -Zend/InfoCard -Zend/InputFilter -Zend/Json -Zend/Ldap -Zend/Loader -Zend/Locale -Zend/Log -Zend/Mail -Zend/Markup -Zend/Math -Zend/Measure -Zend/Memory -Zend/Mime -Zend/ModuleManager -Zend/Mvc -Zend/Navigation -Zend/OAuth -Zend/OpenId -Zend/Paginator -Zend/Pdf -Zend/ProgressBar -Zend/RegistryTest.php -Zend/Rest -Zend/Search -Zend/Serializer -Zend/Server -Zend/Session -Zend/Soap -Zend/Stdlib -Zend/Tag -Zend/Text -Zend/TimeSync -Zend/Translator -Zend/Uri -Zend/Validator -Zend/VersionTest.php -Zend/View -Zend/XmlRpc diff --git a/composer.json b/composer.json index 213b99dbe..d9f079955 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "zendframework/zend-stdlib", - "description": "Zend\\Stdlib component", + "description": " ", "license": "BSD-3-Clause", "keywords": [ "zf2", @@ -9,11 +9,11 @@ "homepage": "https://github.com/zendframework/zend-stdlib", "autoload": { "psr-4": { - "Zend\\Stdlib\\": "src/" + "Zend\\Stdlib": "src/" } }, "require": { - "php": ">=5.3.23" + "php": ">=5.3.3" }, "require-dev": { "zendframework/zend-eventmanager": "self.version", diff --git a/src/Options.php b/src/AbstractOptions.php similarity index 58% rename from src/Options.php rename to src/AbstractOptions.php index d69ca8c3a..b0c074146 100644 --- a/src/Options.php +++ b/src/AbstractOptions.php @@ -1,21 +1,11 @@ $value) { + if ($key === '__strictMode__') continue; + $normalizedKey = preg_replace_callback('/([A-Z])/', $transform, $key); + $array[$normalizedKey] = $value; } - return $setter; - } - - /** - * @param string $key name of option with underscore - * @return string name of getter method - * @throws Exception\BadMethodCallException if getter method is undefined - */ - protected function assembleGetterNameFromKey($key) - { - $parts = explode('_', $key); - $parts = array_map('ucfirst', $parts); - $getter = 'get' . implode('', $parts); - if (!method_exists($this, $getter)) { - throw new Exception\BadMethodCallException( - 'The option "' . $key . '" does not ' - . 'have a matching ' . $getter . ' getter method ' - . 'which must be defined' - ); - } - return $getter; + return $array; } /** @@ -108,7 +84,16 @@ protected function assembleGetterNameFromKey($key) */ public function __set($key, $value) { - $setter = $this->assembleSetterNameFromKey($key); + $setter = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); + if ($this->__strictMode__ && !method_exists($this, $setter)) { + throw new Exception\BadMethodCallException( + 'The option "' . $key . '" does not ' + . 'have a matching ' . $setter . ' setter method ' + . 'which must be defined' + ); + } elseif (!$this->__strictMode__ && !method_exists($this, $setter)) { + return; + } $this->{$setter}($value); } @@ -119,7 +104,14 @@ public function __set($key, $value) */ public function __get($key) { - $getter = $this->assembleGetterNameFromKey($key); + $getter = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); + if (!method_exists($this, $getter)) { + throw new Exception\BadMethodCallException( + 'The option "' . $key . '" does not ' + . 'have a matching ' . $getter . ' getter method ' + . 'which must be defined' + ); + } return $this->{$getter}(); } diff --git a/src/ArraySerializableInterface.php b/src/ArraySerializableInterface.php index d943e5774..20dd4633c 100644 --- a/src/ArraySerializableInterface.php +++ b/src/ArraySerializableInterface.php @@ -1,21 +1,11 @@ callback = $callback; @@ -120,7 +108,7 @@ protected function registerCallback($callback) /** * Retrieve registered callback - * + * * @return Callback */ public function getCallback() @@ -142,7 +130,7 @@ public function getCallback() return $callback; } - // Array callback with WeakRef object -- retrieve the object first, and + // Array callback with WeakRef object -- retrieve the object first, and // then return list($target, $method) = $callback; if ($target instanceof WeakRef) { @@ -155,7 +143,7 @@ public function getCallback() /** * Invoke handler - * + * * @param array $args Arguments to pass to callback * @return mixed */ @@ -174,7 +162,7 @@ public function call(array $args = array()) $this->validateStringCallbackFor54($callback); } - // Minor performance tweak; use call_user_func() until > 3 arguments + // Minor performance tweak; use call_user_func() until > 3 arguments // reached switch (count($args)) { case 0: @@ -209,7 +197,7 @@ public function call(array $args = array()) /** * Invoke as functor - * + * * @return mixed */ public function __invoke() @@ -219,7 +207,7 @@ public function __invoke() /** * Get all callback metadata - * + * * @return array */ public function getMetadata() @@ -229,8 +217,8 @@ public function getMetadata() /** * Retrieve a single metadatum - * - * @param string $name + * + * @param string $name * @return mixed */ public function getMetadatum($name) @@ -245,8 +233,8 @@ public function getMetadatum($name) * Validate a static method call * * Validates that a static method call in PHP 5.4 will actually work - * - * @param string $callback + * + * @param string $callback * @return true * @throws Exception\InvalidCallbackException if invalid */ diff --git a/src/DispatchableInterface.php b/src/DispatchableInterface.php index 794227074..33b0d1980 100644 --- a/src/DispatchableInterface.php +++ b/src/DispatchableInterface.php @@ -1,8 +1,17 @@ exchangeArray($data); - } else if (is_callable(array($object, 'populate'))) { + } elseif (is_callable(array($object, 'populate'))) { $object->populate($data); } else { throw new Exception\BadMethodCallException(sprintf( diff --git a/src/Hydrator/ClassMethods.php b/src/Hydrator/ClassMethods.php index 3ee8da8dd..136aa5725 100644 --- a/src/Hydrator/ClassMethods.php +++ b/src/Hydrator/ClassMethods.php @@ -1,22 +1,11 @@ useCamelCase = $useCamelCase; + $this->underscoreSeparatedKeys = $underscoreSeparatedKeys; } - + /** * Extract values from an object with class methods * * Extracts the getter/setter of the given $object. - * - * @param object $object + * + * @param object $object * @return array * @throws Exception\BadMethodCallException for a non-object $object */ @@ -64,9 +51,8 @@ public function extract($object) __METHOD__ )); } - - $transform = function($letters) - { + + $transform = function($letters) { $letter = array_shift($letters); return '_' . strtolower($letter); }; @@ -81,13 +67,14 @@ public function extract($object) } $attribute = substr($method, 3); $attribute = lcfirst($attribute); - if (!$this->useCamelCase) { + if ($this->underscoreSeparatedKeys) { $attribute = preg_replace_callback('/([A-Z])/', $transform, $attribute); } - $attributes[$attribute] = $object->$method(); + + $attributes[$attribute] = $object->$method(); } } - + return $attributes; } @@ -95,9 +82,9 @@ public function extract($object) * Hydrate an object by populating getter/setter methods * * Hydrates an object by getter/setter methods of the object. - * - * @param array $data - * @param object $object + * + * @param array $data + * @param object $object * @return object * @throws Exception\BadMethodCallException for a non-object $object */ @@ -109,14 +96,14 @@ public function hydrate(array $data, $object) __METHOD__ )); } - - $transform = function($letters) - { + + $transform = function($letters) { $letter = substr(array_shift($letters), 1, 1); return ucfirst($letter); }; + foreach ($data as $property => $value) { - if (!$this->useCamelCase) { + if ($this->underscoreSeparatedKeys) { $property = preg_replace_callback('/(_[a-z])/', $transform, $property); } $method = 'set' . ucfirst($property); diff --git a/src/Hydrator/HydratorInterface.php b/src/Hydrator/HydratorInterface.php index a97db30e5..d014b3fdc 100644 --- a/src/Hydrator/HydratorInterface.php +++ b/src/Hydrator/HydratorInterface.php @@ -1,22 +1,11 @@ getName()] = $property->getValue($object); + } + + return $result; + } + + /** + * Hydrate $object with the provided $data. + * + * @param array $data + * @param object $object + * @return object + */ + public function hydrate(array $data, $object) + { + $reflProperties = self::getReflProperties($object); + foreach($data as $key => $value) { + if (isset($reflProperties[$key])) { + $reflProperties[$key]->setValue($object, $value); + } + } + return $object; + } + + /** + * Get a reflection properties from in-memory cache and lazy-load if + * class has not been loaded. + * + * @static + * @param string|object $object + * @return array + */ + protected static function getReflProperties($input) + { + if (is_object($input)) { + $input = get_class($input); + } elseif (!is_string($input)) { + throw new Exception\InvalidArgumentException('Input must be a string or an object.'); + } + + if (!isset(self::$reflProperties[$input])) { + $reflClass = new ReflectionClass($input); + $reflProperties = $reflClass->getProperties(); + + foreach($reflProperties as $key => $property) { + $property->setAccessible(true); + self::$reflProperties[$input][$property->getName()] = $property; + } + } + + return self::$reflProperties[$input]; + } +} diff --git a/src/Message.php b/src/Message.php index 7a6bf8cdd..e5e8f088a 100644 --- a/src/Message.php +++ b/src/Message.php @@ -1,4 +1,12 @@ data pairs - * + * * @return array */ public function toArray() @@ -91,7 +79,7 @@ public function toArray() /** * Serialize - * + * * @return string */ public function serialize() @@ -114,7 +102,7 @@ public function serialize() /** * Deserialize - * + * * @param string $data * @return void */ diff --git a/src/SplQueue.php b/src/SplQueue.php index ef7d6a4b9..e753201d8 100644 --- a/src/SplQueue.php +++ b/src/SplQueue.php @@ -1,21 +1,11 @@ markTestSkipped('GLOB_BRACE not available'); } - + $this->assertEquals( glob(__DIR__ . '/_files/{alph,bet}a', GLOB_BRACE), Glob::glob(__DIR__ . '/_files/{alph,bet}a', Glob::GLOB_BRACE, true) ); } + + public function testNonMatchingGlobReturnsArray() + { + $result = Glob::glob('/some/path/{,*.}{this,orthis}.php', Glob::GLOB_BRACE); + $this->assertInternalType('array', $result); + } } diff --git a/test/HydratorTest.php b/test/HydratorTest.php index 2b9fe0462..10fae389e 100644 --- a/test/HydratorTest.php +++ b/test/HydratorTest.php @@ -1,39 +1,27 @@ classMethodsCamelCase = new ClassMethodsCamelCase(); $this->classMethodsCamelCaseMissing = new ClassMethodsCamelCaseMissing(); $this->classMethodsUnderscore = new ClassMethodsUnderscore(); + $this->reflection = new ReflectionAsset; } - + public function testInitiateValues() { $this->assertEquals($this->classMethodsCamelCase->getFooBar(), '1'); @@ -68,9 +62,26 @@ public function testInitiateValues() $this->assertEquals($this->classMethodsUnderscore->getFooBarBaz(), '2'); } + public function testHydratorReflection() + { + $hydrator = new Reflection; + $datas = $hydrator->extract($this->reflection); + $this->assertTrue(isset($datas['foo'])); + $this->assertEquals($datas['foo'], '1'); + $this->assertTrue(isset($datas['fooBar'])); + $this->assertEquals($datas['fooBar'], '2'); + $this->assertTrue(isset($datas['fooBarBaz'])); + $this->assertEquals($datas['fooBarBaz'], '3'); + + $test = $hydrator->hydrate(array('foo' => 'foo', 'fooBar' => 'bar', 'fooBarBaz' => 'baz'), $this->reflection); + $this->assertEquals($test->foo, 'foo'); + $this->assertEquals($test->getFooBar(), 'bar'); + $this->assertEquals($test->getFooBarBaz(), 'baz'); + } + public function testHydratorClassMethodsCamelCase() { - $hydrator = new ClassMethods(true); + $hydrator = new ClassMethods(false); $datas = $hydrator->extract($this->classMethodsCamelCase); $this->assertTrue(isset($datas['fooBar'])); $this->assertEquals($datas['fooBar'], '1'); @@ -81,10 +92,10 @@ public function testHydratorClassMethodsCamelCase() $this->assertEquals($test->getFooBar(), 'foo'); $this->assertEquals($test->getFooBarBaz(), 'bar'); } - + public function testHydratorClassMethodsCamelCaseWithSetterMissing() { - $hydrator = new ClassMethods(true); + $hydrator = new ClassMethods(false); $datas = $hydrator->extract($this->classMethodsCamelCaseMissing); $this->assertTrue(isset($datas['fooBar'])); $this->assertEquals($datas['fooBar'], '1'); @@ -95,10 +106,10 @@ public function testHydratorClassMethodsCamelCaseWithSetterMissing() $this->assertEquals($test->getFooBar(), 'foo'); $this->assertEquals($test->getFooBarBaz(), '2'); } - + public function testHydratorClassMethodsUnderscore() { - $hydrator = new ClassMethods(false); + $hydrator = new ClassMethods(true); $datas = $hydrator->extract($this->classMethodsUnderscore); $this->assertTrue(isset($datas['foo_bar'])); $this->assertEquals($datas['foo_bar'], '1'); @@ -112,7 +123,7 @@ public function testHydratorClassMethodsUnderscore() public function testHydratorClassMethodsIgnoresInvalidValues() { - $hydrator = new ClassMethods(false); + $hydrator = new ClassMethods(true); $data = array( 'foo_bar' => '1', 'foo_bar_baz' => '2', @@ -121,4 +132,18 @@ public function testHydratorClassMethodsIgnoresInvalidValues() $test = $hydrator->hydrate($data, $this->classMethodsUnderscore); $this->assertSame($this->classMethodsUnderscore, $test); } + + public function testHydratorClassMethodsDefaultBehaviorIsConvertUnderscoreToCamelCase() + { + $hydrator = new ClassMethods(); + $datas = $hydrator->extract($this->classMethodsUnderscore); + $this->assertTrue(isset($datas['foo_bar'])); + $this->assertEquals($datas['foo_bar'], '1'); + $this->assertTrue(isset($datas['foo_bar_baz'])); + $this->assertFalse(isset($datas['fooBar'])); + $test = $hydrator->hydrate(array('foo_bar' => 'foo', 'foo_bar_baz' => 'bar'), $this->classMethodsUnderscore); + $this->assertSame($this->classMethodsUnderscore, $test); + $this->assertEquals($test->getFooBar(), 'foo'); + $this->assertEquals($test->getFooBarBaz(), 'bar'); + } } diff --git a/test/MessageTest.php b/test/MessageTest.php index 6060bb31d..9f81add04 100644 --- a/test/MessageTest.php +++ b/test/MessageTest.php @@ -1,4 +1,12 @@ assertInstanceOf('Zend\Stdlib\Message', $ret); $this->assertEquals('I can set content', $message->getContent()); } - + public function testMessageCanSetAndGetMetadataKeyAsString() { $message = new Message(); @@ -22,7 +30,7 @@ public function testMessageCanSetAndGetMetadataKeyAsString() $this->assertEquals('bar', $message->getMetadata('foo')); $this->assertEquals(array('foo' => 'bar'), $message->getMetadata()); } - + public function testMessageCanSetAndGetMetadataKeyAsArray() { $message = new Message(); @@ -30,29 +38,29 @@ public function testMessageCanSetAndGetMetadataKeyAsArray() $this->assertInstanceOf('Zend\Stdlib\Message', $ret); $this->assertEquals('bar', $message->getMetadata('foo')); } - + public function testMessageGetMetadataWillUseDefaultValueIfNoneExist() { $message = new Message(); $this->assertEquals('bar', $message->getMetadata('foo', 'bar')); } - + public function testMessageThrowsExceptionOnInvalidKeyForMetadataSet() { $message = new Message(); - + $this->setExpectedException('Zend\Stdlib\Exception\InvalidArgumentException'); $message->setMetadata(new \stdClass()); } - + public function testMessageThrowsExceptionOnInvalidKeyForMetadataGet() { $message = new Message(); - + $this->setExpectedException('Zend\Stdlib\Exception\InvalidArgumentException'); $message->getMetadata(new \stdClass()); } - + public function testMessageToStringWorks() { $message = new Message(); diff --git a/test/OptionsTest.php b/test/OptionsTest.php index 2678f24f1..a834bde93 100644 --- a/test/OptionsTest.php +++ b/test/OptionsTest.php @@ -1,29 +1,54 @@ 1)); - + $this->assertEquals(1, $options->test_field); } - + public function testConstructionWithTraversable() { $config = new ArrayObject(array('test_field' => 1)); $options = new TestOptions($config); - + $this->assertEquals(1, $options->test_field); } - + + public function testInvalidFieldThrowsException() + { + $this->setExpectedException('BadMethodCallException'); + $options = new TestOptions(array('foo' => 'bar')); + } + + public function testNonStrictOptionsDoesNotThrowException() + { + try { + $options = new TestOptionsNoStrict(array('foo' => 'bar')); + } catch (\Exception $e) { + $this->fail('Nonstrict options should not throw an exception'); + } + } + + public function testConstructionWithNull() { try { @@ -32,14 +57,13 @@ public function testConstructionWithNull() $this->fail("Unexpected InvalidArgumentException raised"); } } - + public function testUnsetting() { $options = new TestOptions(array('test_field' => 1)); - + $this->assertEquals(true, isset($options->test_field)); unset($options->testField); $this->assertEquals(false, isset($options->test_field)); - } } diff --git a/test/ParametersTest.php b/test/ParametersTest.php index 7f4e1cb61..5ebba9b14 100644 --- a/test/ParametersTest.php +++ b/test/ParametersTest.php @@ -1,4 +1,12 @@ queue->toArray(); diff --git a/test/SplQueueTest.php b/test/SplQueueTest.php index 7412a68e0..5eb3af1ac 100644 --- a/test/SplQueueTest.php +++ b/test/SplQueueTest.php @@ -1,23 +1,11 @@ fooBar; } - + public function setFooBar($value) { $this->fooBar = $value; return $this; } - + public function getFooBarBaz() { return $this->fooBarBaz; } - + public function setFooBarBaz($value) { $this->fooBarBaz = $value; return $this; } -} \ No newline at end of file +} diff --git a/test/TestAsset/ClassMethodsCamelCaseMissing.php b/test/TestAsset/ClassMethodsCamelCaseMissing.php index 03ffb4ee4..7ad333e26 100644 --- a/test/TestAsset/ClassMethodsCamelCaseMissing.php +++ b/test/TestAsset/ClassMethodsCamelCaseMissing.php @@ -1,36 +1,44 @@ fooBar; } - + public function setFooBar($value) { $this->fooBar = $value; return $this; } - + public function getFooBarBaz() { return $this->fooBarBaz; } - + /* * comment to detection verification - * + * public function setFooBarBaz($value) { $this->fooBarBaz = $value; return $this; } */ -} \ No newline at end of file +} diff --git a/test/TestAsset/ClassMethodsUnderscore.php b/test/TestAsset/ClassMethodsUnderscore.php index 35c4c0baa..47d5cf1bb 100644 --- a/test/TestAsset/ClassMethodsUnderscore.php +++ b/test/TestAsset/ClassMethodsUnderscore.php @@ -1,32 +1,40 @@ foo_bar; } - + public function setFooBar($value) { $this->foo_bar = $value; return $this; } - + public function getFooBarBaz() { return $this->foo_bar_baz; } - + public function setFooBarBaz($value) { $this->foo_bar_baz = $value; return $this; } -} \ No newline at end of file +} diff --git a/test/TestAsset/Reflection.php b/test/TestAsset/Reflection.php new file mode 100644 index 000000000..97ddc1b12 --- /dev/null +++ b/test/TestAsset/Reflection.php @@ -0,0 +1,30 @@ +fooBar; + } + + public function getFooBarBaz() + { + return $this->fooBarBaz; + } +} diff --git a/test/TestAsset/TestOptions.php b/test/TestAsset/TestOptions.php index 85bcf5f0c..a2fbe9842 100644 --- a/test/TestAsset/TestOptions.php +++ b/test/TestAsset/TestOptions.php @@ -1,21 +1,29 @@ testField = $value; } - + public function getTestField() { return $this->testField; diff --git a/test/TestAsset/TestOptionsNoStrict.php b/test/TestAsset/TestOptionsNoStrict.php new file mode 100644 index 000000000..cd1a557ba --- /dev/null +++ b/test/TestAsset/TestOptionsNoStrict.php @@ -0,0 +1,33 @@ +testField = $value; + } + + public function getTestField() + { + return $this->testField; + } +}