From ad950f8356d4da5f1cb4c208a202772db54ccbe2 Mon Sep 17 00:00:00 2001 From: Stepan Mazurov Date: Fri, 28 Aug 2015 19:55:37 -0600 Subject: [PATCH 1/4] Added a way to get/set meta properties Meta properties are sometimes great to use in cases where you do not have defined property (as its not in the db) but you still want to set or get a property from an entity. For example, if you have category_id stored in the db, it would be great to map that category id to an actual category name. --- src/Entity.php | 31 ++++++++++++++++++------------- tests/EntityTest.php | 16 ++++++++++++++++ tests/Fixtures/TestEntity.php | 17 +++++++++++++++++ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/Entity.php b/src/Entity.php index d826615..8a54bfc 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -120,12 +120,6 @@ public function isLoaded() public function fromArray(array $data) { foreach ($data as $k => $v) { - if (!property_exists($this, $k) || in_array($k, $this->propertyBlacklist)) { - throw new InvalidArgumentException(sprintf( - '$data key: "%s" was not listed in the allowed properties', - $k - )); - } $this->setProp($k, $v); } @@ -188,7 +182,7 @@ public function isClean() return empty($this->propertyDirty); } - /** + /** * @param $key * @param $value */ @@ -197,18 +191,28 @@ protected function setProp($key, $value) if (!is_string($key)) { throw new InvalidArgumentException('$key must be a string'); } - if (!property_exists($this, $key) || in_array($key, $this->propertyBlacklist)) { + + $methodName = $this->normalizeAccessor($key); + $hasAccessor = method_exists($this, $methodName); + + if ((!property_exists($this, $key) || in_array($key, $this->propertyBlacklist))) { + if ($hasAccessor) { + // let meta property set the actual prop. + $this->$methodName($value); + return; + } + throw new InvalidArgumentException(sprintf( 'Key: "%s" is not an allowed property', $key )); } + $this->propertyLoaded[] = $key; if ($this->getProp($key) !== $value) { - $methodName = $this->normalizeAccessor($key); - if (method_exists($this, $methodName)) { + if ($hasAccessor) { $this->$methodName($value); } else { $this->$key = $value; @@ -223,15 +227,16 @@ protected function setProp($key, $value) */ protected function getProp($key) { - if (!in_array($key, $this->propertyLoaded)) { + $methodName = $this->normalizeAccessor($key, false); + $hasAccessor = method_exists($this, $methodName); + if (!in_array($key, $this->propertyLoaded) && !$hasAccessor) { throw new InvalidArgumentException(sprintf( 'Key: "%s" was not loaded', $key )); } - $methodName = $this->normalizeAccessor($key, false); - if (method_exists($this, $methodName)) { + if ($hasAccessor) { return $this->$methodName(); } else { return $this->$key; diff --git a/tests/EntityTest.php b/tests/EntityTest.php index 75d8c59..bf3b5ba 100644 --- a/tests/EntityTest.php +++ b/tests/EntityTest.php @@ -70,6 +70,22 @@ public function test_assignment_to_nonexistant_property() $entity->fake = 1; } + public function test_meta_property_get() + { + $entity = new TestEntity(); + $this->assertEquals($entity::META_PROPERTY, $entity->customMethodProp); + } + + public function test_meta_property_set() + { + $entity = new TestEntity(); + $entity->uppercaseTestProp = 'lowercase_test'; + $this->assertEquals(strtoupper('lowercase_test'), $entity->testProp); + + $entity2 = new TestEntity(['uppercaseTestProp' => 'lowercase_test']); + $this->assertEquals(strtoupper('lowercase_test'), $entity->testProp); + } + public function test_isset() { $entity = new TestEntity(['testProp' => 'test1']); diff --git a/tests/Fixtures/TestEntity.php b/tests/Fixtures/TestEntity.php index f3a918b..f5c3d21 100644 --- a/tests/Fixtures/TestEntity.php +++ b/tests/Fixtures/TestEntity.php @@ -17,6 +17,13 @@ class TestEntity extends Entity protected $test_prop; // @codingStandardsIgnoreEnd + /** + * For accessing from tests + * + * @var string + */ + const META_PROPERTY = 'This is a meta property'; + protected function getGetMethodProp() { return $this->getMethodProp . ' From Get'; @@ -26,4 +33,14 @@ protected function setSetMethodProp($value) { $this->setMethodProp = $value . ' From Set'; } + + protected function getCustomMethodProp() + { + return self::META_PROPERTY; + } + + public function setUppercaseTestProp($value) + { + $this->setProp('testProp', strtoupper($value)); + } } From 1dee8e161bc2371aa9bfb95d34559bbb37b28c7e Mon Sep 17 00:00:00 2001 From: Stepan Mazurov Date: Fri, 28 Aug 2015 19:57:15 -0600 Subject: [PATCH 2/4] Fix make sniff command --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e14624d..c235004 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +SOCIALENGINE_STRD='./vendor/socialengine/sniffer-rules/src/Socialengine/SnifferRules/Standard/SocialEngine' + test: php ./vendor/bin/phpunit @@ -5,8 +7,7 @@ test-cover: php ./vendor/bin/phpunit --coverage-clover=coverage.clover sniff: - php ./vendor/bin/phpcs --colors --standard=SocialEngine --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests + php ./vendor/bin/phpcs --colors --standard=${SOCIALENGINE_STRD} --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests sniff-fix: - php ./vendor/bin/phpcbf --colors --standard='./vendor/socialengine/sniffer-rules/src/Socialengine/SnifferRules/Standard/SocialEngine' --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests - + php ./vendor/bin/phpcbf --colors --standard=${SOCIALENGINE_STRD} --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests From 7a3782aafa8f7eb82eec3cdc1b1229326114c536 Mon Sep 17 00:00:00 2001 From: Stepan Mazurov Date: Fri, 28 Aug 2015 20:15:58 -0600 Subject: [PATCH 3/4] Documented meta set/get attributes --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/README.md b/README.md index 2363a0d..07ad35a 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,67 @@ array(0) { */ ``` +### Meta Attributes + +You can set and get "meta" attributes - ones that do not have attributes directly attached to them. + +This is good if you have an entity that stores a `category_id` but does not store the category name + +```php + 'Awesome' + ]; + + return $categoryNamesMap[$this->getProp('category_id')]; + } + + /** + * You can also set meta properties + */ + protected function setName($name) + { + list($firstName, $lastName) = explode(' ', $name, 2); + + $this->fromArray([ + 'first_name' => $firstName, + 'last_name' => $lastName + ]); + } +} + +$entity = new MyEntity(['category_id' => 1]); +var_dump($entity->categoryName); +/* +string(7) "Awesome" +*/ + +$entity['name'] = 'Duke Orcino'; +var_dump($entity->toArray(true)); +/* +array(2) { + 'first_name' => + string(4) "Duke" + 'last_name' => + string(6) "Orcino" +} +*/ +``` + +The entity above will let you access Meta attributes via the normal syntax. Use build in `setProp` and `getProp` so +that you can leverage some of the validation and attribute checking code **Unum** offers you. + ## Code Style Please follow the following guides and code standards: From 82d2b038582088eedbe34321fbdd64a9d44ddc16 Mon Sep 17 00:00:00 2001 From: Stepan Mazurov Date: Fri, 28 Aug 2015 20:21:24 -0600 Subject: [PATCH 4/4] fix travis --- Makefile | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c235004..e5b4405 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ -SOCIALENGINE_STRD='./vendor/socialengine/sniffer-rules/src/Socialengine/SnifferRules/Standard/SocialEngine' +SOCIALENGINE_STRD="`pwd`/vendor/socialengine/sniffer-rules/src/Socialengine/SnifferRules/Standard/" +PHPCS=php ./vendor/bin/phpcs +INSTALLED=$(shell ${PHPCS} -i) test: php ./vendor/bin/phpunit @@ -6,8 +8,13 @@ test: test-cover: php ./vendor/bin/phpunit --coverage-clover=coverage.clover -sniff: - php ./vendor/bin/phpcs --colors --standard=${SOCIALENGINE_STRD} --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests +sniff: check-standard + ${PHPCS} --colors --standard=SocialEngine --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests -sniff-fix: - php ./vendor/bin/phpcbf --colors --standard=${SOCIALENGINE_STRD} --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests +sniff-fix: check-standard + php ./vendor/bin/phpcbf --colors --standard=SocialEngine --runtime-set allowSnakeCaseMethodName '[{"classSuffix":"Test","methodPrefix":["test"]}]' src tests + +check-standard: +ifeq (,$(findstring SocialEngine, $(INSTALLED))) + php ./vendor/bin/phpcs --config-set installed_paths ${SOCIALENGINE_STRD} +endif