From 8da2718c277a9a316fc8970173304bd0e57a660f Mon Sep 17 00:00:00 2001 From: Anup Dugar Date: Sun, 19 Apr 2015 21:34:49 -0500 Subject: [PATCH 01/30] MAGETWO-36062: Add ACL resources configuration section to data_object.xml - Refactored custom_attributes node to extension_attributes - Refactored data_object xml and xsd file to service_data_attributes --- ...object.xml => service_data_attributes.xml} | 6 ++--- ...object.xml => service_data_attributes.xml} | 10 ++++----- ...object.xml => service_data_attributes.xml} | 6 ++--- ...object.xml => service_data_attributes.xml} | 6 ++--- ...object.xml => service_data_attributes.xml} | 10 ++++----- ...object.xml => service_data_attributes.xml} | 10 ++++----- ...object.xml => service_data_attributes.xml} | 22 +++++++++---------- .../Customer/Model/FileResolverStub.php | 2 +- ...object.xml => service_data_attributes.xml} | 22 +++++++++---------- .../Api/Config/_files/config_one.xml | 14 ++++++------ .../Api/Config/_files/config_two.xml | 6 ++--- .../Framework/Api/Config/Converter.php | 2 +- .../Magento/Framework/Api/Config/Reader.php | 6 ++--- .../Framework/Api/Config/SchemaLocator.php | 2 +- .../Api/Test/Unit/Config/ConverterTest.php | 2 +- .../Test/Unit/Config/SchemaLocatorTest.php | 4 ++-- ..._valid.xml => service_data_attributes.xml} | 14 ++++++------ ...object.xsd => service_data_attributes.xsd} | 4 ++-- 18 files changed, 74 insertions(+), 74 deletions(-) rename app/code/Magento/Bundle/etc/{data_object.xml => service_data_attributes.xml} (75%) rename app/code/Magento/GiftMessage/etc/{data_object.xml => service_data_attributes.xml} (64%) rename app/code/Magento/GroupedProduct/etc/{data_object.xml => service_data_attributes.xml} (66%) rename app/code/Magento/Sales/etc/{data_object.xml => service_data_attributes.xml} (78%) rename dev/tests/api-functional/_files/Magento/TestModule1/etc/{data_object.xml => service_data_attributes.xml} (69%) rename dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/{data_object.xml => service_data_attributes.xml} (69%) rename dev/tests/integration/testsuite/Magento/Catalog/_files/etc/{data_object.xml => service_data_attributes.xml} (63%) rename dev/tests/integration/testsuite/Magento/Customer/_files/etc/{data_object.xml => service_data_attributes.xml} (63%) rename lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/{data_object_valid.xml => service_data_attributes.xml} (59%) rename lib/internal/Magento/Framework/Api/etc/{data_object.xsd => service_data_attributes.xsd} (86%) diff --git a/app/code/Magento/Bundle/etc/data_object.xml b/app/code/Magento/Bundle/etc/service_data_attributes.xml similarity index 75% rename from app/code/Magento/Bundle/etc/data_object.xml rename to app/code/Magento/Bundle/etc/service_data_attributes.xml index 88e317dafc78c..331149b6203ea 100644 --- a/app/code/Magento/Bundle/etc/data_object.xml +++ b/app/code/Magento/Bundle/etc/service_data_attributes.xml @@ -5,10 +5,10 @@ * See COPYING.txt for license details. */ --> - - + + - + diff --git a/app/code/Magento/GiftMessage/etc/data_object.xml b/app/code/Magento/GiftMessage/etc/service_data_attributes.xml similarity index 64% rename from app/code/Magento/GiftMessage/etc/data_object.xml rename to app/code/Magento/GiftMessage/etc/service_data_attributes.xml index a1255cc8a161a..f02c0a717e169 100644 --- a/app/code/Magento/GiftMessage/etc/data_object.xml +++ b/app/code/Magento/GiftMessage/etc/service_data_attributes.xml @@ -5,11 +5,11 @@ * See COPYING.txt for license details. */ --> - - + + - - + + - + diff --git a/app/code/Magento/GroupedProduct/etc/data_object.xml b/app/code/Magento/GroupedProduct/etc/service_data_attributes.xml similarity index 66% rename from app/code/Magento/GroupedProduct/etc/data_object.xml rename to app/code/Magento/GroupedProduct/etc/service_data_attributes.xml index d6a76ebaa081f..0618cc9286cfd 100644 --- a/app/code/Magento/GroupedProduct/etc/data_object.xml +++ b/app/code/Magento/GroupedProduct/etc/service_data_attributes.xml @@ -5,8 +5,8 @@ * See COPYING.txt for license details. */ --> - - + + - + diff --git a/app/code/Magento/Sales/etc/data_object.xml b/app/code/Magento/Sales/etc/service_data_attributes.xml similarity index 78% rename from app/code/Magento/Sales/etc/data_object.xml rename to app/code/Magento/Sales/etc/service_data_attributes.xml index 8ef8080db8a29..1e7f320c18ed6 100644 --- a/app/code/Magento/Sales/etc/data_object.xml +++ b/app/code/Magento/Sales/etc/service_data_attributes.xml @@ -5,10 +5,10 @@ * See COPYING.txt for license details. */ --> - - + + - + diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/service_data_attributes.xml similarity index 69% rename from dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml rename to dev/tests/api-functional/_files/Magento/TestModule1/etc/service_data_attributes.xml index de2236e2195f3..fa96514a063b6 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/service_data_attributes.xml @@ -5,13 +5,13 @@ * See COPYING.txt for license details. */ --> - - + + - - + + - + diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/service_data_attributes.xml similarity index 69% rename from dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml rename to dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/service_data_attributes.xml index ece2b1f581775..f11e639ccd275 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/service_data_attributes.xml @@ -5,13 +5,13 @@ * See COPYING.txt for license details. */ --> - - + + - - + + - + diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/data_object.xml b/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/service_data_attributes.xml similarity index 63% rename from dev/tests/integration/testsuite/Magento/Catalog/_files/etc/data_object.xml rename to dev/tests/integration/testsuite/Magento/Catalog/_files/etc/service_data_attributes.xml index c2888a64ee00c..93cf7bfb484a6 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/data_object.xml +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/service_data_attributes.xml @@ -5,22 +5,22 @@ * See COPYING.txt for license details. */ --> - - - - + + + + - - + + - - + + - - + + - + diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php b/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php index 48d81d30eb841..9ee9ed911f7c0 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php @@ -21,7 +21,7 @@ public function get($filename, $scope) 'path' => realpath(__DIR__ . '/../_files/etc'), ] ); - $paths = ['data_object.xml']; + $paths = ['service_data_attributes.xml']; return new \Magento\Framework\Config\FileIterator($readDirectory, $paths); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/etc/data_object.xml b/dev/tests/integration/testsuite/Magento/Customer/_files/etc/service_data_attributes.xml similarity index 63% rename from dev/tests/integration/testsuite/Magento/Customer/_files/etc/data_object.xml rename to dev/tests/integration/testsuite/Magento/Customer/_files/etc/service_data_attributes.xml index a75fa2a653213..a7ae041eda768 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/etc/data_object.xml +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/etc/service_data_attributes.xml @@ -5,22 +5,22 @@ * See COPYING.txt for license details. */ --> - - - - + + + + - - + + - - + + - - + + - + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml index f5a3d522454ab..82aa641d5e8bd 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml @@ -5,14 +5,14 @@ * See COPYING.txt for license details. */ --> - - - - + + + + - - + + - + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml index 629efb9b7a30a..5596f61e572f4 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml @@ -5,9 +5,9 @@ * See COPYING.txt for license details. */ --> - - + + - + diff --git a/lib/internal/Magento/Framework/Api/Config/Converter.php b/lib/internal/Magento/Framework/Api/Config/Converter.php index f21db3bbd9b22..f0fecc73bfe5b 100644 --- a/lib/internal/Magento/Framework/Api/Config/Converter.php +++ b/lib/internal/Magento/Framework/Api/Config/Converter.php @@ -21,7 +21,7 @@ public function convert($source) } /** @var \DOMNodeList $types */ - $types = $source->getElementsByTagName('custom_attributes'); + $types = $source->getElementsByTagName('extension_attributes'); /** @var \DOMNode $type */ foreach ($types as $type) { $typeConfig = []; diff --git a/lib/internal/Magento/Framework/Api/Config/Reader.php b/lib/internal/Magento/Framework/Api/Config/Reader.php index 8cd1a8ac32935..6bc97c71c1156 100644 --- a/lib/internal/Magento/Framework/Api/Config/Reader.php +++ b/lib/internal/Magento/Framework/Api/Config/Reader.php @@ -13,8 +13,8 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem * @var array */ protected $_idAttributes = [ - '/config/custom_attributes' => 'for', - '/config/custom_attributes/attribute' => 'code', + '/config/extension_attributes' => 'for', + '/config/extension_attributes/attribute' => 'code', ]; /** @@ -32,7 +32,7 @@ public function __construct( \Magento\Framework\Api\Config\Converter $converter, \Magento\Framework\Api\Config\SchemaLocator $schemaLocator, \Magento\Framework\Config\ValidationStateInterface $validationState, - $fileName = 'data_object.xml', + $fileName = 'service_data_attributes.xml', $idAttributes = [], $domDocumentClass = 'Magento\Framework\Config\Dom', $defaultScope = 'global' diff --git a/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php b/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php index 86662ab252813..1e8334c643def 100644 --- a/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php +++ b/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php @@ -16,7 +16,7 @@ class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface */ public function getSchema() { - return realpath(__DIR__ . '/../etc/data_object.xsd'); + return realpath(__DIR__ . '/../etc/service_data_attributes.xsd'); } /** diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php index 94f5a4494a75d..2a4c66f031558 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php @@ -55,7 +55,7 @@ public function testConvert() ], ]; - $xmlFile = __DIR__ . '/_files/data_object_valid.xml'; + $xmlFile = __DIR__ . '/_files/service_data_attributes.xml'; $dom = new \DOMDocument(); $dom->loadXML(file_get_contents($xmlFile)); $result = $this->_converter->convert($dom); diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php index f0df38d59a070..f05583db04901 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php @@ -22,7 +22,7 @@ protected function setUp() public function testGetSchema() { - $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/data_object.xsd'); + $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd'); $actual = str_replace('\\', '/', $this->_model->getSchema()); $this->assertEquals($expected, $actual); } @@ -30,7 +30,7 @@ public function testGetSchema() public function testGetPerFileSchema() { $actual = str_replace('\\', '/', $this->_model->getPerFileSchema()); - $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/data_object.xsd'); + $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd'); $this->assertEquals($expected, $actual); } } diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/data_object_valid.xml b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml similarity index 59% rename from lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/data_object_valid.xml rename to lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml index 67606deab2eb4..423cf6f68410e 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/data_object_valid.xml +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml @@ -5,14 +5,14 @@ * See COPYING.txt for license details. */ --> - - - - + + + + - - + + - + diff --git a/lib/internal/Magento/Framework/Api/etc/data_object.xsd b/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd similarity index 86% rename from lib/internal/Magento/Framework/Api/etc/data_object.xsd rename to lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd index 0983dbbf91238..7ab744a6c3b07 100644 --- a/lib/internal/Magento/Framework/Api/etc/data_object.xsd +++ b/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd @@ -9,7 +9,7 @@ - + Main schema element. Extended Attributes @@ -25,7 +25,7 @@ - + From c19b946d56a49a6942f8011ec05c483bfea16370 Mon Sep 17 00:00:00 2001 From: Anup Dugar Date: Sun, 19 Apr 2015 23:43:49 -0700 Subject: [PATCH 02/30] MAGETWO-36062: Add ACL resources configuration section to data_object.xml - Updated xsd to add acl resource per attribute --- .../Api/etc/service_data_attributes.xsd | 63 ++++++++++++------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd b/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd index 7ab744a6c3b07..24590e3d758c7 100644 --- a/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd +++ b/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd @@ -5,30 +5,45 @@ * See COPYING.txt for license details. */ --> - - - - - - - Main schema element. Extended Attributes - - - - - - - - + + + + + + + Main schema element. Extended Attributes + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + From 7c00cb90333789948ce6c2a3bace3c27cf43e0ca Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 20 Apr 2015 15:58:30 -0500 Subject: [PATCH 03/30] MAGETWO-35806: [API] All path parameters in the rest URI are lowercased - Remove the lowercasing of the path. Paths are case-sensitive --- .../Webapi/Controller/Rest/Router/Route.php | 11 ++--------- app/code/Magento/Webapi/Model/Rest/Config.php | 18 +----------------- .../Unit/Controller/Rest/Router/RouteTest.php | 6 +++--- .../Webapi/Routing/RestErrorHandlingTest.php | 2 +- 4 files changed, 7 insertions(+), 30 deletions(-) diff --git a/app/code/Magento/Webapi/Controller/Rest/Router/Route.php b/app/code/Magento/Webapi/Controller/Rest/Router/Route.php index 5c125c29611d9..03e6d2fd8ca06 100644 --- a/app/code/Magento/Webapi/Controller/Rest/Router/Route.php +++ b/app/code/Magento/Webapi/Controller/Rest/Router/Route.php @@ -69,7 +69,7 @@ protected function getRouteParts() $this->variables[$key] = substr($value, 1); $value = null; } - $result[$key] = strtolower($value); + $result[$key] = $value; } return $result; } @@ -92,19 +92,12 @@ protected function isVariable($value) /** * Retrieve unified requested path * - * Lowercase all path chunks, except variables names. - * E.g. the path '/V1/Categories/:categoryId' will be converted to '/v1/categories/:categoryId'. - * * @param string $path * @return array */ protected function getPathParts($path) { - $result = explode('/', trim($path, '/')); - array_walk($result, function (&$item) { - $item = substr($item, 0, 1) === ":" ? $item : strtolower($item); - }); - return $result; + return explode('/', trim($path, '/')); } /** diff --git a/app/code/Magento/Webapi/Model/Rest/Config.php b/app/code/Magento/Webapi/Model/Rest/Config.php index dfee1d873c021..51d0e67d78036 100644 --- a/app/code/Magento/Webapi/Model/Rest/Config.php +++ b/app/code/Magento/Webapi/Model/Rest/Config.php @@ -67,7 +67,7 @@ protected function _createRoute($routeData) /** @var $route \Magento\Webapi\Controller\Rest\Router\Route */ $route = $this->_routeFactory->createRoute( 'Magento\Webapi\Controller\Rest\Router\Route', - $this->_formatRoutePath($routeData[self::KEY_ROUTE_PATH]) + $routeData[self::KEY_ROUTE_PATH] ); $route->setServiceClass($routeData[self::KEY_CLASS]) @@ -78,22 +78,6 @@ protected function _createRoute($routeData) return $route; } - /** - * Lowercase all parts of the given route path except for the path parameters. - * - * @param string $routePath The route path (e.g. '/V1/Categories/:categoryId') - * @return string The modified route path (e.g. '/v1/categories/:categoryId') - */ - protected function _formatRoutePath($routePath) - { - $routePathParts = explode('/', $routePath); - $pathParts = []; - foreach ($routePathParts as $pathPart) { - $pathParts[] = substr($pathPart, 0, 1) === ":" ? $pathPart : strtolower($pathPart); - } - return implode('/', $pathParts); - } - /** * Get service base URL * diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php index 6732d012dc1e7..4a9192b36882b 100644 --- a/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php @@ -95,10 +95,7 @@ public function dataProviderRoutes() ['/V1/one/two/:threeValue/four/:fiveValue', '/V1/one/two/3/four/5', ['threeValue' => 3, 'fiveValue' => 5]], ['/v1/One', '/v1/One', []], - ['/v1/oNe', '/V1/one', []], - ['/v1/onE', '/V1/oNe', []], - ['/v1/One/:twoValue', '/V1/one/2', ['twoValue' => 2]], ['/v1/oNe/:TwoValue', '/v1/oNe/2', ['TwoValue' => 2]], ['/v1/onE/:twovalue', '/v1/onE/2', ['twovalue' => 2]], @@ -108,6 +105,9 @@ public function dataProviderRoutes() ['/V1/one-one/:two_value', '/V1/one-one/2', ['two_value' => 2]], // Error + ['/v1/oNe', '/V1/one', false], + ['/v1/onE', '/V1/oNe', false], + ['/v1/One/:twoValue', '/V1/one/2', false], ['/V1/one', '/V1/two', false], ['/V1/one/:twoValue', '/V1/one', false], ['/V1/one/two', '/V1/one', false], diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php index 41d6e8a2914de..a64744df17ad6 100644 --- a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php @@ -81,7 +81,7 @@ public function testOtherException() { $serviceInfo = [ 'rest' => [ - 'resourcePath' => '/V1/errortest/otherexception', + 'resourcePath' => '/V1/errortest/otherException', 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, ], ]; From 4c7885d9407a6a9cdb8800c976f6e6b18d50a4c8 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Thu, 23 Apr 2015 14:04:00 -0500 Subject: [PATCH 04/30] MAGETWO-36062: Add ACL resources configuration section to data_object.xml - Read in the configuration for the resource permissions for data object attributes - Change clients of the (former data_object.xml) config to use the new config data structure --- .../ExtensionAttributesGenerator.php | 9 ++++-- .../Framework/Api/Config/Converter.php | 20 ++++++++++-- .../Api/Test/Unit/Config/ConverterTest.php | 32 +++++++++++++++++-- .../Config/_files/service_data_attributes.xml | 13 ++++++++ 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php b/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php index 98f5dc5d5e072..f1d50f50d084d 100644 --- a/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php +++ b/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php @@ -8,6 +8,7 @@ use Magento\Framework\Code\Generator\DefinedClasses; use Magento\Framework\Code\Generator\Io; use Magento\Framework\Api\SimpleDataObjectConverter; +use Magento\Framework\Api\Config\Converter; /** * Code generator for data object extensions. @@ -79,7 +80,8 @@ protected function _getClassProperties() protected function _getClassMethods() { $methods = []; - foreach ($this->getCustomAttributes() as $attributeName => $attributeType) { + foreach ($this->getCustomAttributes() as $attributeName => $attributeMetadata) { + $attributeType = $attributeMetadata[Converter::DATA_TYPE]; $propertyName = SimpleDataObjectConverter::snakeCaseToCamelCase($attributeName); $getterName = 'get' . ucfirst($propertyName); $setterName = 'set' . ucfirst($propertyName); @@ -150,11 +152,12 @@ protected function getCustomAttributes() } $dataInterface = ltrim($this->getSourceClassName(), '\\'); if (isset($this->allCustomAttributes[$dataInterface])) { - foreach ($this->allCustomAttributes[$dataInterface] as $attributeName => $attributeType) { + foreach ($this->allCustomAttributes[$dataInterface] as $attributeName => $attributeMetadata) { + $attributeType = $attributeMetadata[Converter::DATA_TYPE]; if (strpos($attributeType, '\\') !== false) { /** Add preceding slash to class names, while leaving primitive types as is */ $attributeType = $this->_getFullyQualifiedClassName($attributeType); - $this->allCustomAttributes[$dataInterface][$attributeName] = + $this->allCustomAttributes[$dataInterface][$attributeName][Converter::DATA_TYPE] = $this->_getFullyQualifiedClassName($attributeType); } } diff --git a/lib/internal/Magento/Framework/Api/Config/Converter.php b/lib/internal/Magento/Framework/Api/Config/Converter.php index f0fecc73bfe5b..68914a98b5c77 100644 --- a/lib/internal/Magento/Framework/Api/Config/Converter.php +++ b/lib/internal/Magento/Framework/Api/Config/Converter.php @@ -7,6 +7,9 @@ class Converter implements \Magento\Framework\Config\ConverterInterface { + const RESOURCE_PERMISSIONS = "resourceRefs"; + const DATA_TYPE = "type"; + /** * Convert dom node tree to array * @@ -32,9 +35,22 @@ public function convert($source) $code = $attribute->getAttribute('code'); $codeType = $attribute->getAttribute('type'); - if ($code && $codeType) { - $typeConfig[$code] = $codeType; + $resourcesElement = $attribute->getElementsByTagName('resources')->item(0); + $resourceRefs = []; + if ($resourcesElement && $resourcesElement->nodeType === XML_ELEMENT_NODE) { + $singleResourceElements = $resourcesElement->getElementsByTagName('resource'); + foreach ($singleResourceElements as $element) { + if ($element->nodeType != XML_ELEMENT_NODE) { + continue; + } + $resourceRefs[] = $element->attributes->getNamedItem('ref')->nodeValue; + } } + + $typeConfig[$code] = [ + self::DATA_TYPE => $codeType, + self::RESOURCE_PERMISSIONS => $resourceRefs, + ]; } $output[$typeName] = $typeConfig; diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php index 2a4c66f031558..d4629213b20be 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Framework\Api\Test\Unit\Config; +use Magento\Framework\Api\Config\Converter; + class ConverterTest extends \PHPUnit_Framework_TestCase { /** @@ -47,11 +49,35 @@ public function testConvert() 'Magento\Tax\Api\Data\TaxRateInterface' => [ ], 'Magento\Catalog\Api\Data\ProductInterface' => [ - 'stock_item' => 'Magento\CatalogInventory\Api\Data\StockItemInterface' + 'stock_item' => [ + Converter::DATA_TYPE => 'Magento\CatalogInventory\Api\Data\StockItemInterface', + Converter::RESOURCE_PERMISSIONS => [], + ], ], 'Magento\Customer\Api\Data\CustomerInterface' => [ - 'custom_1' => 'Magento\Customer\Api\Data\CustomerCustom', - 'custom_2' => 'Magento\CustomerExtra\Api\Data\CustomerCustom2' + 'custom_1' => [ + Converter::DATA_TYPE => 'Magento\Customer\Api\Data\CustomerCustom', + Converter::RESOURCE_PERMISSIONS => [], + ], + 'custom_2' => [ + Converter::DATA_TYPE => 'Magento\CustomerExtra\Api\Data\CustomerCustom2', + Converter::RESOURCE_PERMISSIONS => [], + ], + ], + 'Magento\Customer\Api\Data\CustomerInterface2' => [ + 'custom_with_permission' => [ + Converter::DATA_TYPE => 'Magento\Customer\Api\Data\CustomerCustom', + Converter::RESOURCE_PERMISSIONS => [ + 'Magento_Customer::manage', + ], + ], + 'custom_with_multiple_permissions' => [ + Converter::DATA_TYPE => 'Magento\CustomerExtra\Api\Data\CustomerCustom2', + Converter::RESOURCE_PERMISSIONS => [ + 'Magento_Customer::manage', + 'Magento_Customer::manage2', + ], + ], ], ]; diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml index 423cf6f68410e..4f6a9838bfcdb 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml @@ -15,4 +15,17 @@ + + + + + + + + + + + + + From 2a1a29c07e459474bbce235188b977cc4083de46 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Thu, 23 Apr 2015 14:26:45 -0500 Subject: [PATCH 05/30] MAGETWO-36064: Add ACL configuration to CatalgInventory attributes of the ProductInterface - Add ACL for CatalogInventory attributes - Right now, the implementation for the CatalogInventory extension attributes does not exist, but it will in a future merge with another team --- .../etc/service_data_attributes.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 app/code/Magento/CatalogInventory/etc/service_data_attributes.xml diff --git a/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml new file mode 100644 index 0000000000000..587b98b401a09 --- /dev/null +++ b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + From 9910c884146fb35a2175f123bdffd056a2714abd Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Thu, 23 Apr 2015 15:26:23 -0500 Subject: [PATCH 06/30] MAGETWO-36062: Add ACL resources configuration section to data_object.xml - Fix framework unit tests --- .../ExtensionAttributesGeneratorTest.php | 18 +++++++++++++++--- ...tensionAttributesInterfaceGeneratorTest.php | 17 ++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php index 5207a20588c73..efdeb4ae91434 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php @@ -6,6 +6,8 @@ // @codingStandardsIgnoreFile namespace Magento\Framework\Api\Test\Unit\Code\Generator; +use Magento\Framework\Api\Config\Converter; + class ExtensionAttributesGeneratorTest extends \PHPUnit_Framework_TestCase { /** @@ -44,11 +46,21 @@ public function testGenerate() ->willReturn( [ 'Magento\Catalog\Api\Data\ProductInterface' => [ - 'string_attribute' => 'string', - 'complex_object_attribute' => '\Magento\Bundle\Api\Data\OptionInterface[]' + 'string_attribute' => [ + Converter::DATA_TYPE => 'string', + Converter::RESOURCE_PERMISSIONS => [], + + ], + 'complex_object_attribute' => [ + Converter::DATA_TYPE => '\Magento\Bundle\Api\Data\OptionInterface[]', + Converter::RESOURCE_PERMISSIONS => [], + ], ], 'Magento\Catalog\Api\Data\Product' => [ - 'should_not_include' => 'string', + 'should_not_include' => [ + Converter::DATA_TYPE => 'string', + Converter::RESOURCE_PERMISSIONS => [], + ], ], ] ); diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php index 8f80baf39beee..33d4ecf9e7906 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php @@ -6,6 +6,8 @@ // @codingStandardsIgnoreFile namespace Magento\Framework\Api\Test\Unit\Code\Generator; +use Magento\Framework\Api\Config\Converter; + class ExtensionAttributesInterfaceGeneratorTest extends \PHPUnit_Framework_TestCase { public function testGenerate() @@ -19,11 +21,20 @@ public function testGenerate() ->willReturn( [ 'Magento\Catalog\Api\Data\ProductInterface' => [ - 'string_attribute' => 'string', - 'complex_object_attribute' => '\Magento\Bundle\Api\Data\OptionInterface[]' + 'string_attribute' => [ + Converter::DATA_TYPE => 'string', + Converter::RESOURCE_PERMISSIONS => [], + ], + 'complex_object_attribute' => [ + Converter::DATA_TYPE => '\Magento\Bundle\Api\Data\OptionInterface[]', + Converter::RESOURCE_PERMISSIONS => [], + ], ], 'Magento\Catalog\Api\Data\Product' => [ - 'should_not_include' => 'string', + 'should_not_include' => [ + Converter::DATA_TYPE => 'string', + Converter::RESOURCE_PERMISSIONS => [], + ], ], ] ); From 00bece01eb8f396605eeea4c842988c47b77affd Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Thu, 23 Apr 2015 17:01:29 -0500 Subject: [PATCH 07/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Update DataObjectProcessor to extract out the writing of the Extension Attributes - Need to clean this up but let's see if we can filter the results first --- app/code/Magento/Webapi/etc/di.xml | 1 + .../Reflection/DataObjectProcessor.php | 14 ++- .../ExtensionAttributesProcessor.php | 92 +++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml index d9f47dfd67a79..bff952b7ed323 100644 --- a/app/code/Magento/Webapi/etc/di.xml +++ b/app/code/Magento/Webapi/etc/di.xml @@ -25,6 +25,7 @@ Magento\Framework\App\Cache\Type\Webapi + Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 2b9977d7355f5..433fbfd169a1b 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -49,19 +49,27 @@ class DataObjectProcessor */ protected $attributeTypeResolver; + /** + * @var ExtensionAttributesProcessor + */ + private $extensionAttributesProcessor; + /** * @param \Magento\Framework\Cache\FrontendInterface $cache * @param TypeProcessor $typeProcessor * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver + * @param ExtensionAttributesProcessor $extensionAttributesProcessor */ public function __construct( \Magento\Framework\Cache\FrontendInterface $cache, TypeProcessor $typeProcessor, - \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver + \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver, + ExtensionAttributesProcessor $extensionAttributesProcessor ) { $this->cache = $cache; $this->typeProcessor = $typeProcessor; $this->attributeTypeResolver = $typeResolver; + $this->extensionAttributesProcessor = $extensionAttributesProcessor; } /** @@ -110,6 +118,8 @@ public function buildOutputDataArray($dataObject, $dataObjectType) $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) { $value = $this->convertCustomAttributes($value, $dataObjectType); + } elseif ($key === "extension_attributes") { + $value = $this->extensionAttributesProcessor->buildOutputDataArray($value, $returnType); } elseif (is_object($value) && !($value instanceof Phrase)) { $value = $this->buildOutputDataArray($value, $returnType); } elseif (is_array($value)) { @@ -138,7 +148,7 @@ public function buildOutputDataArray($dataObject, $dataObjectType) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - protected function castValueToType($value, $type) + public function castValueToType($value, $type) { if ($value === null) { return null; diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php new file mode 100644 index 0000000000000..3d1bd2ed5d4b4 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -0,0 +1,92 @@ +dataObjectProcessor = $dataObjectProcessor; + } + + public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType) + { + $methods = $this->dataObjectProcessor->getMethodsMap($dataObjectType); + $outputData = []; + + /** @var MethodReflection $method */ + foreach ($methods as $methodName => $methodReflectionData) { + // any method with parameter(s) gets ignored because we do not know the type and value of + // the parameter(s), so we are not able to process + if ($methodReflectionData['parameterCount'] > 0) { + continue; + } + $returnType = $methodReflectionData['type']; + if (substr($methodName, 0, 2) === self::IS_METHOD_PREFIX) { + $value = $dataObject->{$methodName}(); + if ($value === null && !$methodReflectionData['isRequired']) { + continue; + } + $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 2)); + $outputData[$key] = $this->dataObjectProcessor->castValueToType($value, $returnType); + } elseif (substr($methodName, 0, 3) === self::HAS_METHOD_PREFIX) { + $value = $dataObject->{$methodName}(); + if ($value === null && !$methodReflectionData['isRequired']) { + continue; + } + $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); + $outputData[$key] = $this->dataObjectProcessor->castValueToType($value, $returnType); + } elseif (substr($methodName, 0, 3) === self::GETTER_PREFIX) { + $value = $dataObject->{$methodName}(); + if ($value === null && !$methodReflectionData['isRequired']) { + continue; + } + $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); + if (is_object($value) && !($value instanceof Phrase)) { + $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType); + } elseif (is_array($value)) { + $valueResult = []; + $arrayElementType = substr($returnType, 0, -2); + foreach ($value as $singleValue) { + if (is_object($singleValue) && !($singleValue instanceof Phrase)) { + $singleValue = $this->dataObjectProcessor->buildOutputDataArray( + $singleValue, + $arrayElementType + ); + } + $valueResult[] = $this->dataObjectProcessor->castValueToType($singleValue, $arrayElementType); + } + $value = $valueResult; + } + $outputData[$key] = $this->dataObjectProcessor->castValueToType($value, $returnType); + } + } + + return $outputData; + } +} From de82ba69f6fe3f19b9b32d22b1c239a97abaa939 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Thu, 23 Apr 2015 17:04:20 -0500 Subject: [PATCH 08/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Extension attributes do not have any is/has methods --- .../Reflection/ExtensionAttributesProcessor.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 3d1bd2ed5d4b4..58f179a912668 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -47,21 +47,7 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ continue; } $returnType = $methodReflectionData['type']; - if (substr($methodName, 0, 2) === self::IS_METHOD_PREFIX) { - $value = $dataObject->{$methodName}(); - if ($value === null && !$methodReflectionData['isRequired']) { - continue; - } - $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 2)); - $outputData[$key] = $this->dataObjectProcessor->castValueToType($value, $returnType); - } elseif (substr($methodName, 0, 3) === self::HAS_METHOD_PREFIX) { - $value = $dataObject->{$methodName}(); - if ($value === null && !$methodReflectionData['isRequired']) { - continue; - } - $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); - $outputData[$key] = $this->dataObjectProcessor->castValueToType($value, $returnType); - } elseif (substr($methodName, 0, 3) === self::GETTER_PREFIX) { + if (substr($methodName, 0, 3) === self::GETTER_PREFIX) { $value = $dataObject->{$methodName}(); if ($value === null && !$methodReflectionData['isRequired']) { continue; From 93fd3bb721b48d933a3a2b8942fa5f301aeedf62 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Thu, 23 Apr 2015 17:44:09 -0500 Subject: [PATCH 09/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Filter out extension attributes based on permissions inside of service_data_attributes.xml --- .../ExtensionAttributesProcessor.php | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 58f179a912668..bf8b6ba5cccb1 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -6,6 +6,9 @@ namespace Magento\Framework\Reflection; +use Magento\Framework\Api\Config\Reader as ExtensionAttributesConfigReader; +use Magento\Framework\Api\Config\Converter; +use Magento\Framework\AuthorizationInterface; use Magento\Framework\Phrase; use Magento\Framework\Api\SimpleDataObjectConverter; use Magento\Framework\Api\ExtensionAttributesInterface; @@ -25,17 +28,42 @@ class ExtensionAttributesProcessor */ private $dataObjectProcessor; + /** + * @var AuthorizationInterface + */ + private $authorization; + + /** + * @var ExtensionAttributesConfigReader + */ + private $configReader; + /** * @param DataObjectProcessor $dataObjectProcessor + * @param AuthorizationInterface $authorization + * @param ExtensionAttributesConfigReader $configReader */ public function __construct( - DataObjectProcessor $dataObjectProcessor + DataObjectProcessor $dataObjectProcessor, + AuthorizationInterface $authorization, + ExtensionAttributesConfigReader $configReader ) { $this->dataObjectProcessor = $dataObjectProcessor; + $this->authorization = $authorization; + $this->configReader = $configReader; } + /** + * Writes out the extension attributes in an array. + * + * @param ExtensionAttributeInterface $dataObject + * @param string $dataObjectType + * @return array + */ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType) { + // TODO: cleanup all of this that's already duplicated in DataObjectProcessor; re-write the serializers + $methods = $this->dataObjectProcessor->getMethodsMap($dataObjectType); $outputData = []; @@ -53,6 +81,12 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ continue; } $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); + + if (!$this->isAttributePermissionValid($dataObjectType, $key)) { + $outputData[$key] = null; + continue; + } + if (is_object($value) && !($value instanceof Phrase)) { $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType); } elseif (is_array($value)) { @@ -75,4 +109,48 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ return $outputData; } + + /** + * @param string $dataObjectType + * @param string $attributeCode + * @return bool + */ + private function isAttributePermissionValid($dataObjectType, $attributeCode) + { + $typeName = $this->getRegularTypeForExtensionAttributesType($dataObjectType); + $permissions = $this->getPermissionsForTypeAndMethod($typeName, $attributeCode); + foreach ($permissions as $permission) { + if (!$this->authorization->isAllowed($permission)) { + return false; + } + } + + return true; + } + + private function getRegularTypeForExtensionAttributesType($name) + { + return ltrim(str_replace('ExtensionInterface', 'Interface', $name), '\\'); + } + + /** + * @param string $typeName + * @param string $attributeCode + * @return string[] A list of permissions + */ + private function getPermissionsForTypeAndMethod($typeName, $attributeCode) + { + // TODO: Move function to the Config and hope this is cached + $attributes = $this->configReader->read(); + if (isset($attributes[$typeName]) && isset($attributes[$typeName][$attributeCode])) { + $attributeMetadata = $attributes[$typeName][$attributeCode]; + $permissions = []; + foreach ($attributeMetadata[Converter::RESOURCE_PERMISSIONS] as $permission) { + $permissions[] = $permission; + } + return $permissions; + } + + return []; + } } From 21036da557cc2b93777d74e97f06b0a69725ccb0 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Fri, 24 Apr 2015 14:23:06 -0500 Subject: [PATCH 10/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Extract method reflection gathering into MethodsMap class --- .../Unit/Model/DataObjectProcessorTest.php | 6 +- app/code/Magento/Webapi/etc/di.xml | 6 +- .../Framework/Api/DataObjectHelper.php | 14 +- .../Api/Test/Unit/DataObjectHelperTest.php | 17 ++- .../Reflection/DataObjectProcessor.php | 122 ++-------------- .../ExtensionAttributesProcessor.php | 4 + .../Framework/Reflection/MethodsMap.php | 135 ++++++++++++++++++ 7 files changed, 182 insertions(+), 122 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/MethodsMap.php diff --git a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php index 3453c7e1d7951..9c0a4d9ca508c 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php @@ -23,7 +23,11 @@ class DataObjectProcessorTest extends \PHPUnit_Framework_TestCase protected function setup() { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->dataObjectProcessor = $objectManager->getObject('Magento\Framework\Reflection\DataObjectProcessor'); + $this->dataObjectProcessor = $objectManager->getObject('Magento\Framework\Reflection\DataObjectProcessor', + [ + 'methodsMapProcessor' => $objectManager->getObject('Magento\Framework\Reflection\MethodsMap') + ] + ); parent::setUp(); } diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml index bff952b7ed323..c4cdae6b4883d 100644 --- a/app/code/Magento/Webapi/etc/di.xml +++ b/app/code/Magento/Webapi/etc/di.xml @@ -22,9 +22,13 @@ - + Magento\Framework\App\Cache\Type\Webapi + + + + Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy diff --git a/lib/internal/Magento/Framework/Api/DataObjectHelper.php b/lib/internal/Magento/Framework/Api/DataObjectHelper.php index d0a22a194be44..fc3a3b0920c60 100644 --- a/lib/internal/Magento/Framework/Api/DataObjectHelper.php +++ b/lib/internal/Magento/Framework/Api/DataObjectHelper.php @@ -6,6 +6,8 @@ namespace Magento\Framework\Api; +use Magento\Framework\Reflection\MethodsMap; + class DataObjectHelper { /** @@ -28,22 +30,30 @@ class DataObjectHelper */ protected $extensionFactory; + /** + * @var MethodsMap + */ + protected $methodsMapProcessor; + /** * @param ObjectFactory $objectFactory * @param \Magento\Framework\Reflection\DataObjectProcessor $objectProcessor * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory + * @param MethodsMap $methodsMapProcessor */ public function __construct( ObjectFactory $objectFactory, \Magento\Framework\Reflection\DataObjectProcessor $objectProcessor, \Magento\Framework\Reflection\TypeProcessor $typeProcessor, - \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory + \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory, + MethodsMap $methodsMapProcessor ) { $this->objectFactory = $objectFactory; $this->objectProcessor = $objectProcessor; $this->typeProcessor = $typeProcessor; $this->extensionFactory = $extensionFactory; + $this->methodsMapProcessor = $methodsMapProcessor; } /** @@ -128,7 +138,7 @@ protected function setComplexValue( if ($interfaceName == null) { $interfaceName = get_class($dataObject); } - $returnType = $this->objectProcessor->getMethodReturnType($interfaceName, $getterMethodName); + $returnType = $this->methodsMapProcessor->getMethodReturnType($interfaceName, $getterMethodName); if ($this->typeProcessor->isTypeSimple($returnType)) { $dataObject->$methodName($value); return $this; diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php index ff229abd7d22e..65c7cb906d1f2 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php @@ -43,6 +43,11 @@ class DataObjectHelperTest extends \PHPUnit_Framework_TestCase */ protected $attributeValueFactoryMock; + /** + * @var \Magento\Framework\Reflection\MethodsMap|\PHPUnit_Framework_MockObject_MockObject + */ + protected $methodsMapProcessor; + public function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -53,6 +58,9 @@ public function setUp() $this->objectProcessorMock = $this->getMockBuilder('\Magento\Framework\Reflection\DataObjectProcessor') ->disableOriginalConstructor() ->getMock(); + $this->methodsMapProcessor = $this->getMockBuilder('\Magento\Framework\Reflection\MethodsMap') + ->disableOriginalConstructor() + ->getMock(); $this->attributeValueFactoryMock = $this->getMockBuilder('\Magento\Framework\Api\AttributeValueFactory') ->disableOriginalConstructor() ->getMock(); @@ -63,6 +71,7 @@ public function setUp() 'objectFactory' => $this->objectFactoryMock, 'typeProcessor' => $this->typeProcessor, 'objectProcessor' => $this->objectProcessorMock, + 'methodsMapProcessor' => $this->methodsMapProcessor, ] ); } @@ -103,11 +112,11 @@ public function testPopulateWithArrayWithSimpleAttributes() ], ]; - $this->objectProcessorMock->expects($this->at(0)) + $this->methodsMapProcessor->expects($this->at(0)) ->method('getMethodReturnType') ->with('\Magento\Customer\Api\Data\AddressInterface', 'getStreet') ->willReturn('string[]'); - $this->objectProcessorMock->expects($this->at(1)) + $this->methodsMapProcessor->expects($this->at(1)) ->method('getMethodReturnType') ->with('\Magento\Customer\Api\Data\AddressInterface', 'getRegion') ->willReturn('\Magento\Customer\Api\Data\RegionInterface'); @@ -317,11 +326,11 @@ public function testMergeDataObjects($data1, $data2) ->method('buildOutputDataArray') ->with($secondAddressDataObject, get_class($firstAddressDataObject)) ->willReturn($data2); - $this->objectProcessorMock->expects($this->at(1)) + $this->methodsMapProcessor->expects($this->at(0)) ->method('getMethodReturnType') ->with('Magento\Customer\Model\Data\Address', 'getStreet') ->willReturn('string[]'); - $this->objectProcessorMock->expects($this->at(2)) + $this->methodsMapProcessor->expects($this->at(1)) ->method('getMethodReturnType') ->with('Magento\Customer\Model\Data\Address', 'getRegion') ->willReturn('\Magento\Customer\Api\Data\RegionInterface'); diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 433fbfd169a1b..015399ee8f1a3 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -21,33 +21,16 @@ class DataObjectProcessor const IS_METHOD_PREFIX = 'is'; const HAS_METHOD_PREFIX = 'has'; const GETTER_PREFIX = 'get'; - const SERVICE_INTERFACE_METHODS_CACHE_PREFIX = 'serviceInterfaceMethodsMap'; - const BASE_MODEL_CLASS = 'Magento\Framework\Model\AbstractExtensibleModel'; /** - * @var \Magento\Framework\Cache\FrontendInterface - */ - protected $cache; - - /** - * @var TypeProcessor - */ - protected $typeProcessor; - - /** - * @var array + * @var \Magento\Framework\Api\AttributeTypeResolverInterface */ - protected $dataInterfaceMethodsMap = []; + protected $attributeTypeResolver; /** - * @var array + * @var MethodsMap */ - protected $serviceInterfaceMethodsMap = []; - - /** - * @var \Magento\Framework\Api\AttributeTypeResolverInterface - */ - protected $attributeTypeResolver; + private $methodsMapProcessor; /** * @var ExtensionAttributesProcessor @@ -55,20 +38,17 @@ class DataObjectProcessor private $extensionAttributesProcessor; /** - * @param \Magento\Framework\Cache\FrontendInterface $cache - * @param TypeProcessor $typeProcessor * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver + * @param MethodsMap $methodsMapProcessor * @param ExtensionAttributesProcessor $extensionAttributesProcessor */ public function __construct( - \Magento\Framework\Cache\FrontendInterface $cache, - TypeProcessor $typeProcessor, \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver, + MethodsMap $methodsMapProcessor, ExtensionAttributesProcessor $extensionAttributesProcessor ) { - $this->cache = $cache; - $this->typeProcessor = $typeProcessor; $this->attributeTypeResolver = $typeResolver; + $this->methodsMapProcessor = $methodsMapProcessor; $this->extensionAttributesProcessor = $extensionAttributesProcessor; } @@ -82,7 +62,7 @@ public function __construct( */ public function buildOutputDataArray($dataObject, $dataObjectType) { - $methods = $this->getMethodsMap($dataObjectType); + $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType); $outputData = []; /** @var MethodReflection $method */ @@ -177,18 +157,6 @@ public function castValueToType($value, $type) return $value; } - /** - * Get return type by interface name and method - * - * @param string $interfaceName - * @param string $methodName - * @return string - */ - public function getMethodReturnType($interfaceName, $methodName) - { - return $this->getMethodsMap($interfaceName)[$methodName]['type']; - } - /** * Convert array of custom_attributes to use flat array structure * @@ -243,78 +211,4 @@ protected function convertCustomAttribute($customAttribute, $dataObjectType) $data[AttributeValue::VALUE] = $value; return $data; } - - /** - * Return service interface or Data interface methods loaded from cache - * - * @param string $interfaceName - * @return array - *
-     * Service methods' reflection data stored in cache as 'methodName' => 'returnType'
-     * ex.
-     * [
-     *  'create' => '\Magento\Customer\Api\Data\Customer',
-     *  'validatePassword' => 'boolean'
-     * ]
-     * 
- */ - public function getMethodsMap($interfaceName) - { - $key = self::SERVICE_INTERFACE_METHODS_CACHE_PREFIX . "-" . md5($interfaceName); - if (!isset($this->serviceInterfaceMethodsMap[$key])) { - $methodMap = $this->cache->load($key); - if ($methodMap) { - $this->serviceInterfaceMethodsMap[$key] = unserialize($methodMap); - } else { - $methodMap = $this->getMethodMapViaReflection($interfaceName); - $this->serviceInterfaceMethodsMap[$key] = $methodMap; - $this->cache->save(serialize($this->serviceInterfaceMethodsMap[$key]), $key); - } - } - return $this->serviceInterfaceMethodsMap[$key]; - } - - /** - * Use reflection to load the method information - * - * @param string $interfaceName - * @return array - */ - protected function getMethodMapViaReflection($interfaceName) - { - $methodMap = []; - $class = new ClassReflection($interfaceName); - $baseClassMethods = false; - foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { - // Include all the methods of classes inheriting from AbstractExtensibleObject. - // Ignore all the methods of AbstractExtensibleModel's parent classes - if ($method->class === self::BASE_MODEL_CLASS) { - $baseClassMethods = true; - } elseif ($baseClassMethods) { - // ReflectionClass::getMethods() sorts the methods by class (lowest in inheritance tree first) - // then by the order they are defined in the class definition - break; - } - - if ($this->isSuitableMethod($method)) { - $methodMap[$method->getName()] = $this->typeProcessor->getGetterReturnType($method); - } - } - return $methodMap; - } - - /** - * Determines if the method is suitable to be used by the processor. - * - * @param \ReflectionMethod $method - * @return bool - */ - protected function isSuitableMethod($method) - { - $isSuitableMethodType = !($method->isConstructor() || $method->isFinal() - || $method->isStatic() || $method->isDestructor()); - - $isExcludedMagicMethod = strpos($method->getName(), '__') === 0; - return $isSuitableMethodType && !$isExcludedMagicMethod; - } } diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index bf8b6ba5cccb1..3b4fed97a0daa 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -128,6 +128,10 @@ private function isAttributePermissionValid($dataObjectType, $attributeCode) return true; } + /** + * @param string $name + * @return string + */ private function getRegularTypeForExtensionAttributesType($name) { return ltrim(str_replace('ExtensionInterface', 'Interface', $name), '\\'); diff --git a/lib/internal/Magento/Framework/Reflection/MethodsMap.php b/lib/internal/Magento/Framework/Reflection/MethodsMap.php new file mode 100644 index 0000000000000..e3f56d50fc23e --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/MethodsMap.php @@ -0,0 +1,135 @@ +cache = $cache; + $this->typeProcessor = $typeProcessor; + $this->attributeTypeResolver = $typeResolver; + } + + /** + * Get return type by interface name and method + * + * @param string $interfaceName + * @param string $methodName + * @return string + */ + public function getMethodReturnType($interfaceName, $methodName) + { + return $this->getMethodsMap($interfaceName)[$methodName]['type']; + } + + /** + * Return service interface or Data interface methods loaded from cache + * + * @param string $interfaceName + * @return array + *
+     * Service methods' reflection data stored in cache as 'methodName' => 'returnType'
+     * ex.
+     * [
+     *  'create' => '\Magento\Customer\Api\Data\Customer',
+     *  'validatePassword' => 'boolean'
+     * ]
+     * 
+ */ + public function getMethodsMap($interfaceName) + { + $key = self::SERVICE_INTERFACE_METHODS_CACHE_PREFIX . "-" . md5($interfaceName); + if (!isset($this->serviceInterfaceMethodsMap[$key])) { + $methodMap = $this->cache->load($key); + if ($methodMap) { + $this->serviceInterfaceMethodsMap[$key] = unserialize($methodMap); + } else { + $methodMap = $this->getMethodMapViaReflection($interfaceName); + $this->serviceInterfaceMethodsMap[$key] = $methodMap; + $this->cache->save(serialize($this->serviceInterfaceMethodsMap[$key]), $key); + } + } + return $this->serviceInterfaceMethodsMap[$key]; + } + + /** + * Use reflection to load the method information + * + * @param string $interfaceName + * @return array + */ + private function getMethodMapViaReflection($interfaceName) + { + $methodMap = []; + $class = new ClassReflection($interfaceName); + $baseClassMethods = false; + foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + // Include all the methods of classes inheriting from AbstractExtensibleObject. + // Ignore all the methods of AbstractExtensibleModel's parent classes + if ($method->class === self::BASE_MODEL_CLASS) { + $baseClassMethods = true; + } elseif ($baseClassMethods) { + // ReflectionClass::getMethods() sorts the methods by class (lowest in inheritance tree first) + // then by the order they are defined in the class definition + break; + } + + if ($this->isSuitableMethod($method)) { + $methodMap[$method->getName()] = $this->typeProcessor->getGetterReturnType($method); + } + } + return $methodMap; + } + + /** + * Determines if the method is suitable to be used by the processor. + * + * @param \ReflectionMethod $method + * @return bool + */ + private function isSuitableMethod($method) + { + $isSuitableMethodType = !($method->isConstructor() || $method->isFinal() + || $method->isStatic() || $method->isDestructor()); + + $isExcludedMagicMethod = strpos($method->getName(), '__') === 0; + return $isSuitableMethodType && !$isExcludedMagicMethod; + } +} From 171754a3ebcf23444adc41d0eeade8d02fbfced2 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Fri, 24 Apr 2015 14:30:08 -0500 Subject: [PATCH 11/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Extract type casting method to own class --- .../Reflection/DataObjectProcessor.php | 56 +++++-------------- .../Framework/Reflection/TypeCaster.php | 51 +++++++++++++++++ 2 files changed, 64 insertions(+), 43 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/TypeCaster.php diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 015399ee8f1a3..67556517fc5f5 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -37,19 +37,27 @@ class DataObjectProcessor */ private $extensionAttributesProcessor; + /** + * @var TypeCaster + */ + private $typeCaster; + /** * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver * @param MethodsMap $methodsMapProcessor * @param ExtensionAttributesProcessor $extensionAttributesProcessor + * @param TypeCaster $typeCaster */ public function __construct( \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver, MethodsMap $methodsMapProcessor, - ExtensionAttributesProcessor $extensionAttributesProcessor + ExtensionAttributesProcessor $extensionAttributesProcessor, + TypeCaster $typeCaster ) { $this->attributeTypeResolver = $typeResolver; $this->methodsMapProcessor = $methodsMapProcessor; $this->extensionAttributesProcessor = $extensionAttributesProcessor; + $this->typeCaster = $typeCaster; } /** @@ -79,14 +87,14 @@ public function buildOutputDataArray($dataObject, $dataObjectType) continue; } $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 2)); - $outputData[$key] = $this->castValueToType($value, $returnType); + $outputData[$key] = $this->typeCaster->castValueToType($value, $returnType); } elseif (substr($methodName, 0, 3) === self::HAS_METHOD_PREFIX) { $value = $dataObject->{$methodName}(); if ($value === null && !$methodReflectionData['isRequired']) { continue; } $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); - $outputData[$key] = $this->castValueToType($value, $returnType); + $outputData[$key] = $this->typeCaster->castValueToType($value, $returnType); } elseif (substr($methodName, 0, 3) === self::GETTER_PREFIX) { $value = $dataObject->{$methodName}(); if ($methodName === 'getCustomAttributes' && $value === []) { @@ -109,54 +117,16 @@ public function buildOutputDataArray($dataObject, $dataObjectType) if (is_object($singleValue) && !($singleValue instanceof Phrase)) { $singleValue = $this->buildOutputDataArray($singleValue, $arrayElementType); } - $valueResult[] = $this->castValueToType($singleValue, $arrayElementType); + $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType); } $value = $valueResult; } - $outputData[$key] = $this->castValueToType($value, $returnType); + $outputData[$key] = $this->typeCaster->castValueToType($value, $returnType); } } return $outputData; } - /** - * Cast the output type to the documented type. This helps for output purposes. - * - * @param mixed $value - * @param string $type - * @return mixed - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - public function castValueToType($value, $type) - { - if ($value === null) { - return null; - } - - if ($type === "int" || $type === "integer") { - return (int)$value; - } - - if ($type === "string") { - return (string)$value; - } - - if ($type === "bool" || $type === "boolean" || $type === "true" || $type == "false") { - return (bool)$value; - } - - if ($type === "float") { - return (float)$value; - } - - if ($type === "double") { - return (double)$value; - } - - return $value; - } - /** * Convert array of custom_attributes to use flat array structure * diff --git a/lib/internal/Magento/Framework/Reflection/TypeCaster.php b/lib/internal/Magento/Framework/Reflection/TypeCaster.php new file mode 100644 index 0000000000000..1b9aa0facf1f1 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/TypeCaster.php @@ -0,0 +1,51 @@ + Date: Fri, 24 Apr 2015 16:04:50 -0500 Subject: [PATCH 12/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix tests for type casting --- .../Webapi/Test/Unit/Model/DataObjectProcessorTest.php | 3 ++- .../Magento/Framework/Reflection/DataObjectProcessor.php | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php index 9c0a4d9ca508c..6bde04cc0a83d 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php @@ -25,7 +25,8 @@ protected function setup() $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->dataObjectProcessor = $objectManager->getObject('Magento\Framework\Reflection\DataObjectProcessor', [ - 'methodsMapProcessor' => $objectManager->getObject('Magento\Framework\Reflection\MethodsMap') + 'methodsMapProcessor' => $objectManager->getObject('Magento\Framework\Reflection\MethodsMap'), + 'typeCaster' => $objectManager->getObject('Magento\Framework\Reflection\TypeCaster'), ] ); parent::setUp(); diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 67556517fc5f5..63486df5bc0a2 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -120,8 +120,11 @@ public function buildOutputDataArray($dataObject, $dataObjectType) $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType); } $value = $valueResult; + } else { + $value = $this->typeCaster->castValueToType($value, $returnType); } - $outputData[$key] = $this->typeCaster->castValueToType($value, $returnType); + + $outputData[$key] = $value; } } return $outputData; From c8a7f54c3a40a7e83b3662e86d7ec574fe0fb1b2 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Fri, 24 Apr 2015 17:09:12 -0500 Subject: [PATCH 13/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Extract field naming logic --- .../Unit/Model/DataObjectProcessorTest.php | 9 ++- .../Unit/Model/Files/TestDataInterface.php | 12 ++++ .../Reflection/DataObjectProcessor.php | 66 +++++++++---------- .../Framework/Reflection/FieldNamer.php | 41 ++++++++++++ .../Framework/Reflection/MethodsMap.php | 43 +++++++++++- 5 files changed, 134 insertions(+), 37 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/FieldNamer.php diff --git a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php index 6bde04cc0a83d..c42d295962737 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php @@ -23,10 +23,17 @@ class DataObjectProcessorTest extends \PHPUnit_Framework_TestCase protected function setup() { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $methodsMapProcessor = $objectManager->getObject('Magento\Framework\Reflection\MethodsMap', + [ + 'fieldNamer' => $objectManager->getObject('Magento\Framework\Reflection\FieldNamer'), + 'typeProcessor' => $objectManager->getObject('Magento\Framework\Reflection\TypeProcessor'), + ] + ); $this->dataObjectProcessor = $objectManager->getObject('Magento\Framework\Reflection\DataObjectProcessor', [ - 'methodsMapProcessor' => $objectManager->getObject('Magento\Framework\Reflection\MethodsMap'), + 'methodsMapProcessor' => $methodsMapProcessor, 'typeCaster' => $objectManager->getObject('Magento\Framework\Reflection\TypeCaster'), + 'fieldNamer' => $objectManager->getObject('Magento\Framework\Reflection\FieldNamer'), ] ); parent::setUp(); diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php b/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php index 1b4f971c2c3a4..2010509ff4161 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php @@ -8,11 +8,23 @@ interface TestDataInterface { + /** + * @return string + */ public function getId(); + /** + * @return string + */ public function getAddress(); + /** + * @return string + */ public function isDefaultShipping(); + /** + * @return string + */ public function isRequiredBilling(); } diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 63486df5bc0a2..5eb51f8238854 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -42,22 +42,30 @@ class DataObjectProcessor */ private $typeCaster; + /** + * @var FieldNamer + */ + private $fieldNamer; + /** * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver * @param MethodsMap $methodsMapProcessor * @param ExtensionAttributesProcessor $extensionAttributesProcessor * @param TypeCaster $typeCaster + * @param FieldNamer $fieldNamer */ public function __construct( \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver, MethodsMap $methodsMapProcessor, ExtensionAttributesProcessor $extensionAttributesProcessor, - TypeCaster $typeCaster + TypeCaster $typeCaster, + FieldNamer $fieldNamer ) { $this->attributeTypeResolver = $typeResolver; $this->methodsMapProcessor = $methodsMapProcessor; $this->extensionAttributesProcessor = $extensionAttributesProcessor; $this->typeCaster = $typeCaster; + $this->fieldNamer = $fieldNamer; } /** @@ -75,40 +83,28 @@ public function buildOutputDataArray($dataObject, $dataObjectType) /** @var MethodReflection $method */ foreach ($methods as $methodName => $methodReflectionData) { - // any method with parameter(s) gets ignored because we do not know the type and value of - // the parameter(s), so we are not able to process - if ($methodReflectionData['parameterCount'] > 0) { + if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) { continue; } - $returnType = $methodReflectionData['type']; - if (substr($methodName, 0, 2) === self::IS_METHOD_PREFIX) { - $value = $dataObject->{$methodName}(); - if ($value === null && !$methodReflectionData['isRequired']) { - continue; - } - $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 2)); - $outputData[$key] = $this->typeCaster->castValueToType($value, $returnType); - } elseif (substr($methodName, 0, 3) === self::HAS_METHOD_PREFIX) { - $value = $dataObject->{$methodName}(); - if ($value === null && !$methodReflectionData['isRequired']) { - continue; - } - $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); - $outputData[$key] = $this->typeCaster->castValueToType($value, $returnType); - } elseif (substr($methodName, 0, 3) === self::GETTER_PREFIX) { - $value = $dataObject->{$methodName}(); - if ($methodName === 'getCustomAttributes' && $value === []) { - continue; - } - if ($value === null && !$methodReflectionData['isRequired']) { - continue; - } - $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); - if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) { - $value = $this->convertCustomAttributes($value, $dataObjectType); - } elseif ($key === "extension_attributes") { - $value = $this->extensionAttributesProcessor->buildOutputDataArray($value, $returnType); - } elseif (is_object($value) && !($value instanceof Phrase)) { + + $value = $dataObject->{$methodName}(); + $isMethodRequired = $this->methodsMapProcessor->isMethodRequired($dataObjectType, $methodName); + if ($value === null && !$isMethodRequired) { + continue; + } + + $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName); + $key = $this->fieldNamer->getFieldNameForMethodName($methodName); + if ($key === 'custom_attributes' && $value === []) { + continue; + } + + if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) { + $value = $this->convertCustomAttributes($value, $dataObjectType); + } elseif ($key === "extension_attributes") { + $value = $this->extensionAttributesProcessor->buildOutputDataArray($value, $returnType); + } else { + if (is_object($value) && !($value instanceof Phrase)) { $value = $this->buildOutputDataArray($value, $returnType); } elseif (is_array($value)) { $valueResult = []; @@ -123,9 +119,9 @@ public function buildOutputDataArray($dataObject, $dataObjectType) } else { $value = $this->typeCaster->castValueToType($value, $returnType); } - - $outputData[$key] = $value; } + + $outputData[$key] = $value; } return $outputData; } diff --git a/lib/internal/Magento/Framework/Reflection/FieldNamer.php b/lib/internal/Magento/Framework/Reflection/FieldNamer.php new file mode 100644 index 0000000000000..cae90f9c8c806 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/FieldNamer.php @@ -0,0 +1,41 @@ +cache = $cache; $this->typeProcessor = $typeProcessor; $this->attributeTypeResolver = $typeResolver; + $this->fieldNamer = $fieldNamer; } /** @@ -132,4 +140,37 @@ private function isSuitableMethod($method) $isExcludedMagicMethod = strpos($method->getName(), '__') === 0; return $isSuitableMethodType && !$isExcludedMagicMethod; } + + /** + * @param string $type + * @param string $methodName + * @return bool + */ + public function isMethodValidForDataField($type, $methodName) + { + $methods = $this->getMethodsMap($type); + if (isset($methods[$methodName])) { + $methodMetadata = $methods[$methodName]; + // any method with parameter(s) gets ignored because we do not know the type and value of + // the parameter(s), so we are not able to process + if ($methodMetadata['parameterCount'] > 0) { + return false; + } + + return $this->fieldNamer->getFieldNameForMethodName($methodName) !== null; + } + + return false; + } + + /** + * @param string $type + * @param string $methodName + * @return bool + */ + public function isMethodRequired($type, $methodName) + { + $methods = $this->getMethodsMap($type); + return $methods[$methodName]['isRequired']; + } } From 8c2738332c716904787aa045eb112d50796c2b6a Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Fri, 24 Apr 2015 17:29:18 -0500 Subject: [PATCH 14/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Refactor ExtensionAttributesProcessor to reduce logic --- .../Reflection/DataObjectProcessor.php | 2 +- .../ExtensionAttributesProcessor.php | 64 ++++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 5eb51f8238854..8a4bb8232f928 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -95,7 +95,7 @@ public function buildOutputDataArray($dataObject, $dataObjectType) $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName); $key = $this->fieldNamer->getFieldNameForMethodName($methodName); - if ($key === 'custom_attributes' && $value === []) { + if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES && $value === []) { continue; } diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 3b4fed97a0daa..1b1ee0600bf64 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -69,42 +69,48 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ /** @var MethodReflection $method */ foreach ($methods as $methodName => $methodReflectionData) { - // any method with parameter(s) gets ignored because we do not know the type and value of - // the parameter(s), so we are not able to process - if ($methodReflectionData['parameterCount'] > 0) { + if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) { continue; } - $returnType = $methodReflectionData['type']; - if (substr($methodName, 0, 3) === self::GETTER_PREFIX) { - $value = $dataObject->{$methodName}(); - if ($value === null && !$methodReflectionData['isRequired']) { - continue; - } - $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3)); - if (!$this->isAttributePermissionValid($dataObjectType, $key)) { - $outputData[$key] = null; - continue; - } + $key = $this->fieldNamer->getFieldNameForMethodName($methodName); + if (!$this->isAttributePermissionValid($dataObjectType, $key)) { + $outputData[$key] = null; + continue; + } - if (is_object($value) && !($value instanceof Phrase)) { - $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType); - } elseif (is_array($value)) { - $valueResult = []; - $arrayElementType = substr($returnType, 0, -2); - foreach ($value as $singleValue) { - if (is_object($singleValue) && !($singleValue instanceof Phrase)) { - $singleValue = $this->dataObjectProcessor->buildOutputDataArray( - $singleValue, - $arrayElementType - ); - } - $valueResult[] = $this->dataObjectProcessor->castValueToType($singleValue, $arrayElementType); + $value = $dataObject->{$methodName}(); + if ($value === null) { + // all extension attributes are optional + continue; + } + + // should write field? + // isWriterValid + // what value should be written + + $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName); + + if (is_object($value) && !($value instanceof Phrase)) { + $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType); + } elseif (is_array($value)) { + $valueResult = []; + $arrayElementType = substr($returnType, 0, -2); + foreach ($value as $singleValue) { + if (is_object($singleValue) && !($singleValue instanceof Phrase)) { + $singleValue = $this->dataObjectProcessor->buildOutputDataArray( + $singleValue, + $arrayElementType + ); } - $value = $valueResult; + $valueResult[] = $this->dataObjectProcessor->castValueToType($singleValue, $arrayElementType); } - $outputData[$key] = $this->dataObjectProcessor->castValueToType($value, $returnType); + $value = $valueResult; + } else { + $value = $this->typeCaster->castValueToType($value, $returnType); } + + $outputData[$key] = $value; } return $outputData; From f88531402623cb78267b6888456d3e20bb95297f Mon Sep 17 00:00:00 2001 From: Cari Spruiell Date: Mon, 27 Apr 2015 10:43:43 -0500 Subject: [PATCH 15/30] MAGETWO-35081: Backend navigation Menu contains groups with single sections which have titles - removed level 1 headings when there is only one level 1 group - updated expected results for corresponding test --- app/code/Magento/Backend/Block/Menu.php | 39 ++++++++++++------- .../Backend/Block/_files/menu/expected.txt | 2 +- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Backend/Block/Menu.php b/app/code/Magento/Backend/Block/Menu.php index 6eaed8e5b1634..bf671373b4402 100644 --- a/app/code/Magento/Backend/Block/Menu.php +++ b/app/code/Magento/Backend/Block/Menu.php @@ -454,21 +454,30 @@ public function renderNavigation($menu, $level = 0, $limit = 0, $colBrakes = []) } $id = $this->getJsId($menuItem->getId()); - $output .= '
  • getUiId( - $menuItem->getId() - ) . ' class="item-' . $itemClass . ' ' . $this->_renderItemCssClass( - $menuItem, - $level - ) . ($level == 0 ? '" id="' . $id . '" aria-haspopup="true' : '') - . '" role="menu-item">' . $this->_renderAnchor( - $menuItem, - $level - ) . $this->_addSubMenu( - $menuItem, - $level, - $limit, - $id - ) . '
  • '; + if (count($menu) > 1 || $level != 1) { + $output .= '
  • getUiId( + $menuItem->getId() + ) . ' class="item-' . $itemClass . ' ' . $this->_renderItemCssClass( + $menuItem, + $level + ) . ($level == 0 ? '" id="' . $id . '" aria-haspopup="true' : '') + . '" role="menu-item">' . $this->_renderAnchor( + $menuItem, + $level + ) . $this->_addSubMenu( + $menuItem, + $level, + $limit, + $id + ) . '
  • '; + } else { + $output .= $this->_addSubMenu( + $menuItem, + $level, + $limit, + $id); + } + $itemPosition++; } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt index fc890c803aae3..dc07065f7be1e 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From e53f09dda4f2867d6b293ed8f7cc757e1fd19ae8 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 14:54:08 -0500 Subject: [PATCH 16/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix calls for getMethodReturnType --- .../Webapi/Controller/Soap/Request/Handler.php | 11 +++++++++-- .../Reflection/ExtensionAttributesProcessor.php | 17 +++++++++++------ .../Framework/Webapi/ServiceOutputProcessor.php | 16 +++++++++++++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php b/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php index 25d196ce6a804..ec73bd7236c10 100644 --- a/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php +++ b/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php @@ -15,6 +15,7 @@ use Magento\Webapi\Controller\Soap\Request as SoapRequest; use Magento\Framework\Webapi\Exception as WebapiException; use Magento\Webapi\Model\Soap\Config as SoapConfig; +use Magento\Framework\Reflection\MethodsMap; /** * Handler of requests to SOAP server. @@ -48,6 +49,9 @@ class Handler /** @var DataObjectProcessor */ protected $_dataObjectProcessor; + /** @var MethodsMap */ + protected $methodsMapProcessor; + /** * Initialize dependencies. * @@ -58,6 +62,7 @@ class Handler * @param SimpleDataObjectConverter $dataObjectConverter * @param ServiceInputProcessor $serviceInputProcessor * @param DataObjectProcessor $dataObjectProcessor + * @param MethodsMap $methodsMapProcessor */ public function __construct( SoapRequest $request, @@ -66,7 +71,8 @@ public function __construct( AuthorizationInterface $authorization, SimpleDataObjectConverter $dataObjectConverter, ServiceInputProcessor $serviceInputProcessor, - DataObjectProcessor $dataObjectProcessor + DataObjectProcessor $dataObjectProcessor, + MethodsMap $methodsMapProcessor ) { $this->_request = $request; $this->_objectManager = $objectManager; @@ -75,6 +81,7 @@ public function __construct( $this->_dataObjectConverter = $dataObjectConverter; $this->serviceInputProcessor = $serviceInputProcessor; $this->_dataObjectProcessor = $dataObjectProcessor; + $this->methodsMapProcessor = $methodsMapProcessor; } /** @@ -149,7 +156,7 @@ protected function _prepareRequestData($serviceClass, $serviceMethod, $arguments protected function _prepareResponseData($data, $serviceClassName, $serviceMethodName) { /** @var string $dataType */ - $dataType = $this->_dataObjectProcessor->getMethodReturnType($serviceClassName, $serviceMethodName); + $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName); $result = null; if (is_object($data)) { $result = $this->_dataObjectConverter diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 1b1ee0600bf64..35cdc3812b04a 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -38,19 +38,27 @@ class ExtensionAttributesProcessor */ private $configReader; + /** + * @var bool + */ + private $isPermissionChecked; + /** * @param DataObjectProcessor $dataObjectProcessor * @param AuthorizationInterface $authorization * @param ExtensionAttributesConfigReader $configReader + * @param bool $isPermissionChecked */ public function __construct( DataObjectProcessor $dataObjectProcessor, AuthorizationInterface $authorization, - ExtensionAttributesConfigReader $configReader + ExtensionAttributesConfigReader $configReader, + $isPermissionChecked = false ) { $this->dataObjectProcessor = $dataObjectProcessor; $this->authorization = $authorization; $this->configReader = $configReader; + $this->isPermissionChecked = $isPermissionChecked; } /** @@ -62,8 +70,6 @@ public function __construct( */ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType) { - // TODO: cleanup all of this that's already duplicated in DataObjectProcessor; re-write the serializers - $methods = $this->dataObjectProcessor->getMethodsMap($dataObjectType); $outputData = []; @@ -74,14 +80,13 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ } $key = $this->fieldNamer->getFieldNameForMethodName($methodName); - if (!$this->isAttributePermissionValid($dataObjectType, $key)) { - $outputData[$key] = null; + if ($this->isPermissionChecked && !$this->isAttributePermissionValid($dataObjectType, $key)) { continue; } $value = $dataObject->{$methodName}(); if ($value === null) { - // all extension attributes are optional + // all extension attributes are optional so don't need to check if isRequired continue; } diff --git a/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php b/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php index 79cd652f4b22e..1bf5137218bf4 100644 --- a/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php +++ b/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php @@ -8,6 +8,7 @@ use Magento\Framework\Api\AbstractExtensibleObject; use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Framework\Reflection\DataObjectProcessor; +use Magento\Framework\Reflection\MethodsMap; /** * Data object converter for REST @@ -19,12 +20,21 @@ class ServiceOutputProcessor */ protected $dataObjectProcessor; + /** + * @var MethodsMap + */ + protected $methodsMapProcessor; + /** * @param DataObjectProcessor $dataObjectProcessor + * @param MethodsMap $methodsMapProcessor */ - public function __construct(DataObjectProcessor $dataObjectProcessor) - { + public function __construct( + DataObjectProcessor $dataObjectProcessor, + MethodsMap $methodsMapProcessor + ) { $this->dataObjectProcessor = $dataObjectProcessor; + $this->methodsMapProcessor = $methodsMapProcessor; } /** @@ -44,7 +54,7 @@ public function __construct(DataObjectProcessor $dataObjectProcessor) public function process($data, $serviceClassName, $serviceMethodName) { /** @var string $dataType */ - $dataType = $this->dataObjectProcessor->getMethodReturnType($serviceClassName, $serviceMethodName); + $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName); if (is_array($data)) { $result = []; $arrayElementType = substr($dataType, 0, -2); From bd3be013896a850b63858b6653147629d2a4e5c5 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 15:20:41 -0500 Subject: [PATCH 17/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Add CustomAttributesProcessor --- .../Reflection/CustomAttributesProcessor.php | 97 +++++++++++++++++++ .../Reflection/DataObjectProcessor.php | 69 +------------ .../ExtensionAttributesProcessor.php | 6 +- 3 files changed, 99 insertions(+), 73 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php diff --git a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php new file mode 100644 index 0000000000000..ac9ff080a3024 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php @@ -0,0 +1,97 @@ +dataObjectProcessor = $dataObjectProcessor; + $this->attributeTypeResolver = $typeResolver; + } + + /** + * Writes out the custom attributes for a given object into an array. + * + * @param CustomAttributesDataInterface $objectWithCustomAttributes + * @param string $dataObjectType + * @return array + */ + public function buildOutputDataArray(CustomAttributesDataInterface $objectWithCustomAttributes, $dataObjectType) + { + $customAttributes = $objectWithCustomAttributes->getCustomAttributes(); + $result = []; + foreach ($customAttributes as $customAttribute) { + $result[] = $this->convertCustomAttribute($customAttribute, $dataObjectType); + } + return $result; + } + + /** + * Convert custom_attribute object to use flat array structure + * + * @param \Magento\Framework\Api\AttributeInterface $customAttribute + * @param string $dataObjectType + * @return array + */ + private function convertCustomAttribute($customAttribute, $dataObjectType) + { + $data = []; + $data[AttributeValue::ATTRIBUTE_CODE] = $customAttribute->getAttributeCode(); + $value = $customAttribute->getValue(); + if (is_object($value)) { + $type = $this->attributeTypeResolver->resolveObjectType( + $customAttribute->getAttributeCode(), + $value, + $dataObjectType + ); + $value = $this->dataObjectProcessor->buildOutputDataArray($value, $type); + } elseif (is_array($value)) { + $valueResult = []; + foreach ($value as $singleValue) { + if (is_object($singleValue)) { + $type = $this->attributeTypeResolver->resolveObjectType( + $customAttribute->getAttributeCode(), + $singleValue, + $dataObjectType + ); + $singleValue = $this->dataObjectProcessor->buildOutputDataArray($singleValue, $type); + } + // Cannot cast to a type because the type is unknown + $valueResult[] = $singleValue; + } + $value = $valueResult; + } + $data[AttributeValue::VALUE] = $value; + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 8a4bb8232f928..8df9ee717f946 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -18,15 +18,6 @@ */ class DataObjectProcessor { - const IS_METHOD_PREFIX = 'is'; - const HAS_METHOD_PREFIX = 'has'; - const GETTER_PREFIX = 'get'; - - /** - * @var \Magento\Framework\Api\AttributeTypeResolverInterface - */ - protected $attributeTypeResolver; - /** * @var MethodsMap */ @@ -48,20 +39,17 @@ class DataObjectProcessor private $fieldNamer; /** - * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver * @param MethodsMap $methodsMapProcessor * @param ExtensionAttributesProcessor $extensionAttributesProcessor * @param TypeCaster $typeCaster * @param FieldNamer $fieldNamer */ public function __construct( - \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver, MethodsMap $methodsMapProcessor, ExtensionAttributesProcessor $extensionAttributesProcessor, TypeCaster $typeCaster, FieldNamer $fieldNamer ) { - $this->attributeTypeResolver = $typeResolver; $this->methodsMapProcessor = $methodsMapProcessor; $this->extensionAttributesProcessor = $extensionAttributesProcessor; $this->typeCaster = $typeCaster; @@ -100,7 +88,7 @@ public function buildOutputDataArray($dataObject, $dataObjectType) } if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) { - $value = $this->convertCustomAttributes($value, $dataObjectType); + $value = $this->customAttributesProcessor->buildOutputDataArray($dataObject, $dataObjectType); } elseif ($key === "extension_attributes") { $value = $this->extensionAttributesProcessor->buildOutputDataArray($value, $returnType); } else { @@ -125,59 +113,4 @@ public function buildOutputDataArray($dataObject, $dataObjectType) } return $outputData; } - - /** - * Convert array of custom_attributes to use flat array structure - * - * @param \Magento\Framework\Api\AttributeInterface[] $customAttributes - * @param string $dataObjectType - * @return array - */ - protected function convertCustomAttributes($customAttributes, $dataObjectType) - { - $result = []; - foreach ((array)$customAttributes as $customAttribute) { - $result[] = $this->convertCustomAttribute($customAttribute, $dataObjectType); - } - return $result; - } - - /** - * Convert custom_attribute object to use flat array structure - * - * @param \Magento\Framework\Api\AttributeInterface $customAttribute - * @param string $dataObjectType - * @return array - */ - protected function convertCustomAttribute($customAttribute, $dataObjectType) - { - $data = []; - $data[AttributeValue::ATTRIBUTE_CODE] = $customAttribute->getAttributeCode(); - $value = $customAttribute->getValue(); - if (is_object($value)) { - $type = $this->attributeTypeResolver->resolveObjectType( - $customAttribute->getAttributeCode(), - $value, - $dataObjectType - ); - $value = $this->buildOutputDataArray($value, $type); - } elseif (is_array($value)) { - $valueResult = []; - foreach ($value as $singleValue) { - if (is_object($singleValue)) { - $type = $this->attributeTypeResolver->resolveObjectType( - $customAttribute->getAttributeCode(), - $singleValue, - $dataObjectType - ); - $singleValue = $this->buildOutputDataArray($singleValue, $type); - } - // Cannot cast to a type because the type is unknown - $valueResult[] = $singleValue; - } - $value = $valueResult; - } - $data[AttributeValue::VALUE] = $value; - return $data; - } } diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 35cdc3812b04a..b093484d522a8 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -15,14 +15,10 @@ use Zend\Code\Reflection\MethodReflection; /** - * Processes extension attributes and produces a PHP array for the data. + * Processes extension attributes and produces an array for the data. */ class ExtensionAttributesProcessor { - const IS_METHOD_PREFIX = 'is'; - const HAS_METHOD_PREFIX = 'has'; - const GETTER_PREFIX = 'get'; - /** * @var DataObjectProcessor */ From d6c704378bd93295375ed28a268248cdbe3e5094 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 15:33:30 -0500 Subject: [PATCH 18/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix unit test --- .../Controller/Soap/Request/HandlerTest.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php index 2800d5466585f..8c3741c3b8d48 100644 --- a/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php @@ -40,6 +40,9 @@ class HandlerTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Framework\Reflection\DataObjectProcessor|\PHPUnit_Framework_MockObject_MockObject */ protected $_dataObjectProcessorMock; + /** @var \Magento\Framework\Reflection\MethodsMap|\PHPUnit_Framework_MockObject_MockObject */ + protected $_methodsMapProcessorMock; + /** @var array */ protected $_arguments; @@ -67,7 +70,13 @@ protected function setUp() ); $this->_dataObjectProcessorMock = $this->getMock( 'Magento\Framework\Reflection\DataObjectProcessor', - ['getMethodReturnType'], + [], + [], + '', + false); + $this->_methodsMapProcessorMock = $this->getMock( + 'Magento\Framework\Reflection\MethodsMap', + [], [], '', false); @@ -80,7 +89,8 @@ protected function setUp() $this->_authorizationMock, $this->_dataObjectConverter, $this->_serviceInputProcessorMock, - $this->_dataObjectProcessorMock + $this->_dataObjectProcessorMock, + $this->_methodsMapProcessorMock ); parent::setUp(); } @@ -128,10 +138,6 @@ public function testCall() ->method('process') ->will($this->returnArgument(2)); - $this->_dataObjectProcessorMock->expects($this->any())->method('getMethodReturnType') - ->with($className, $methodName) - ->will($this->returnValue('string')); - /** Execute SUT. */ $this->assertEquals( ['result' => $serviceResponse], From c3b1e645e9dcc69b360c7af0e63ac87ebc2f885e Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 15:34:09 -0500 Subject: [PATCH 19/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Use CustomAttributesProcessor --- app/code/Magento/Webapi/etc/di.xml | 1 + .../Reflection/DataObjectProcessor.php | 28 ++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml index c4cdae6b4883d..94f49a8395f3e 100644 --- a/app/code/Magento/Webapi/etc/di.xml +++ b/app/code/Magento/Webapi/etc/di.xml @@ -30,6 +30,7 @@ Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy + Magento\Framework\Reflection\CustomAttributesProcessor\Proxy diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 8df9ee717f946..ba11032b7e470 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -14,7 +14,7 @@ use Zend\Code\Reflection\MethodReflection; /** - * Data object processor for de-serialization using class reflection + * Data object processor for array serialization using class reflection */ class DataObjectProcessor { @@ -23,11 +23,6 @@ class DataObjectProcessor */ private $methodsMapProcessor; - /** - * @var ExtensionAttributesProcessor - */ - private $extensionAttributesProcessor; - /** * @var TypeCaster */ @@ -38,22 +33,35 @@ class DataObjectProcessor */ private $fieldNamer; + /** + * @var ExtensionAttributesProcessor + */ + private $extensionAttributesProcessor; + + /** + * @var CustomAttributesProcessor + */ + private $customAttributesProcessor; + /** * @param MethodsMap $methodsMapProcessor - * @param ExtensionAttributesProcessor $extensionAttributesProcessor * @param TypeCaster $typeCaster * @param FieldNamer $fieldNamer + * @param CustomAttributesProcessor $customAttributesProcessor + * @param ExtensionAttributesProcessor $extensionAttributesProcessor */ public function __construct( MethodsMap $methodsMapProcessor, - ExtensionAttributesProcessor $extensionAttributesProcessor, TypeCaster $typeCaster, - FieldNamer $fieldNamer + FieldNamer $fieldNamer, + CustomAttributesProcessor $customAttributesProcessor, + ExtensionAttributesProcessor $extensionAttributesProcessor ) { $this->methodsMapProcessor = $methodsMapProcessor; - $this->extensionAttributesProcessor = $extensionAttributesProcessor; $this->typeCaster = $typeCaster; $this->fieldNamer = $fieldNamer; + $this->extensionAttributesProcessor = $extensionAttributesProcessor; + $this->customAttributesProcessor = $customAttributesProcessor; } /** From b83ecf350a3922cdc62c8471c6d69cde1fa2f180 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 15:54:49 -0500 Subject: [PATCH 20/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix CustomAttributesProcessor use statements --- .../Framework/Reflection/CustomAttributesProcessor.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php index ac9ff080a3024..655cfb0ee526b 100644 --- a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php @@ -7,11 +7,12 @@ namespace Magento\Framework\Reflection; use Magento\Framework\Phrase; +use Magento\Framework\Api\AttributeInterface; +use Magento\Framework\Api\AttributeValue; use Magento\Framework\Api\SimpleDataObjectConverter; use Zend\Code\Reflection\MethodReflection; use Magento\Framework\Api\CustomAttributesDataInterface; use Magento\Framework\Api\AttributeTypeResolverInterface; - /** * Processes custom attributes and produces an array for the data. */ @@ -59,11 +60,11 @@ public function buildOutputDataArray(CustomAttributesDataInterface $objectWithCu /** * Convert custom_attribute object to use flat array structure * - * @param \Magento\Framework\Api\AttributeInterface $customAttribute + * @param AttributeInterface $customAttribute * @param string $dataObjectType * @return array */ - private function convertCustomAttribute($customAttribute, $dataObjectType) + private function convertCustomAttribute(AttributeInterface $customAttribute, $dataObjectType) { $data = []; $data[AttributeValue::ATTRIBUTE_CODE] = $customAttribute->getAttributeCode(); From 6f1221996ca4ca751ae18e721642035b89dd0dd9 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 16:55:26 -0500 Subject: [PATCH 21/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix ExtensionAttributesProcessor --- .../ExtensionAttributesProcessor.php | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index b093484d522a8..90216d659f323 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -12,6 +12,7 @@ use Magento\Framework\Phrase; use Magento\Framework\Api\SimpleDataObjectConverter; use Magento\Framework\Api\ExtensionAttributesInterface; +use Magento\Framework\Reflection\MethodsMap; use Zend\Code\Reflection\MethodReflection; /** @@ -24,6 +25,11 @@ class ExtensionAttributesProcessor */ private $dataObjectProcessor; + /** + * @var MethodsMap + */ + private $methodsMapProcessor; + /** * @var AuthorizationInterface */ @@ -39,19 +45,38 @@ class ExtensionAttributesProcessor */ private $isPermissionChecked; + /** + * @var FieldNamer + */ + private $fieldNamer; + + /** + * @var TypeCaster + */ + private $typeCaster; + /** * @param DataObjectProcessor $dataObjectProcessor + * @param MethodsMap $methodsMapProcessor + * @param TypeCaster $typeCaster + * @param FieldNamer $fieldNamer * @param AuthorizationInterface $authorization * @param ExtensionAttributesConfigReader $configReader * @param bool $isPermissionChecked */ public function __construct( DataObjectProcessor $dataObjectProcessor, + MethodsMap $methodsMapProcessor, + TypeCaster $typeCaster, + FieldNamer $fieldNamer, AuthorizationInterface $authorization, ExtensionAttributesConfigReader $configReader, $isPermissionChecked = false ) { $this->dataObjectProcessor = $dataObjectProcessor; + $this->methodsMapProcessor = $methodsMapProcessor; + $this->typeCaster = $typeCaster; + $this->fieldNamer = $fieldNamer; $this->authorization = $authorization; $this->configReader = $configReader; $this->isPermissionChecked = $isPermissionChecked; @@ -66,7 +91,7 @@ public function __construct( */ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType) { - $methods = $this->dataObjectProcessor->getMethodsMap($dataObjectType); + $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType); $outputData = []; /** @var MethodReflection $method */ @@ -104,7 +129,7 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ $arrayElementType ); } - $valueResult[] = $this->dataObjectProcessor->castValueToType($singleValue, $arrayElementType); + $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType); } $value = $valueResult; } else { From 665ca1fc179f25632b2eab3d017a33d4a237c235 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 17:27:28 -0500 Subject: [PATCH 22/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Use specific DataObjectProcessor when serializing the response. This is to isolate the times whenever we write out a data array in the system. Only do permission checks on the serialization of the outbound response. --- .../Magento/Webapi/etc/webapi_rest/di.xml | 21 ++++++++++++++++++ .../Magento/Webapi/etc/webapi_soap/di.xml | 22 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/app/code/Magento/Webapi/etc/webapi_rest/di.xml b/app/code/Magento/Webapi/etc/webapi_rest/di.xml index 48420045d4afc..7941e76f564b0 100644 --- a/app/code/Magento/Webapi/etc/webapi_rest/di.xml +++ b/app/code/Magento/Webapi/etc/webapi_rest/di.xml @@ -71,4 +71,25 @@ + + + + + true + Magento\Framework\Reflection\DataObjectProcessor\Proxy + + + + + Magento\Framework\Reflection\ExtensionAttributesProcessorPermissionChecked + Magento\Framework\Reflection\CustomAttributesProcessor\Proxy + + + + + + Magento\Framework\Reflection\DataObjectProcessorPermissionChecked + + + diff --git a/app/code/Magento/Webapi/etc/webapi_soap/di.xml b/app/code/Magento/Webapi/etc/webapi_soap/di.xml index 6d5607c49c18d..c8cabfba0ac25 100644 --- a/app/code/Magento/Webapi/etc/webapi_soap/di.xml +++ b/app/code/Magento/Webapi/etc/webapi_soap/di.xml @@ -39,4 +39,26 @@ + + + + + true + Magento\Framework\Reflection\DataObjectProcessor\Proxy + + + + + Magento\Framework\Reflection\ExtensionAttributesProcessorPermissionChecked + Magento\Framework\Reflection\CustomAttributesProcessor\Proxy + + + + + + Magento\Framework\Reflection\DataObjectProcessorPermissionChecked + + + + From 63749affe4c8cea483266dfd2133c8a11012b561 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 17:42:14 -0500 Subject: [PATCH 23/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix static analysis --- .../Webapi/Test/Unit/Model/DataObjectProcessorTest.php | 6 ++++-- .../Magento/Framework/Reflection/DataObjectProcessor.php | 2 +- .../Framework/Reflection/ExtensionAttributesProcessor.php | 3 ++- lib/internal/Magento/Framework/Reflection/FieldNamer.php | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php index c42d295962737..c3f586d835a8d 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php @@ -23,13 +23,15 @@ class DataObjectProcessorTest extends \PHPUnit_Framework_TestCase protected function setup() { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $methodsMapProcessor = $objectManager->getObject('Magento\Framework\Reflection\MethodsMap', + $methodsMapProcessor = $objectManager->getObject( + 'Magento\Framework\Reflection\MethodsMap', [ 'fieldNamer' => $objectManager->getObject('Magento\Framework\Reflection\FieldNamer'), 'typeProcessor' => $objectManager->getObject('Magento\Framework\Reflection\TypeProcessor'), ] ); - $this->dataObjectProcessor = $objectManager->getObject('Magento\Framework\Reflection\DataObjectProcessor', + $this->dataObjectProcessor = $objectManager->getObject( + 'Magento\Framework\Reflection\DataObjectProcessor', [ 'methodsMapProcessor' => $methodsMapProcessor, 'typeCaster' => $objectManager->getObject('Magento\Framework\Reflection\TypeCaster'), diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index ba11032b7e470..6eb4d4e7e69ec 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -78,7 +78,7 @@ public function buildOutputDataArray($dataObject, $dataObjectType) $outputData = []; /** @var MethodReflection $method */ - foreach ($methods as $methodName => $methodReflectionData) { + foreach (array_keys($methods) as $methodName) { if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) { continue; } diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 90216d659f323..41e33028e4bc0 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -88,6 +88,7 @@ public function __construct( * @param ExtensionAttributeInterface $dataObject * @param string $dataObjectType * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType) { @@ -95,7 +96,7 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ $outputData = []; /** @var MethodReflection $method */ - foreach ($methods as $methodName => $methodReflectionData) { + foreach (array_keys($methods) as $methodName) { if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) { continue; } diff --git a/lib/internal/Magento/Framework/Reflection/FieldNamer.php b/lib/internal/Magento/Framework/Reflection/FieldNamer.php index cae90f9c8c806..f92a80d95b3ed 100644 --- a/lib/internal/Magento/Framework/Reflection/FieldNamer.php +++ b/lib/internal/Magento/Framework/Reflection/FieldNamer.php @@ -23,7 +23,7 @@ class FieldNamer const GETTER_PREFIX = 'get'; /** - * @param string + * @param string $methodName * @return string|null */ public function getFieldNameForMethodName($methodName) From c43e369a4f6d4cb90da77d9681319ecf0cd2a13f Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Mon, 27 Apr 2015 17:57:49 -0500 Subject: [PATCH 24/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix integration tests --- .../Framework/Api/Config/ReaderTest.php | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php index 351a0ba03144a..07fceddb6424b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php @@ -76,12 +76,24 @@ public function testMerge() $expectedArray = [ 'Magento\Tax\Api\Data\TaxRateInterface' => [], 'Magento\Catalog\Api\Data\Product' => [ - 'stock_item' => "Magento\CatalogInventory\Api\Data\StockItem", + 'stock_item' => [ + "type" => "Magento\CatalogInventory\Api\Data\StockItem", + "resourceRefs" => [], + ], ], 'Magento\Customer\Api\Data\CustomerInterface' => [ - 'custom_1' => "Magento\Customer\Api\Data\CustomerCustom", - 'custom_2' => "Magento\CustomerExtra\Api\Data\CustomerCustom22", - 'custom_3' => "Magento\Customer\Api\Data\CustomerCustom3", + 'custom_1' => [ + "type" => "Magento\Customer\Api\Data\CustomerCustom", + "resourceRefs" => [], + ], + 'custom_2' => [ + "type" => "Magento\CustomerExtra\Api\Data\CustomerCustom22", + "resourceRefs" => [], + ], + 'custom_3' => [ + "type" => "Magento\Customer\Api\Data\CustomerCustom3", + "resourceRefs" => [], + ], ], ]; From dbe003d09e5aeaad07b56ed11228dd42dd545a64 Mon Sep 17 00:00:00 2001 From: Arkadii Chyzhov Date: Tue, 28 Apr 2015 15:19:50 +0300 Subject: [PATCH 25/30] MAGETWO-36638: Update the CICD builds - added updater app bootstrap to magento test framework --- dev/tests/integration/framework/bootstrap.php | 5 +++++ dev/tests/integration/phpunit.xml.dist | 2 ++ dev/tests/unit/framework/bootstrap.php | 5 +++++ dev/tests/unit/phpunit.xml.dist | 2 ++ 4 files changed, 14 insertions(+) diff --git a/dev/tests/integration/framework/bootstrap.php b/dev/tests/integration/framework/bootstrap.php index 41453aa0becc0..b71bb17d945cc 100644 --- a/dev/tests/integration/framework/bootstrap.php +++ b/dev/tests/integration/framework/bootstrap.php @@ -8,6 +8,11 @@ require_once __DIR__ . '/../../../../app/bootstrap.php'; require_once __DIR__ . '/autoload.php'; +$updateAppBootstrap = __DIR__ . '/../../../../update/app/bootstrap.php'; +if (file_exists($updateAppBootstrap)) { + require_once $updateAppBootstrap; +} + $testsBaseDir = dirname(__DIR__); $testsTmpDir = "{$testsBaseDir}/tmp"; $magentoBaseDir = realpath("{$testsBaseDir}/../../../"); diff --git a/dev/tests/integration/phpunit.xml.dist b/dev/tests/integration/phpunit.xml.dist index 7a9e365c8f150..bd6cbffb247d6 100644 --- a/dev/tests/integration/phpunit.xml.dist +++ b/dev/tests/integration/phpunit.xml.dist @@ -18,6 +18,7 @@ testsuite + ../../../update/dev/tests/integration/testsuite testsuite/Magento/Test/Integrity testsuite/Magento/MemoryUsageTest.php @@ -27,6 +28,7 @@ ../../../app/code/Magento ../../../lib/internal/Magento + ../../../update/app/code diff --git a/dev/tests/unit/framework/bootstrap.php b/dev/tests/unit/framework/bootstrap.php index b30486b50a17d..45ae70bc21fbb 100755 --- a/dev/tests/unit/framework/bootstrap.php +++ b/dev/tests/unit/framework/bootstrap.php @@ -6,6 +6,11 @@ require_once __DIR__ . '/../../../../app/autoload.php'; +$updateAppBootstrap = __DIR__ . '/../../../../update/app/bootstrap.php'; +if (file_exists($updateAppBootstrap)) { + require_once $updateAppBootstrap; +} + if (!defined('TESTS_TEMP_DIR')) { define('TESTS_TEMP_DIR', dirname(__DIR__) . '/tmp'); } diff --git a/dev/tests/unit/phpunit.xml.dist b/dev/tests/unit/phpunit.xml.dist index 5c785e252e48a..4c5587187da79 100644 --- a/dev/tests/unit/phpunit.xml.dist +++ b/dev/tests/unit/phpunit.xml.dist @@ -17,6 +17,7 @@ ../../../lib/internal/*/*/Test/Unit ../../../lib/internal/*/*/*/Test/Unit ../../../setup/src/*/*/Test/Unit + ../../../update/dev/tests/unit/testsuite @@ -26,6 +27,7 @@ ../../../app/code/* ../../../lib/internal/Magento ../../../setup/src/* + ../../../update/app/code/* ../../../app/code/*/*/Test ../../../lib/internal/*/*/Test From 4d7743c248d1e39a160968d5542510c4463cff18 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Tue, 28 Apr 2015 10:17:56 -0500 Subject: [PATCH 26/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Fix code style --- .../Magento/Framework/Reflection/CustomAttributesProcessor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php index 655cfb0ee526b..0a98c9e39e8c2 100644 --- a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php @@ -13,6 +13,7 @@ use Zend\Code\Reflection\MethodReflection; use Magento\Framework\Api\CustomAttributesDataInterface; use Magento\Framework\Api\AttributeTypeResolverInterface; + /** * Processes custom attributes and produces an array for the data. */ From 148cd4cd47d11af2bbb9febc482931ca2b1860bb Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Tue, 28 Apr 2015 10:19:32 -0500 Subject: [PATCH 27/30] MAGETWO-36064: Add ACL configuration to CatalogInventory attributes of the ProductInterface - Comment out configuration since we need to wait for a merge from a different team and this will cause web APIs to fail because there is no extension attribute for stock_item yet. --- .../Magento/CatalogInventory/etc/service_data_attributes.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml index 587b98b401a09..577b4678c42e9 100644 --- a/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml +++ b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml @@ -7,10 +7,14 @@ --> + From 5e5213a64e34abd1d5bca18e5860422e5d0259a1 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Tue, 28 Apr 2015 11:35:39 -0500 Subject: [PATCH 28/30] MAGETWO-36064: Add ACL configuration to CatalogInventory attributes of the ProductInterface - Cherry-pick commit where extension attributes are made optional --- .../Api/Code/Generator/ExtensionAttributesGenerator.php | 2 +- .../Api/Test/Unit/Code/Generator/_files/SampleExtension.txt | 4 ++-- .../Unit/Code/Generator/_files/SampleExtensionInterface.txt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php b/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php index f1d50f50d084d..aa91250b41fb3 100644 --- a/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php +++ b/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php @@ -88,7 +88,7 @@ protected function _getClassMethods() $methods[] = [ 'name' => $getterName, 'body' => "return \$this->_get('{$attributeName}');", - 'docblock' => ['tags' => [['name' => 'return', 'description' => $attributeType]]], + 'docblock' => ['tags' => [['name' => 'return', 'description' => $attributeType . '|null']]], ]; $methods[] = [ 'name' => $setterName, diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt index 8b5caad1ecc44..0f9838bd8736c 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt @@ -6,7 +6,7 @@ namespace Magento\Catalog\Api\Data; class ProductExtension extends \Magento\Framework\Api\AbstractSimpleObject implements \Magento\Catalog\Api\Data\ProductExtensionInterface { /** - * @return string + * @return string|null */ public function getStringAttribute() { @@ -24,7 +24,7 @@ class ProductExtension extends \Magento\Framework\Api\AbstractSimpleObject imple } /** - * @return \Magento\Bundle\Api\Data\OptionInterface[] + * @return \Magento\Bundle\Api\Data\OptionInterface[]|null */ public function getComplexObjectAttribute() { diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt index ec9edd7affc2d..75dde39b21519 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt @@ -6,7 +6,7 @@ namespace Magento\Catalog\Api\Data; interface ProductExtensionInterface extends \Magento\Framework\Api\ExtensionAttributesInterface { /** - * @return string + * @return string|null */ public function getStringAttribute(); @@ -17,7 +17,7 @@ interface ProductExtensionInterface extends \Magento\Framework\Api\ExtensionAttr public function setStringAttribute($stringAttribute); /** - * @return \Magento\Bundle\Api\Data\OptionInterface[] + * @return \Magento\Bundle\Api\Data\OptionInterface[]|null */ public function getComplexObjectAttribute(); From 5eb9b370326dfbefdda94c7a606ca5057c52c1ac Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Tue, 28 Apr 2015 14:29:16 -0500 Subject: [PATCH 29/30] MAGETWO-36063: Update REST and SOAP controllers to filter out attributes based on ACL - Add more unit tests --- .../Reflection/DataObjectProcessor.php | 7 +- .../ExtensionAttributesProcessor.php | 4 - .../Framework/Reflection/FieldNamer.php | 4 +- .../Framework/Reflection/MethodsMap.php | 16 +- .../Test/Unit/ExtensionAttributesObject.php | 30 +++ .../Unit/ExtensionAttributesProcessorTest.php | 173 +++++++++++++++++ .../Reflection/Test/Unit/FieldNamerTest.php | 52 ++++++ .../Reflection/Test/Unit/MethodsMapTest.php | 174 ++++++++++++++++++ .../Reflection/Test/Unit/TypeCasterTest.php | 61 ++++++ .../Framework/Reflection/TypeCaster.php | 2 +- 10 files changed, 509 insertions(+), 14 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php index 6eb4d4e7e69ec..4adceb83c7720 100644 --- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php @@ -84,8 +84,11 @@ public function buildOutputDataArray($dataObject, $dataObjectType) } $value = $dataObject->{$methodName}(); - $isMethodRequired = $this->methodsMapProcessor->isMethodRequired($dataObjectType, $methodName); - if ($value === null && !$isMethodRequired) { + $isMethodReturnValueRequired = $this->methodsMapProcessor->isMethodReturnValueRequired( + $dataObjectType, + $methodName + ); + if ($value === null && !$isMethodReturnValueRequired) { continue; } diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 41e33028e4bc0..c2d2d69c758f8 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -112,10 +112,6 @@ public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $ continue; } - // should write field? - // isWriterValid - // what value should be written - $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName); if (is_object($value) && !($value instanceof Phrase)) { diff --git a/lib/internal/Magento/Framework/Reflection/FieldNamer.php b/lib/internal/Magento/Framework/Reflection/FieldNamer.php index f92a80d95b3ed..2e105b9a4f666 100644 --- a/lib/internal/Magento/Framework/Reflection/FieldNamer.php +++ b/lib/internal/Magento/Framework/Reflection/FieldNamer.php @@ -14,7 +14,7 @@ use Zend\Code\Reflection\MethodReflection; /** - * Determines the name to use for fields given metadata. + * Determines the name to use for fields in a data output array given method metadata. */ class FieldNamer { @@ -23,6 +23,8 @@ class FieldNamer const GETTER_PREFIX = 'get'; /** + * Converts a method's name into a data field name. + * * @param string $methodName * @return string|null */ diff --git a/lib/internal/Magento/Framework/Reflection/MethodsMap.php b/lib/internal/Magento/Framework/Reflection/MethodsMap.php index 6019fddc0b0ea..36b446d1b870a 100644 --- a/lib/internal/Magento/Framework/Reflection/MethodsMap.php +++ b/lib/internal/Magento/Framework/Reflection/MethodsMap.php @@ -10,7 +10,7 @@ use Zend\Code\Reflection\MethodReflection; /** - * Determines method metadata information. + * Gathers method metadata information. */ class MethodsMap { @@ -56,15 +56,15 @@ public function __construct( } /** - * Get return type by interface name and method + * Get return type by type name and method name. * - * @param string $interfaceName + * @param string $typeName * @param string $methodName * @return string */ - public function getMethodReturnType($interfaceName, $methodName) + public function getMethodReturnType($typeName, $methodName) { - return $this->getMethodsMap($interfaceName)[$methodName]['type']; + return $this->getMethodsMap($typeName)[$methodName]['type']; } /** @@ -142,6 +142,8 @@ private function isSuitableMethod($method) } /** + * Determines if the given method's on the given type is suitable for an output data array. + * * @param string $type * @param string $methodName * @return bool @@ -164,11 +166,13 @@ public function isMethodValidForDataField($type, $methodName) } /** + * If the method has only non-null return types + * * @param string $type * @param string $methodName * @return bool */ - public function isMethodRequired($type, $methodName) + public function isMethodReturnValueRequired($type, $methodName) { $methods = $this->getMethodsMap($type); return $methods[$methodName]['isRequired']; diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php new file mode 100644 index 0000000000000..66077712a43b3 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php @@ -0,0 +1,30 @@ +dataObjectProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\DataObjectProcessor') + ->disableOriginalConstructor() + ->getMock(); + $this->methodsMapProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\MethodsMap') + ->disableOriginalConstructor() + ->getMock(); + $this->typeCasterMock = $this->getMockBuilder('Magento\Framework\Reflection\TypeCaster') + ->disableOriginalConstructor() + ->getMock(); + $this->fieldNamerMock = $this->getMockBuilder('Magento\Framework\Reflection\FieldNamer') + ->disableOriginalConstructor() + ->getMock(); + $this->configReaderMock = $this->getMockBuilder('Magento\Framework\Api\Config\Reader') + ->disableOriginalConstructor() + ->getMock(); + $this->authorizationMock = $this->getMockBuilder('Magento\Framework\AuthorizationInterface') + ->disableOriginalConstructor() + ->getMock(); + + $this->model = $objectManager->getObject( + 'Magento\Framework\Reflection\ExtensionAttributesProcessor', + [ + 'dataObjectProcessor' => $this->dataObjectProcessorMock, + 'methodsMapProcessor' => $this->methodsMapProcessorMock, + 'typeCaster' => $this->typeCasterMock, + 'fieldNamer' => $this->fieldNamerMock, + 'authorization' => $this->authorizationMock, + 'configReader' => $this->configReaderMock, + 'isPermissionChecked' => true, + ] + ); + } + + /** + * @param bool $isPermissionAllowed + * @param array $expectedValue + * @dataProvider buildOutputDataArrayWithPermissionProvider + */ + public function testBuildOutputDataArrayWithPermission($isPermissionAllowed, $expectedValue) + { + $dataObject = new \Magento\Framework\Reflection\Test\Unit\ExtensionAttributesObject(); + $dataObjectType = 'Magento\Framework\Reflection\Test\Unit\ExtensionAttributesObject'; + $methodName = 'getAttrName'; + $attributeName = 'attr_name'; + $attributeValue = 'attrName'; + + $this->methodsMapProcessorMock->expects($this->once()) + ->method('getMethodsMap') + ->with($dataObjectType) + ->will($this->returnValue([$methodName => []])); + $this->methodsMapProcessorMock->expects($this->once()) + ->method('isMethodValidForDataField') + ->with($dataObjectType, $methodName) + ->will($this->returnValue(true)); + $this->fieldNamerMock->expects($this->once()) + ->method('getFieldNameForMethodName') + ->with($methodName) + ->will($this->returnValue($attributeName)); + $permissionName = 'Magento_Permission'; + $this->configReaderMock->expects($this->once()) + ->method('read') + ->will($this->returnValue([ + $dataObjectType => [ + $attributeName => [ Converter::RESOURCE_PERMISSIONS => [ $permissionName ] ] + ] + ])); + $this->authorizationMock->expects($this->once()) + ->method('isAllowed') + ->with($permissionName) + ->will($this->returnValue($isPermissionAllowed)); + + if ($isPermissionAllowed) { + $this->methodsMapProcessorMock->expects($this->once()) + ->method('getMethodReturnType') + ->with($dataObjectType, $methodName) + ->will($this->returnValue('string')); + $this->typeCasterMock->expects($this->once()) + ->method('castValueToType') + ->with($attributeValue, 'string') + ->will($this->returnValue($attributeValue)); + } + + $value = $this->model->buildOutputDataArray( + $dataObject, + $dataObjectType + ); + + $this->assertEquals( + $value, + $expectedValue + ); + } + + public function buildOutputDataArrayWithPermissionProvider() + { + return [ + 'permission allowed' => [ + true, + [ + 'attr_name' => 'attrName', + ], + ], + 'permission not allowed' => [ + false, + [], + ], + ]; + } + +} diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php new file mode 100644 index 0000000000000..1d498a940ec1a --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php @@ -0,0 +1,52 @@ +model = $objectManager->getObject('Magento\Framework\Reflection\FieldNamer'); + } + + /** + * @param string $methodName + * @param string $expectedName + * @dataProvider methodNameProvider + */ + public function testGetFieldNameForMethodName($methodName, $expectedName) + { + $value = $this->model->getFieldNameForMethodName($methodName); + $this->assertEquals($value, $expectedName); + } + + /** + * @return array + */ + public function methodNameProvider() + { + return [ + 'isMethod' => ['isValid', 'valid'], + 'getMethod' => ['getValue', 'value'], + 'hasMethod' => ['hasStuff', 'stuff'], + 'randomMethod' => ['randomMethod', null], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php new file mode 100644 index 0000000000000..82f859897da9b --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php @@ -0,0 +1,174 @@ +getMockBuilder('Magento\Framework\Cache\FrontendInterface') + ->getMockForAbstractClass(); + $cacheMock->expects($this->any()) + ->method('save'); + $cacheMock->expects($this->any()) + ->method('load') + ->will($this->returnValue(null)); + + $attributeTypeResolverMock = $this->getMockBuilder('Magento\Framework\Api\AttributeTypeResolverInterface') + ->getMockForAbstractClass(); + $fieldNamerMock = $this->getMockBuilder('Magento\Framework\Reflection\FieldNamer') + ->getMockForAbstractClass(); + $this->model = $objectManager->getObject( + 'Magento\Framework\Reflection\MethodsMap', + [ + 'cache' => $cacheMock, + 'typeProcessor' => new TypeProcessor(), + 'typeResolver' => $attributeTypeResolverMock, + 'fieldNamer' => $fieldNamerMock, + ] + ); + } + + public function testGetMethodReturnType() + { + $this->assertEquals( + 'string', + $this->model->getMethodReturnType('Magento\Framework\Reflection\FieldNamer', 'getFieldNameForMethodName') + ); + $this->assertEquals( + 'mixed', + $this->model->getMethodReturnType('Magento\Framework\Reflection\TypeCaster', 'castValueToType') + ); + $this->assertEquals( + 'array', + $this->model->getMethodReturnType('Magento\Framework\Reflection\MethodsMap', 'getMethodsMap') + ); + } + + public function testGetMethodsMap() + { + $methodsMap = $this->model->getMethodsMap('Magento\Framework\Reflection\MethodsMap'); + $this->assertEquals( + $methodsMap, + [ + 'getMethodReturnType' => [ + 'type' => 'string', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2, + ], + 'getMethodsMap' => [ + 'type' => 'array', + 'isRequired' => true, + 'description' => "
     Service methods' reflection data stored in cache as 'methodName' => "
    +                        . "'returnType' ex. [ 'create' => '\Magento\Customer\Api\Data\Customer', 'validatePassword' "
    +                        . "=> 'boolean' ] 
    ", + 'parameterCount' => 1, + ], + 'isMethodValidForDataField' => [ + 'type' => 'bool', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2, + ], + 'isMethodReturnValueRequired' => [ + 'type' => 'bool', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2, + ], + ] + ); + } + + /** + * @param string $type + * @param string $methodName + * @param bool $expectedResult + * @dataProvider isMethodValidForDataFieldProvider + */ + public function testIsMethodValidForDataField($type, $methodName, $expectedResult) + { + $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult); + } + + /** + * @return array + */ + public function isMethodValidForDataFieldProvider() + { + return [ + 'MethodsMap#isMethodValidForDataField' => [ + 'Magento\Framework\Reflection\MethodsMap', + 'isMethodValidForDataField', + false, + ], + 'DataObject#getAttrName' => [ + 'Magento\Framework\Reflection\Test\Unit\DataObject', + 'getAttrName', + true, + ], + 'DataObject#isActive' => [ + 'Magento\Framework\Reflection\Test\Unit\DataObject', + 'isActive', + true, + ], + ]; + } + + /** + * @param string $type + * @param string $methodName + * @param bool $expectedResult + * @dataProvider isMethodReturnValueRequiredProvider + */ + public function testIsMethodReturnValueRequired($type, $methodName, $expectedResult) + { + $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult); + } + + /** + * @return array + */ + public function isMethodReturnValueRequiredProvider() + { + return [ + 'DataObject#getAttrName' => [ + 'Magento\Framework\Reflection\Test\Unit\DataObject', + 'getAttrName', + true, + ], + 'DataObject#isActive' => [ + 'Magento\Framework\Reflection\Test\Unit\DataObject', + 'isActive', + true, + ], + 'FieldNamer#getFieldNameForMethodName' => [ + 'Magento\Framework\Reflection\FieldNamer', + 'getFieldNameForMethodName', + false, + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php new file mode 100644 index 0000000000000..8f7afdbbedcb0 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php @@ -0,0 +1,61 @@ +model = $objectManager->getObject('Magento\Framework\Reflection\TypeCaster'); + } + + /** + * @param mixed $origValue + * @param string $typeToCast + * @param mixed $expectedValue + * @dataProvider typeCastValueProvider + */ + public function testCastValues($origValue, $typeToCast, $expectedValue) + { + $value = $this->model->castValueToType($origValue, $typeToCast); + $this->assertTrue($value === $expectedValue); + } + + /** + * @return array + */ + public function typeCastValueProvider() + { + return [ + 'null' => [null, 'int', null], + 'int' => ['1', 'int', 1], + 'integer' => ['1', 'integer', 1], + 'string' => ['1', 'string', '1'], + 'bool 0' => ['0', 'bool', false], + 'bool 1' => ['1', 'bool', true], + 'boolean 0' => ['0', 'boolean', false], + 'boolean 1' => ['1', 'boolean', true], + 'true' => ['1', 'true', true], + 'false' => ['0', 'false', false], + 'float' => ['1.03', 'float', 1.03], + 'double' => ['1.30', 'double', 1.30], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Reflection/TypeCaster.php b/lib/internal/Magento/Framework/Reflection/TypeCaster.php index 1b9aa0facf1f1..185b86c1d880b 100644 --- a/lib/internal/Magento/Framework/Reflection/TypeCaster.php +++ b/lib/internal/Magento/Framework/Reflection/TypeCaster.php @@ -12,7 +12,7 @@ class TypeCaster { /** - * Cast the output type to the documented type. This helps for output purposes. + * Cast the output type to the documented type. This helps for consistent output (e.g. JSON). * * @param mixed $value * @param string $type From 7bb3b22911dc937035abf64cd0a41c0ea2390e24 Mon Sep 17 00:00:00 2001 From: Yuxing Zheng Date: Thu, 30 Apr 2015 16:33:56 -0500 Subject: [PATCH 30/30] MAGETWO-36818: Merge and Fix builds - Code style changes to fix static test failures --- app/code/Magento/Backend/Block/Menu.php | 1 + .../Test/Unit/ExtensionAttributesProcessorTest.php | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Backend/Block/Menu.php b/app/code/Magento/Backend/Block/Menu.php index 55b37fca175e2..087fd1fa35170 100644 --- a/app/code/Magento/Backend/Block/Menu.php +++ b/app/code/Magento/Backend/Block/Menu.php @@ -436,6 +436,7 @@ protected function _addSubMenu($menuItem, $level, $limit, $id = null) * @param array $colBrakes * @return string HTML * @SuppressWarnings(PHPMD.NPathComplexity) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function renderNavigation($menu, $level = 0, $limit = 0, $colBrakes = []) { diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php index b411eb75647d6..8da0c1f734f71 100644 --- a/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php @@ -9,16 +9,16 @@ use Magento\Framework\Api\Config\Converter; use Magento\Framework\Api\Config\Reader; use Magento\Framework\AuthorizationInterface; +use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Reflection\ExtensionAttributesProcessor; use Magento\Framework\Reflection\FieldNamer; use Magento\Framework\Reflection\MethodsMap; use Magento\Framework\Reflection\TypeCaster; -use Magento\Framework\Reflection\TypeProcessor; /** * ExtensionAttributesProcessor test */ -class ExtensionsAttributesProcessorTest extends \PHPUnit_Framework_TestCase +class ExtensionAttributesProcessorTest extends \PHPUnit_Framework_TestCase { /** * @var ExtensionAttributesProcessor @@ -28,12 +28,12 @@ class ExtensionsAttributesProcessorTest extends \PHPUnit_Framework_TestCase /** * @var DataObjectProcessor */ - private $dataObjectProcessor; + private $dataObjectProcessorMock; /** * @var MethodsMap */ - private $methodsMapProcessor; + private $methodsMapProcessorMock; /** * @var FieldNamer @@ -169,5 +169,4 @@ public function buildOutputDataArrayWithPermissionProvider() ], ]; } - }