From 38e7ef3d794362ba5d57a2847a8f2975bf752bc8 Mon Sep 17 00:00:00 2001 From: Andrii Lugovyi Date: Thu, 16 Jul 2015 17:42:24 +0300 Subject: [PATCH 01/87] MAGETWO-40302: Filter by Quantity does not work correct in Product grid - add isset --- .../Ui/DataProvider/Product/AddQuantityFilterToCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollection.php b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollection.php index d1b14ad2b21b6..df5d52a9bc935 100644 --- a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollection.php +++ b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollection.php @@ -25,7 +25,7 @@ public function addFilter(Collection $collection, $field, $condition = null) (float)$condition['from'] ); } - if ($condition['to']) { + if (isset($condition['to'])) { $collection->getSelect()->where( AbstractCollection::ATTRIBUTE_TABLE_ALIAS_PREFIX . 'qty.qty <= ?', (float)$condition['to'] From 47effeaefbc86de7ab1adbf5c11b6a9ecface946 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 11:32:27 +0300 Subject: [PATCH 02/87] MAGETWO-41072: Add support for remove attribute --- .../Framework/View/Layout/Reader/Block.php | 13 +++++++--- .../View/Layout/Reader/Container.php | 25 ++++++++++++++++++- .../View/Layout/ScheduledStructure.php | 5 +++- .../Framework/View/Layout/etc/elements.xsd | 2 ++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Block.php b/lib/internal/Magento/Framework/View/Layout/Reader/Block.php index 1ac5fa2d923e0..f5b15c4d04bf3 100644 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Block.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Block.php @@ -158,10 +158,15 @@ protected function scheduleReference( Layout\Element $currentElement ) { $elementName = $currentElement->getAttribute('name'); - $data = $scheduledStructure->getStructureElementData($elementName, []); - $this->updateScheduledData($currentElement, $data); - $this->evaluateArguments($currentElement, $data); - $scheduledStructure->setStructureElementData($elementName, $data); + $elementRemove = (bool)$currentElement->getAttribute('remove'); + if ($elementRemove) { + $scheduledStructure->setElementToRemoveList($elementName); + } else { + $data = $scheduledStructure->getStructureElementData($elementName, []); + $this->updateScheduledData($currentElement, $data); + $this->evaluateArguments($currentElement, $data); + $scheduledStructure->setStructureElementData($elementName, $data); + } } /** diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php index c6c8a643c3c12..c322b31b48535 100644 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php @@ -81,7 +81,7 @@ public function interpret(Context $readerContext, Layout\Element $currentElement break; case self::TYPE_REFERENCE_CONTAINER: - $this->mergeContainerAttributes($readerContext->getScheduledStructure(), $currentElement); + $this->containerReference($readerContext->getScheduledStructure(), $currentElement); break; default: @@ -122,4 +122,27 @@ protected function mergeContainerAttributes( } $scheduledStructure->setStructureElementData($containerName, $elementData); } + + /** + * Handling reference of container + * + * If attribute remove="true" then add the element to list remove, + * else merge container attributes and invoke setStructureElementData + * + * @param Layout\ScheduledStructure $scheduledStructure + * @param Layout\Element $currentElement + */ + protected function containerReference( + Layout\ScheduledStructure $scheduledStructure, + Layout\Element $currentElement + ) { + $containerName = $currentElement->getAttribute('name'); + $containerRemove = (bool)$currentElement->getAttribute('remove'); + + if ($containerRemove) { + $scheduledStructure->setElementToRemoveList($containerName); + } else { + $this->mergeContainerAttributes($scheduledStructure, $currentElement); + } + } } diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php index 41bcaf682e14c..7342ad6c31a30 100644 --- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php +++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php @@ -99,7 +99,10 @@ public function getListToMove() */ public function getListToRemove() { - return array_keys(array_intersect_key($this->_scheduledElements, $this->_scheduledRemoves)); + return array_keys(array_intersect_key( + $this->_scheduledElements, + array_merge($this->_scheduledRemoves, $this->_brokenParent) + )); } /** diff --git a/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd b/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd index fc44f93df682b..739ce0985a075 100644 --- a/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd @@ -314,6 +314,7 @@ + @@ -329,6 +330,7 @@ + From 89cc3dfce537f76441954a63463334a8804de66f Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 13:12:37 +0300 Subject: [PATCH 03/87] MAGETWO-41072: Add support for remove attribute --- .../Framework/View/Layout/Reader/Block.php | 3 +- .../View/Layout/Reader/Container.php | 5 +- .../View/Layout/ScheduledStructure.php | 102 ++++----- .../Test/Unit/Layout/Reader/BlockTest.php | 18 +- .../Test/Unit/Layout/Reader/ContainerTest.php | 67 +++++- .../Unit/Layout/ScheduledStructureTest.php | 194 +++++++++--------- 6 files changed, 230 insertions(+), 159 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Block.php b/lib/internal/Magento/Framework/View/Layout/Reader/Block.php index f5b15c4d04bf3..091439fc8c2b6 100644 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Block.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Block.php @@ -158,7 +158,7 @@ protected function scheduleReference( Layout\Element $currentElement ) { $elementName = $currentElement->getAttribute('name'); - $elementRemove = (bool)$currentElement->getAttribute('remove'); + $elementRemove = filter_var($currentElement->getAttribute('remove'), FILTER_VALIDATE_BOOLEAN); if ($elementRemove) { $scheduledStructure->setElementToRemoveList($elementName); } else { @@ -280,6 +280,7 @@ protected function parseArguments(Layout\Element $node) * * @param Layout\Element $blockElement * @param array $data + * @return void */ protected function evaluateArguments(Layout\Element $blockElement, array &$data) { diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php index c322b31b48535..02af3a5936497 100644 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php @@ -127,17 +127,18 @@ protected function mergeContainerAttributes( * Handling reference of container * * If attribute remove="true" then add the element to list remove, - * else merge container attributes and invoke setStructureElementData + * else merge container attributes * * @param Layout\ScheduledStructure $scheduledStructure * @param Layout\Element $currentElement + * @return void */ protected function containerReference( Layout\ScheduledStructure $scheduledStructure, Layout\Element $currentElement ) { $containerName = $currentElement->getAttribute('name'); - $containerRemove = (bool)$currentElement->getAttribute('remove'); + $containerRemove = filter_var($currentElement->getAttribute('remove'), FILTER_VALIDATE_BOOLEAN); if ($containerRemove) { $scheduledStructure->setElementToRemoveList($containerName); diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php index 7342ad6c31a30..d2a99e2ad3c54 100644 --- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php +++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php @@ -15,56 +15,56 @@ class ScheduledStructure * * @var array */ - protected $_scheduledStructure; + protected $scheduledStructure; /** * Scheduled structure data * * @var array */ - protected $_scheduledData; + protected $scheduledData; /** * Full information about elements to be populated in the layout structure after generating structure * * @var array */ - protected $_scheduledElements; + protected $scheduledElements; /** * Scheduled structure elements moves * * @var array */ - protected $_scheduledMoves; + protected $scheduledMoves; /** * Scheduled structure elements removes * * @var array */ - protected $_scheduledRemoves; + protected $scheduledRemoves; /** * Scheduled structure elements with ifconfig attribute * * @var array */ - protected $_scheduledIfconfig; + protected $scheduledIfconfig; /** * Materialized paths for overlapping workaround of scheduled structural elements * * @var array */ - protected $_scheduledPaths; + protected $scheduledPaths; /** * Elements with reference to non-existing parent element * * @var array */ - protected $_brokenParent = []; + protected $brokenParent = []; /** * @param array $data @@ -73,13 +73,13 @@ class ScheduledStructure */ public function __construct(array $data = []) { - $this->_scheduledStructure = isset($data['scheduledStructure']) ? $data['scheduledStructure'] : []; - $this->_scheduledData = isset($data['scheduledData']) ? $data['scheduledData'] : []; - $this->_scheduledElements = isset($data['scheduledElements']) ? $data['scheduledElements'] : []; - $this->_scheduledMoves = isset($data['scheduledMoves']) ? $data['scheduledMoves'] : []; - $this->_scheduledRemoves = isset($data['scheduledRemoves']) ? $data['scheduledRemoves'] : []; - $this->_scheduledIfconfig = isset($data['scheduledIfconfig']) ? $data['scheduledIfconfig'] : []; - $this->_scheduledPaths = isset($data['scheduledPaths']) ? $data['scheduledPaths'] : []; + $this->scheduledStructure = isset($data['scheduledStructure']) ? $data['scheduledStructure'] : []; + $this->scheduledData = isset($data['scheduledData']) ? $data['scheduledData'] : []; + $this->scheduledElements = isset($data['scheduledElements']) ? $data['scheduledElements'] : []; + $this->scheduledMoves = isset($data['scheduledMoves']) ? $data['scheduledMoves'] : []; + $this->scheduledRemoves = isset($data['scheduledRemoves']) ? $data['scheduledRemoves'] : []; + $this->scheduledIfconfig = isset($data['scheduledIfconfig']) ? $data['scheduledIfconfig'] : []; + $this->scheduledPaths = isset($data['scheduledPaths']) ? $data['scheduledPaths'] : []; } /** @@ -89,7 +89,7 @@ public function __construct(array $data = []) */ public function getListToMove() { - return array_keys(array_intersect_key($this->_scheduledElements, $this->_scheduledMoves)); + return array_keys(array_intersect_key($this->scheduledElements, $this->scheduledMoves)); } /** @@ -100,8 +100,8 @@ public function getListToMove() public function getListToRemove() { return array_keys(array_intersect_key( - $this->_scheduledElements, - array_merge($this->_scheduledRemoves, $this->_brokenParent) + $this->scheduledElements, + array_merge($this->scheduledRemoves, $this->brokenParent) )); } @@ -112,7 +112,7 @@ public function getListToRemove() */ public function getIfconfigList() { - return array_keys(array_intersect_key($this->_scheduledElements, $this->_scheduledIfconfig)); + return array_keys(array_intersect_key($this->scheduledElements, $this->scheduledIfconfig)); } /** @@ -122,7 +122,7 @@ public function getIfconfigList() */ public function getElements() { - return $this->_scheduledElements; + return $this->scheduledElements; } /** @@ -134,7 +134,7 @@ public function getElements() */ public function getElement($elementName, $default = []) { - return $this->hasElement($elementName) ? $this->_scheduledElements[$elementName] : $default; + return $this->hasElement($elementName) ? $this->scheduledElements[$elementName] : $default; } /** @@ -144,7 +144,7 @@ public function getElement($elementName, $default = []) */ public function isElementsEmpty() { - return empty($this->_scheduledElements); + return empty($this->scheduledElements); } /** @@ -156,7 +156,7 @@ public function isElementsEmpty() */ public function setElement($elementName, array $data) { - $this->_scheduledElements[$elementName] = $data; + $this->scheduledElements[$elementName] = $data; } /** @@ -167,7 +167,7 @@ public function setElement($elementName, array $data) */ public function hasElement($elementName) { - return isset($this->_scheduledElements[$elementName]); + return isset($this->scheduledElements[$elementName]); } /** @@ -178,7 +178,7 @@ public function hasElement($elementName) */ public function unsetElement($elementName) { - unset($this->_scheduledElements[$elementName]); + unset($this->scheduledElements[$elementName]); } /** @@ -190,7 +190,7 @@ public function unsetElement($elementName) */ public function getElementToMove($elementName, $default = null) { - return isset($this->_scheduledMoves[$elementName]) ? $this->_scheduledMoves[$elementName] : $default; + return isset($this->scheduledMoves[$elementName]) ? $this->scheduledMoves[$elementName] : $default; } /** @@ -202,7 +202,7 @@ public function getElementToMove($elementName, $default = null) */ public function getIfconfigElement($elementName, $default = null) { - return isset($this->_scheduledIfconfig[$elementName]) ? $this->_scheduledIfconfig[$elementName] : $default; + return isset($this->scheduledIfconfig[$elementName]) ? $this->scheduledIfconfig[$elementName] : $default; } /** @@ -214,7 +214,7 @@ public function getIfconfigElement($elementName, $default = null) */ public function setElementToMove($elementName, array $data) { - $this->_scheduledMoves[$elementName] = $data; + $this->scheduledMoves[$elementName] = $data; } /** @@ -225,7 +225,7 @@ public function setElementToMove($elementName, array $data) */ public function unsetElementFromListToRemove($elementName) { - unset($this->_scheduledRemoves[$elementName]); + unset($this->scheduledRemoves[$elementName]); } /** @@ -236,7 +236,7 @@ public function unsetElementFromListToRemove($elementName) */ public function setElementToRemoveList($elementName) { - $this->_scheduledRemoves[$elementName] = 1; + $this->scheduledRemoves[$elementName] = 1; } /** @@ -247,7 +247,7 @@ public function setElementToRemoveList($elementName) */ public function unsetElementFromIfconfigList($elementName) { - unset($this->_scheduledIfconfig[$elementName]); + unset($this->scheduledIfconfig[$elementName]); } /** @@ -260,7 +260,7 @@ public function unsetElementFromIfconfigList($elementName) */ public function setElementToIfconfigList($elementName, $configPath, $scopeType) { - $this->_scheduledIfconfig[$elementName] = [$configPath, $scopeType]; + $this->scheduledIfconfig[$elementName] = [$configPath, $scopeType]; } /** @@ -270,7 +270,7 @@ public function setElementToIfconfigList($elementName, $configPath, $scopeType) */ public function getStructure() { - return $this->_scheduledStructure; + return $this->scheduledStructure; } /** @@ -282,7 +282,7 @@ public function getStructure() */ public function getStructureElement($elementName, $default = null) { - return $this->hasStructureElement($elementName) ? $this->_scheduledStructure[$elementName] : $default; + return $this->hasStructureElement($elementName) ? $this->scheduledStructure[$elementName] : $default; } /** @@ -292,7 +292,7 @@ public function getStructureElement($elementName, $default = null) */ public function isStructureEmpty() { - return empty($this->_scheduledStructure); + return empty($this->scheduledStructure); } /** @@ -303,7 +303,7 @@ public function isStructureEmpty() */ public function hasStructureElement($elementName) { - return isset($this->_scheduledStructure[$elementName]); + return isset($this->scheduledStructure[$elementName]); } /** @@ -315,7 +315,7 @@ public function hasStructureElement($elementName) */ public function setStructureElement($elementName, array $data) { - $this->_scheduledStructure[$elementName] = $data; + $this->scheduledStructure[$elementName] = $data; } /** @@ -326,8 +326,8 @@ public function setStructureElement($elementName, array $data) */ public function unsetStructureElement($elementName) { - unset($this->_scheduledStructure[$elementName]); - unset($this->_scheduledData[$elementName]); + unset($this->scheduledStructure[$elementName]); + unset($this->scheduledData[$elementName]); } /** @@ -339,7 +339,7 @@ public function unsetStructureElement($elementName) */ public function getStructureElementData($elementName, $default = null) { - return isset($this->_scheduledData[$elementName]) ? $this->_scheduledData[$elementName] : $default; + return isset($this->scheduledData[$elementName]) ? $this->scheduledData[$elementName] : $default; } /** @@ -351,7 +351,7 @@ public function getStructureElementData($elementName, $default = null) */ public function setStructureElementData($elementName, array $data) { - $this->_scheduledData[$elementName] = $data; + $this->scheduledData[$elementName] = $data; } /** @@ -361,7 +361,7 @@ public function setStructureElementData($elementName, array $data) */ public function getPaths() { - return $this->_scheduledPaths; + return $this->scheduledPaths; } /** @@ -373,7 +373,7 @@ public function getPaths() */ public function getPath($elementName, $default = null) { - return $this->hasPath($elementName) ? $this->_scheduledPaths[$elementName] : $default; + return $this->hasPath($elementName) ? $this->scheduledPaths[$elementName] : $default; } /** @@ -384,7 +384,7 @@ public function getPath($elementName, $default = null) */ public function hasPath($elementName) { - return isset($this->_scheduledPaths[$elementName]); + return isset($this->scheduledPaths[$elementName]); } /** @@ -396,7 +396,7 @@ public function hasPath($elementName) */ public function setPathElement($elementName, $data) { - $this->_scheduledPaths[$elementName] = $data; + $this->scheduledPaths[$elementName] = $data; } /** @@ -407,7 +407,7 @@ public function setPathElement($elementName, $data) */ public function unsetPathElement($elementName) { - unset($this->_scheduledPaths[$elementName]); + unset($this->scheduledPaths[$elementName]); } /** @@ -418,7 +418,7 @@ public function unsetPathElement($elementName) */ public function unsetElementFromBrokenParentList($elementName) { - unset($this->_brokenParent[$elementName]); + unset($this->brokenParent[$elementName]); } /** @@ -429,7 +429,7 @@ public function unsetElementFromBrokenParentList($elementName) */ public function setElementToBrokenParentList($elementName) { - $this->_brokenParent[$elementName] = 1; + $this->brokenParent[$elementName] = 1; } /** @@ -439,7 +439,7 @@ public function setElementToBrokenParentList($elementName) */ public function flushPaths() { - $this->_scheduledPaths = []; + $this->scheduledPaths = []; } /** @@ -450,7 +450,7 @@ public function flushPaths() public function flushScheduledStructure() { $this->flushPaths(); - $this->_scheduledElements = []; - $this->_scheduledStructure = []; + $this->scheduledElements = []; + $this->scheduledStructure = []; } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php index 86570f82f9d3c..95f0c8caab17e 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php @@ -176,18 +176,26 @@ public function processBlockDataProvider() /** * @param string $literal + * @param string $remove * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $getCondition * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $setCondition + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $setRemoveCondition * @dataProvider processReferenceDataProvider */ public function testProcessReference( $literal, + $remove, $getCondition, - $setCondition + $setCondition, + $setRemoveCondition ) { $this->context->expects($this->once())->method('getScheduledStructure') ->will($this->returnValue($this->scheduledStructure)); + $this->scheduledStructure->expects($setRemoveCondition) + ->method('setElementToRemoveList') + ->with($literal); + $this->scheduledStructure->expects($getCondition) ->method('getStructureElementData') ->with($literal, []) @@ -209,7 +217,7 @@ public function testProcessReference( ); $this->prepareReaderPool( - '<' . $literal . ' name="' . $literal . '">' + '<' . $literal . ' name="' . $literal . '" remove="' . $remove . '">' . '' . '', $literal @@ -231,8 +239,10 @@ public function testProcessReference( public function processReferenceDataProvider() { return [ - ['referenceBlock', $this->once(), $this->once()], - ['page', $this->never(), $this->never()] + ['referenceBlock', 'false', $this->once(), $this->once(), $this->never()], + ['referenceBlock', 'true', $this->never(), $this->never(), $this->once()], + ['page', 'false', $this->never(), $this->never(), $this->never()], + ['page', 'true', $this->never(), $this->never(), $this->never()], ]; } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php index 2f90f4c1b1f23..33b3319b1aae5 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php @@ -56,6 +56,9 @@ protected function setUp() * @param string $containerName * @param array $structureElement * @param array $expectedData + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $getStructureCondition + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $setStructureCondition + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $setRemoveCondition * * @dataProvider processDataProvider */ @@ -63,21 +66,27 @@ public function testProcess( $elementCurrent, $containerName, $structureElement, - $expectedData + $expectedData, + $getStructureCondition, + $setStructureCondition, + $setRemoveCondition ) { /** @var ScheduledStructure|\PHPUnit_Framework_MockObject_MockObject $scheduledStructureMock */ $scheduledStructureMock = $this->getMockBuilder('Magento\Framework\View\Layout\ScheduledStructure') ->disableOriginalConstructor()->getMock(); - $scheduledStructureMock->expects($this->once()) + $scheduledStructureMock->expects($getStructureCondition) ->method('getStructureElementData') ->with($containerName) ->willReturn($structureElement); - $scheduledStructureMock->expects($this->once()) + $scheduledStructureMock->expects($setStructureCondition) ->method('setStructureElementData') ->with($containerName, $expectedData) ->willReturnSelf(); + $scheduledStructureMock->expects($setRemoveCondition) + ->method('setElementToRemoveList') + ->with($containerName); - /** @var Context|\PHPUnit_Framework_MockObject_MockObject $contextMock */ + /** @var \Magento\Framework\View\Layout\Reader\Context|\PHPUnit_Framework_MockObject_MockObject $contextMock */ $contextMock = $this->getMockBuilder('Magento\Framework\View\Layout\Reader\Context') ->disableOriginalConstructor()->getMock(); $contextMock->expects($this->any()) @@ -122,6 +131,9 @@ public function processDataProvider() 'unchanged' => 'unchanged_value', ], ], + 'getStructureCondition' => $this->once(), + 'setStructureCondition' => $this->once(), + 'setRemoveCondition' => $this->never(), ], 'referenceContainer' => [ 'elementCurrent' => $this->getElement( @@ -138,6 +150,53 @@ public function processDataProvider() Container::CONTAINER_OPT_LABEL => 'Add', ], ], + 'getStructureCondition' => $this->once(), + 'setStructureCondition' => $this->once(), + 'setRemoveCondition' => $this->never(), + ], + 'referenceContainerNoRemove' => [ + 'elementCurrent' => $this->getElement( + '', + 'referenceContainer' + ), + 'containerName' => 'reference', + 'structureElement' => [], + 'expectedData' => [ + 'attributes' => [ + Container::CONTAINER_OPT_HTML_TAG => 'span', + Container::CONTAINER_OPT_HTML_ID => 'id_add', + Container::CONTAINER_OPT_HTML_CLASS => 'new', + Container::CONTAINER_OPT_LABEL => 'Add', + ], + ], + 'getStructureCondition' => $this->once(), + 'setStructureCondition' => $this->once(), + 'setRemoveCondition' => $this->never(), + ], + 'referenceContainerRemove' => [ + 'elementCurrent' => $this->getElement( + '', + 'referenceContainer' + ), + 'containerName' => 'reference', + 'structureElement' => [], + 'expectedData' => [], + 'getStructureCondition' => $this->never(), + 'setStructureCondition' => $this->never(), + 'setRemoveCondition' => $this->once(), + ], + 'referenceContainerRemove2' => [ + 'elementCurrent' => $this->getElement( + '', + 'referenceContainer' + ), + 'containerName' => 'reference', + 'structureElement' => [], + 'expectedData' => [], + 'getStructureCondition' => $this->never(), + 'setStructureCondition' => $this->never(), + 'setRemoveCondition' => $this->once(), ] ]; } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructureTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructureTest.php index de0509c8c6a74..98d8d6a8b1993 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructureTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructureTest.php @@ -13,16 +13,16 @@ class ScheduledStructureTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Framework\View\Layout\ScheduledStructure */ - protected $_model; + protected $model; /** * @var array */ - protected $_scheduledData = []; + protected $scheduledData = []; protected function setUp() { - $this->_scheduledData = [ + $this->scheduledData = [ 'scheduledStructure' => [ 'element1' => ['data', 'of', 'element', '1'], 'element2' => ['data', 'of', 'element', '2'], @@ -62,7 +62,7 @@ protected function setUp() 'path4' => 'path 4', ], ]; - $this->_model = new \Magento\Framework\View\Layout\ScheduledStructure($this->_scheduledData); + $this->model = new \Magento\Framework\View\Layout\ScheduledStructure($this->scheduledData); } /** @@ -74,7 +74,7 @@ public function testGetListToMove() * Only elements that are present in elements list and specified in list to move can be moved */ $expected = ['element1', 'element4']; - $this->assertEquals($expected, $this->_model->getListToMove()); + $this->assertEquals($expected, $this->model->getListToMove()); } /** @@ -86,13 +86,13 @@ public function testGetListToRemove() * Only elements that are present in elements list and specified in list to remove can be removed */ $expected = ['element2', 'element3']; - $this->assertEquals($expected, $this->_model->getListToRemove()); + $this->assertEquals($expected, $this->model->getListToRemove()); } public function testGetIfconfigList() { $expected = ['element1', 'element4']; - $this->assertEquals($expected, $this->_model->getIfconfigList()); + $this->assertEquals($expected, $this->model->getIfconfigList()); } /** @@ -100,7 +100,7 @@ public function testGetIfconfigList() */ public function testGetElements() { - $this->assertEquals($this->_scheduledData['scheduledElements'], $this->_model->getElements()); + $this->assertEquals($this->scheduledData['scheduledElements'], $this->model->getElements()); } /** @@ -108,11 +108,11 @@ public function testGetElements() */ public function testGetElement() { - $expected = $this->_scheduledData['scheduledElements']['element2']; - $this->assertEquals($expected, $this->_model->getElement('element2')); + $expected = $this->scheduledData['scheduledElements']['element2']; + $this->assertEquals($expected, $this->model->getElement('element2')); $default = ['some', 'default', 'value']; - $this->assertEquals($default, $this->_model->getElement('not_existing_element', $default)); + $this->assertEquals($default, $this->model->getElement('not_existing_element', $default)); } /** @@ -120,9 +120,9 @@ public function testGetElement() */ public function testIsElementsEmpty() { - $this->assertFalse($this->_model->isElementsEmpty()); - $this->_model->flushScheduledStructure(); - $this->assertTrue($this->_model->isElementsEmpty()); + $this->assertFalse($this->model->isElementsEmpty()); + $this->model->flushScheduledStructure(); + $this->assertTrue($this->model->isElementsEmpty()); } /** @@ -133,14 +133,14 @@ public function testSetElement() $data = ['some', 'new', 'data']; /** Test add new element */ - $this->assertFalse($this->_model->hasElement('new_element')); - $this->_model->setElement('new_element', $data); - $this->assertEquals($data, $this->_model->getElement('new_element')); + $this->assertFalse($this->model->hasElement('new_element')); + $this->model->setElement('new_element', $data); + $this->assertEquals($data, $this->model->getElement('new_element')); /** Test override existing element */ - $this->assertTrue($this->_model->hasElement('element1')); - $this->_model->setElement('element1', $data); - $this->assertEquals($data, $this->_model->getElement('element1')); + $this->assertTrue($this->model->hasElement('element1')); + $this->model->setElement('element1', $data); + $this->assertEquals($data, $this->model->getElement('element1')); } /** @@ -148,8 +148,8 @@ public function testSetElement() */ public function testHasElement() { - $this->assertFalse($this->_model->hasElement('not_existing_element')); - $this->assertTrue($this->_model->hasElement('element1')); + $this->assertFalse($this->model->hasElement('not_existing_element')); + $this->assertTrue($this->model->hasElement('element1')); } /** @@ -157,9 +157,9 @@ public function testHasElement() */ public function testUnsetElement() { - $this->assertTrue($this->_model->hasElement('element1')); - $this->_model->unsetElement('element1'); - $this->assertFalse($this->_model->hasElement('element1')); + $this->assertTrue($this->model->hasElement('element1')); + $this->model->unsetElement('element1'); + $this->assertFalse($this->model->hasElement('element1')); } /** @@ -168,21 +168,21 @@ public function testUnsetElement() public function testGetElementToMove() { $this->assertEquals( - $this->_scheduledData['scheduledMoves']['element1'], - $this->_model->getElementToMove('element1') + $this->scheduledData['scheduledMoves']['element1'], + $this->model->getElementToMove('element1') ); $default = ['some', 'data']; - $this->assertEquals($default, $this->_model->getElementToMove('not_existing_element', $default)); + $this->assertEquals($default, $this->model->getElementToMove('not_existing_element', $default)); } public function getIfconfigElement() { $this->assertEquals( - $this->_scheduledData['scheduledIfconfig']['element1'], - $this->_model->getIfconfigElement('element1') + $this->scheduledData['scheduledIfconfig']['element1'], + $this->model->getIfconfigElement('element1') ); $default = ['some', 'data']; - $this->assertEquals($default, $this->_model->getIfconfigElement('not_existing_element', $default)); + $this->assertEquals($default, $this->model->getIfconfigElement('not_existing_element', $default)); } /** @@ -193,14 +193,14 @@ public function testSetElementToMove() $data = ['some', 'new', 'data', 'element', 'to', 'move']; /** Test add new element */ - $this->assertFalse($this->_model->hasElement('new_element')); - $this->_model->setElementToMove('new_element', $data); - $this->assertEquals($data, $this->_model->getElementToMove('new_element')); + $this->assertFalse($this->model->hasElement('new_element')); + $this->model->setElementToMove('new_element', $data); + $this->assertEquals($data, $this->model->getElementToMove('new_element')); /** Test override existing element */ - $this->assertNotEquals($data, $this->_model->getElementToMove('element1')); - $this->_model->setElementToMove('element1', $data); - $this->assertEquals($data, $this->_model->getElementToMove('element1')); + $this->assertNotEquals($data, $this->model->getElementToMove('element1')); + $this->model->setElementToMove('element1', $data); + $this->assertEquals($data, $this->model->getElementToMove('element1')); } /** @@ -208,9 +208,9 @@ public function testSetElementToMove() */ public function testUnsetElementFromListToRemove() { - $this->assertContains('element2', $this->_model->getListToRemove()); - $this->_model->unsetElementFromListToRemove('element2'); - $this->assertNotContains('element2', $this->_model->getListToRemove()); + $this->assertContains('element2', $this->model->getListToRemove()); + $this->model->unsetElementFromListToRemove('element2'); + $this->assertNotContains('element2', $this->model->getListToRemove()); } /** @@ -218,23 +218,23 @@ public function testUnsetElementFromListToRemove() */ public function testSetElementToRemoveList() { - $this->assertNotContains('element1', $this->_model->getListToRemove()); - $this->_model->setElementToRemoveList('element1'); - $this->assertContains('element1', $this->_model->getListToRemove()); + $this->assertNotContains('element1', $this->model->getListToRemove()); + $this->model->setElementToRemoveList('element1'); + $this->assertContains('element1', $this->model->getListToRemove()); } public function testUnsetElementFromIfconfigList() { - $this->assertContains('element4', $this->_model->getIfconfigList()); - $this->_model->unsetElementFromIfconfigList('element4'); - $this->assertNotContains('element4', $this->_model->getIfconfigList()); + $this->assertContains('element4', $this->model->getIfconfigList()); + $this->model->unsetElementFromIfconfigList('element4'); + $this->assertNotContains('element4', $this->model->getIfconfigList()); } public function testSetElementToIfconfigList() { - $this->assertNotContains('element5', $this->_model->getIfconfigList()); - $this->_model->setElementToIfconfigList('element5', 'config_path', 'scope'); - $this->assertContains('element5', $this->_model->getIfconfigList()); + $this->assertNotContains('element5', $this->model->getIfconfigList()); + $this->model->setElementToIfconfigList('element5', 'config_path', 'scope'); + $this->assertContains('element5', $this->model->getIfconfigList()); } /** @@ -242,7 +242,7 @@ public function testSetElementToIfconfigList() */ public function testGetStructure() { - $this->assertEquals($this->_scheduledData['scheduledStructure'], $this->_model->getStructure()); + $this->assertEquals($this->scheduledData['scheduledStructure'], $this->model->getStructure()); } /** @@ -250,11 +250,11 @@ public function testGetStructure() */ public function testGetStructureElement() { - $expected = $this->_scheduledData['scheduledStructure']['element2']; - $this->assertEquals($expected, $this->_model->getStructureElement('element2')); + $expected = $this->scheduledData['scheduledStructure']['element2']; + $this->assertEquals($expected, $this->model->getStructureElement('element2')); $default = ['some', 'default', 'value']; - $this->assertEquals($default, $this->_model->getStructureElement('not_existing_element', $default)); + $this->assertEquals($default, $this->model->getStructureElement('not_existing_element', $default)); } /** @@ -262,9 +262,9 @@ public function testGetStructureElement() */ public function testIsStructureEmpty() { - $this->assertFalse($this->_model->isStructureEmpty()); - $this->_model->flushScheduledStructure(); - $this->assertTrue($this->_model->isStructureEmpty()); + $this->assertFalse($this->model->isStructureEmpty()); + $this->model->flushScheduledStructure(); + $this->assertTrue($this->model->isStructureEmpty()); } /** @@ -272,8 +272,8 @@ public function testIsStructureEmpty() */ public function testHasStructureElement() { - $this->assertTrue($this->_model->hasStructureElement('element1')); - $this->assertFalse($this->_model->hasStructureElement('not_existing_element')); + $this->assertTrue($this->model->hasStructureElement('element1')); + $this->assertFalse($this->model->hasStructureElement('not_existing_element')); } /** @@ -284,14 +284,14 @@ public function testSetStructureElement() $data = ['some', 'new', 'data', 'structure', 'element']; /** Test add new structure element */ - $this->assertFalse($this->_model->hasStructureElement('new_element')); - $this->_model->setStructureElement('new_element', $data); - $this->assertEquals($data, $this->_model->getStructureElement('new_element')); + $this->assertFalse($this->model->hasStructureElement('new_element')); + $this->model->setStructureElement('new_element', $data); + $this->assertEquals($data, $this->model->getStructureElement('new_element')); /** Test override existing structure element */ - $this->assertTrue($this->_model->hasStructureElement('element1')); - $this->_model->setStructureElement('element1', $data); - $this->assertEquals($data, $this->_model->getStructureElement('element1')); + $this->assertTrue($this->model->hasStructureElement('element1')); + $this->model->setStructureElement('element1', $data); + $this->assertEquals($data, $this->model->getStructureElement('element1')); } /** @@ -299,9 +299,9 @@ public function testSetStructureElement() */ public function testUnsetStructureElement() { - $this->assertTrue($this->_model->hasStructureElement('element1')); - $this->_model->unsetStructureElement('element1'); - $this->assertFalse($this->_model->hasStructureElement('element1')); + $this->assertTrue($this->model->hasStructureElement('element1')); + $this->model->unsetStructureElement('element1'); + $this->assertFalse($this->model->hasStructureElement('element1')); } /** @@ -309,7 +309,7 @@ public function testUnsetStructureElement() */ public function testGetPaths() { - $this->assertEquals($this->_scheduledData['scheduledPaths'], $this->_model->getPaths()); + $this->assertEquals($this->scheduledData['scheduledPaths'], $this->model->getPaths()); } /** @@ -317,9 +317,9 @@ public function testGetPaths() */ public function testGetPath() { - $this->assertEquals($this->_scheduledData['scheduledPaths']['path1'], $this->_model->getPath('path1')); + $this->assertEquals($this->scheduledData['scheduledPaths']['path1'], $this->model->getPath('path1')); $default = ['some', 'data']; - $this->assertEquals($default, $this->_model->getPath('not_existing_element', $default)); + $this->assertEquals($default, $this->model->getPath('not_existing_element', $default)); } /** @@ -327,8 +327,8 @@ public function testGetPath() */ public function testHasPath() { - $this->assertTrue($this->_model->hasPath('path1')); - $this->assertFalse($this->_model->hasPath('not_existing_element')); + $this->assertTrue($this->model->hasPath('path1')); + $this->assertFalse($this->model->hasPath('not_existing_element')); } /** @@ -339,14 +339,14 @@ public function testSetPathElement() $data = ['some', 'new', 'data', 'path']; /** Test add new structure element */ - $this->assertFalse($this->_model->hasPath('new_element')); - $this->_model->setPathElement('new_element', $data); - $this->assertEquals($data, $this->_model->getPath('new_element')); + $this->assertFalse($this->model->hasPath('new_element')); + $this->model->setPathElement('new_element', $data); + $this->assertEquals($data, $this->model->getPath('new_element')); /** Test override existing structure element */ - $this->assertTrue($this->_model->hasPath('path1')); - $this->_model->setPathElement('path1', $data); - $this->assertEquals($data, $this->_model->getPath('path1')); + $this->assertTrue($this->model->hasPath('path1')); + $this->model->setPathElement('path1', $data); + $this->assertEquals($data, $this->model->getPath('path1')); } /** @@ -354,9 +354,9 @@ public function testSetPathElement() */ public function testUnsetPathElement() { - $this->assertTrue($this->_model->hasPath('path1')); - $this->_model->unsetPathElement('path1'); - $this->assertFalse($this->_model->hasPath('path1')); + $this->assertTrue($this->model->hasPath('path1')); + $this->model->unsetPathElement('path1'); + $this->assertFalse($this->model->hasPath('path1')); } /** @@ -364,9 +364,9 @@ public function testUnsetPathElement() */ public function testFlushPaths() { - $this->assertNotEmpty($this->_model->getPaths()); - $this->_model->flushPaths(); - $this->assertEmpty($this->_model->getPaths()); + $this->assertNotEmpty($this->model->getPaths()); + $this->model->flushPaths(); + $this->assertEmpty($this->model->getPaths()); } /** @@ -374,15 +374,15 @@ public function testFlushPaths() */ public function testFlushScheduledStructure() { - $this->assertNotEmpty($this->_model->getPaths()); - $this->assertNotEmpty($this->_model->getElements()); - $this->assertNotEmpty($this->_model->getStructure()); + $this->assertNotEmpty($this->model->getPaths()); + $this->assertNotEmpty($this->model->getElements()); + $this->assertNotEmpty($this->model->getStructure()); - $this->_model->flushScheduledStructure(); + $this->model->flushScheduledStructure(); - $this->assertEmpty($this->_model->getPaths()); - $this->assertEmpty($this->_model->getElements()); - $this->assertEmpty($this->_model->getStructure()); + $this->assertEmpty($this->model->getPaths()); + $this->assertEmpty($this->model->getElements()); + $this->assertEmpty($this->model->getStructure()); } /** @@ -393,13 +393,13 @@ public function testSetElementToBrokenParentList() { $element = 'element9'; $expectedToRemove = ['element2', 'element3']; - $expectedToRemoveWithBroken = ['element2', 'element3']; - $this->assertEquals($expectedToRemove, $this->_model->getListToRemove()); + $expectedToRemoveWithBroken = ['element2', 'element3', 'element9']; + $this->assertEquals($expectedToRemove, $this->model->getListToRemove()); - $this->_model->setElementToBrokenParentList($element); - $this->assertEquals($expectedToRemoveWithBroken, $this->_model->getListToRemove()); + $this->model->setElementToBrokenParentList($element); + $this->assertEquals($expectedToRemoveWithBroken, $this->model->getListToRemove()); - $this->_model->unsetElementFromBrokenParentList($element); - $this->assertEquals($expectedToRemove, $this->_model->getListToRemove()); + $this->model->unsetElementFromBrokenParentList($element); + $this->assertEquals($expectedToRemove, $this->model->getListToRemove()); } } From e8755589284a8f620fc500630e357fa08fe51fe6 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 13:26:25 +0300 Subject: [PATCH 04/87] MAGETWO-41072: Add support for remove attribute --- .../View/Test/Unit/Layout/Reader/ContainerTest.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php index 33b3319b1aae5..ca67b6f5d5f1c 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php @@ -156,18 +156,17 @@ public function processDataProvider() ], 'referenceContainerNoRemove' => [ 'elementCurrent' => $this->getElement( - '', + '', 'referenceContainer' ), 'containerName' => 'reference', 'structureElement' => [], 'expectedData' => [ 'attributes' => [ - Container::CONTAINER_OPT_HTML_TAG => 'span', - Container::CONTAINER_OPT_HTML_ID => 'id_add', - Container::CONTAINER_OPT_HTML_CLASS => 'new', - Container::CONTAINER_OPT_LABEL => 'Add', + Container::CONTAINER_OPT_HTML_TAG => null, + Container::CONTAINER_OPT_HTML_ID => null, + Container::CONTAINER_OPT_HTML_CLASS => null, + Container::CONTAINER_OPT_LABEL => null, ], ], 'getStructureCondition' => $this->once(), From 7a9914f0456009295b0471d06da08b798caf64bd Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 15:04:45 +0300 Subject: [PATCH 05/87] MAGETWO-41072: Add support for remove attribute --- .../Framework/View/Layout/ScheduledStructure.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php index d2a99e2ad3c54..90ebb4ba60dd2 100644 --- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php +++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php @@ -15,49 +15,49 @@ class ScheduledStructure * * @var array */ - protected $scheduledStructure; + protected $scheduledStructure = []; /** * Scheduled structure data * * @var array */ - protected $scheduledData; + protected $scheduledData = []; /** * Full information about elements to be populated in the layout structure after generating structure * * @var array */ - protected $scheduledElements; + protected $scheduledElements = []; /** * Scheduled structure elements moves * * @var array */ - protected $scheduledMoves; + protected $scheduledMoves = []; /** * Scheduled structure elements removes * * @var array */ - protected $scheduledRemoves; + protected $scheduledRemoves = []; /** * Scheduled structure elements with ifconfig attribute * * @var array */ - protected $scheduledIfconfig; + protected $scheduledIfconfig = []; /** * Materialized paths for overlapping workaround of scheduled structural elements * * @var array */ - protected $scheduledPaths; + protected $scheduledPaths = []; /** * Elements with reference to non-existing parent element From 9237f66282fa1b64e0cd89c2054d1618384eebd3 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 15:47:52 +0300 Subject: [PATCH 06/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../Backend/view/adminhtml/layout/admin_login.xml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Backend/view/adminhtml/layout/admin_login.xml b/app/code/Magento/Backend/view/adminhtml/layout/admin_login.xml index 35b8eebed0c28..b0891c464f5f3 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/admin_login.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/admin_login.xml @@ -9,15 +9,14 @@ - - - - - - + + + + + - - + + From b23e11283aed71b9d89f35a332ec0e53db71d2ce Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 16:21:19 +0300 Subject: [PATCH 07/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- app/code/Magento/Backend/view/adminhtml/layout/popup.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Backend/view/adminhtml/layout/popup.xml b/app/code/Magento/Backend/view/adminhtml/layout/popup.xml index 17da4d9b56eb7..e6f59c729501d 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/popup.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/popup.xml @@ -7,7 +7,7 @@ --> - - + + From 9e3370dc6d6496b5c67d0836e154fad90cdc37f3 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 5 Aug 2015 18:35:38 +0300 Subject: [PATCH 08/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../view/adminhtml/layout/catalog_product_view_type_grouped.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_view_type_grouped.xml b/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_view_type_grouped.xml index d8ba9118949b9..1cfe367c7d69c 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_view_type_grouped.xml +++ b/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_view_type_grouped.xml @@ -10,6 +10,6 @@ - + From 60833ea4f91a637dc102c79a286d718db736f96f Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 6 Aug 2015 10:57:58 +0300 Subject: [PATCH 09/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../layout/adminhtml_system_design_editor_files_index.xml | 2 +- .../adminhtml/layout/adminhtml_system_design_editor_launch.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_files_index.xml b/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_files_index.xml index 047a056d28d84..aab19bee1d1ae 100644 --- a/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_files_index.xml +++ b/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_files_index.xml @@ -7,7 +7,7 @@ --> - + diff --git a/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_launch.xml b/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_launch.xml index a9f502b6433b2..e39ca884c8c3f 100644 --- a/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_launch.xml +++ b/app/code/Magento/DesignEditor/view/adminhtml/layout/adminhtml_system_design_editor_launch.xml @@ -13,7 +13,7 @@ - + From c8b42255606077ec44394935bdd2889034f79cf1 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 6 Aug 2015 12:08:33 +0300 Subject: [PATCH 10/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../layout/checkout_index_index.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/layout/checkout_index_index.xml b/app/design/frontend/Magento/blank/Magento_Checkout/layout/checkout_index_index.xml index bf14f518dd866..9e2266e17b91a 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/layout/checkout_index_index.xml +++ b/app/design/frontend/Magento/blank/Magento_Checkout/layout/checkout_index_index.xml @@ -7,12 +7,12 @@ --> - - - - - - - + + + + + + + From 3b3dc39443cdcd27e820e83c72ff743f6780ef76 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 6 Aug 2015 12:41:15 +0300 Subject: [PATCH 11/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../layout/multishipping_checkout.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Multishipping/layout/multishipping_checkout.xml b/app/design/frontend/Magento/blank/Magento_Multishipping/layout/multishipping_checkout.xml index 9932644c28c8e..e2bf3a4438162 100644 --- a/app/design/frontend/Magento/blank/Magento_Multishipping/layout/multishipping_checkout.xml +++ b/app/design/frontend/Magento/blank/Magento_Multishipping/layout/multishipping_checkout.xml @@ -7,11 +7,11 @@ --> - - - - - - + + + + + + From ff961ad8073797b3fa9ffbbb05c7a3b2ed2ccc50 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 6 Aug 2015 12:53:31 +0300 Subject: [PATCH 12/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- app/code/Magento/Theme/view/frontend/layout/print.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Theme/view/frontend/layout/print.xml b/app/code/Magento/Theme/view/frontend/layout/print.xml index 3a1b6e54d3e94..a007ffbb9b206 100644 --- a/app/code/Magento/Theme/view/frontend/layout/print.xml +++ b/app/code/Magento/Theme/view/frontend/layout/print.xml @@ -8,9 +8,9 @@ - - - + + + From 99235831c2486d3fee33c5308e1b5d2e4198ff71 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Thu, 6 Aug 2015 15:15:50 +0300 Subject: [PATCH 13/87] MAGETWO-41074: Add support for display attribute --- .../Magento/Framework/View/Layout.php | 21 +++- .../View/Layout/Reader/Container.php | 2 + .../Framework/View/Layout/etc/elements.xsd | 2 + .../Framework/View/Test/Unit/LayoutTest.php | 110 ++++++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) mode change 100644 => 100755 lib/internal/Magento/Framework/View/Layout.php mode change 100644 => 100755 lib/internal/Magento/Framework/View/Layout/Reader/Container.php mode change 100644 => 100755 lib/internal/Magento/Framework/View/Layout/etc/elements.xsd mode change 100644 => 100755 lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php diff --git a/lib/internal/Magento/Framework/View/Layout.php b/lib/internal/Magento/Framework/View/Layout.php old mode 100644 new mode 100755 index cc6253c795d2a..1db5b60d0c4e8 --- a/lib/internal/Magento/Framework/View/Layout.php +++ b/lib/internal/Magento/Framework/View/Layout.php @@ -470,7 +470,9 @@ public function renderElement($name, $useCache = true) { $this->build(); if (!isset($this->_renderElementCache[$name]) || !$useCache) { - $this->_renderElementCache[$name] = $this->renderNonCachedElement($name); + $this->_renderElementCache[$name] = $this->displayElement($name) + ? $this->renderNonCachedElement($name) + : ''; } $this->_renderingOutput->setData('output', $this->_renderElementCache[$name]); $this->_eventManager->dispatch( @@ -480,6 +482,23 @@ public function renderElement($name, $useCache = true) return $this->_renderingOutput->getData('output'); } + /** + * Define whether to display element + * Display if 'display' attribute is absent (false, null) or equal true ('1', true, 'true') + * In any other cases - do not display + * + * @param string $name + * @return bool + */ + protected function displayElement($name) + { + $display = $this->structure->getAttribute($name, 'display'); + if ($display === false || $display === null || filter_var($display, FILTER_VALIDATE_BOOLEAN)) { + return true; + } + return false; + } + /** * Render non cached element * diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php old mode 100644 new mode 100755 index c6c8a643c3c12..e0335eeab71e6 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php @@ -26,6 +26,7 @@ class Container implements Layout\ReaderInterface const CONTAINER_OPT_HTML_CLASS = 'htmlClass'; const CONTAINER_OPT_HTML_ID = 'htmlId'; const CONTAINER_OPT_LABEL = 'label'; + const CONTAINER_OPT_DISPLAY = 'display'; /**#@-*/ /** @@ -118,6 +119,7 @@ protected function mergeContainerAttributes( self::CONTAINER_OPT_HTML_ID => (string)$currentElement[self::CONTAINER_OPT_HTML_ID], self::CONTAINER_OPT_HTML_CLASS => (string)$currentElement[self::CONTAINER_OPT_HTML_CLASS], self::CONTAINER_OPT_LABEL => (string)$currentElement[self::CONTAINER_OPT_LABEL], + self::CONTAINER_OPT_DISPLAY => $currentElement[self::CONTAINER_OPT_DISPLAY], ]; } $scheduledStructure->setStructureElementData($containerName, $elementData); diff --git a/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd b/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd old mode 100644 new mode 100755 index fc44f93df682b..92c9c7d2b75e3 --- a/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd @@ -314,6 +314,7 @@ + @@ -329,6 +330,7 @@ + diff --git a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php old mode 100644 new mode 100755 index 2e98cf8fd5d8c..e0ab3346a312c --- a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php @@ -831,4 +831,114 @@ public function testGetXml() $xml = ''; $this->assertSame($xml, \Magento\Framework\View\Layout::LAYOUT_NODE); } + + /** + * @param mixed $displayValue + * @dataProvider renderElementDisplayDataProvider + */ + public function testRenderElementDisplay($displayValue) + { + $name = 'test_container'; + $child = 'child_block'; + $children = [$child => true]; + $blockHtml = ''; + + $this->structureMock->expects($this->atLeastOnce()) + ->method('getAttribute') + ->willReturnMap( + [ + [$name, 'display', $displayValue], + [$child, 'display', $displayValue], + [$child, 'type', \Magento\Framework\View\Layout\Element::TYPE_BLOCK] + ] + ); + + $this->structureMock->expects($this->atLeastOnce())->method('hasElement') + ->willReturnMap( + [ + [$child, true] + ] + ); + + $this->structureMock->expects($this->once()) + ->method('getChildren') + ->with($name) + ->willReturn($children); + + $block = $this->getMock('Magento\Framework\View\Element\AbstractBlock', [], [], '', false); + $block->expects($this->once())->method('toHtml')->willReturn($blockHtml); + + $renderingOutput = new \Magento\Framework\DataObject(); + $renderingOutput->setData('output', $blockHtml); + + $this->eventManagerMock->expects($this->at(0)) + ->method('dispatch') + ->with( + 'core_layout_render_element', + ['element_name' => $child, 'layout' => $this->model, 'transport' => $renderingOutput] + ); + $this->eventManagerMock->expects($this->at(1)) + ->method('dispatch') + ->with( + 'core_layout_render_element', + ['element_name' => $name, 'layout' => $this->model, 'transport' => $renderingOutput] + ); + + $this->model->setBlock($child, $block); + $this->assertEquals($blockHtml, $this->model->renderElement($name, false)); + } + + /** + * @param mixed $displayValue + * @dataProvider renderElementDoNotDisplayDataProvider + */ + public function testRenderElementDoNotDisplay($displayValue) + { + $displayValue = 'false'; + $name = 'test_container'; + $blockHtml = ''; + + $this->structureMock->expects($this->atLeastOnce()) + ->method('getAttribute') + ->willReturnMap([[$name, 'display', $displayValue]]); + + $renderingOutput = new \Magento\Framework\DataObject(); + $renderingOutput->setData('output', $blockHtml); + + $this->eventManagerMock->expects($this->at(0)) + ->method('dispatch') + ->with( + 'core_layout_render_element', + ['element_name' => $name, 'layout' => $this->model, 'transport' => $renderingOutput] + ); + + $this->assertEquals($blockHtml, $this->model->renderElement($name, false)); + } + + /** + * @return array + */ + public function renderElementDoNotDisplayDataProvider() + { + return [ + ['false'], + ['0'], + [0] + ]; + } + + /** + * @return array + */ + public function renderElementDisplayDataProvider() + { + return [ + [true], + ['1'], + [1], + ['true'], + [false], + [null] + ]; + } } From af5ff326535fe891a6708e1f80548a9673ec4251 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 6 Aug 2015 15:34:03 +0300 Subject: [PATCH 14/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../frontend/Magento/luma/Magento_Theme/layout/default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml b/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml index 41178b9cd8dc6..f1033dfd490a4 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml +++ b/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml @@ -23,7 +23,7 @@ - + From 1c7f11226e83ebd315ca196f6a3fdd6015f464fc Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 6 Aug 2015 15:43:19 +0300 Subject: [PATCH 15/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../layout/adminhtml_system_design_wysiwyg_files_index.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml index 32bc75a7eda57..5f50ce5eb338d 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml @@ -7,7 +7,7 @@ --> - + From dc483c7bdd252223d1834b8e2380ad69f6d7e0a5 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Thu, 6 Aug 2015 15:58:56 +0300 Subject: [PATCH 16/87] MAGETWO-41074: Add support for display attribute --- lib/internal/Magento/Framework/View/Layout.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Layout.php b/lib/internal/Magento/Framework/View/Layout.php index 1db5b60d0c4e8..332148f1e2eb3 100755 --- a/lib/internal/Magento/Framework/View/Layout.php +++ b/lib/internal/Magento/Framework/View/Layout.php @@ -470,9 +470,11 @@ public function renderElement($name, $useCache = true) { $this->build(); if (!isset($this->_renderElementCache[$name]) || !$useCache) { - $this->_renderElementCache[$name] = $this->displayElement($name) - ? $this->renderNonCachedElement($name) - : ''; + if ($this->displayElement($name)) { + $this->_renderElementCache[$name] = $this->renderNonCachedElement($name); + } else { + return $this->_renderElementCache[$name] = ''; + } } $this->_renderingOutput->setData('output', $this->_renderElementCache[$name]); $this->_eventManager->dispatch( From 6e17a0b841c8df6ee8dfd75ad6350f61995fff17 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Thu, 6 Aug 2015 16:42:07 +0300 Subject: [PATCH 17/87] MAGETWO-41074: Add support for display attribute --- .../Magento/Framework/View/Test/Unit/LayoutTest.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php index e0ab3346a312c..b40aea316805c 100755 --- a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php @@ -902,16 +902,6 @@ public function testRenderElementDoNotDisplay($displayValue) ->method('getAttribute') ->willReturnMap([[$name, 'display', $displayValue]]); - $renderingOutput = new \Magento\Framework\DataObject(); - $renderingOutput->setData('output', $blockHtml); - - $this->eventManagerMock->expects($this->at(0)) - ->method('dispatch') - ->with( - 'core_layout_render_element', - ['element_name' => $name, 'layout' => $this->model, 'transport' => $renderingOutput] - ); - $this->assertEquals($blockHtml, $this->model->renderElement($name, false)); } From f0d31119a3fda232cb7c97978ccafcb0456f51da Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Thu, 6 Aug 2015 17:04:37 +0300 Subject: [PATCH 18/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../Checkout/view/frontend/layout/checkout_index_index.xml | 2 +- .../view/adminhtml/layout/newsletter_queue_preview.xml | 2 +- .../view/adminhtml/layout/newsletter_template_preview.xml | 2 +- .../Newsletter/view/frontend/layout/customer_account.xml | 1 - .../adminhtml/layout/paypal_billing_agreement_ordersgrid.xml | 4 ++-- .../view/adminhtml/layout/paypal_billing_agreement_view.xml | 4 ++-- .../view/adminhtml/layout/sales_transaction_child_block.xml | 2 +- .../Sales/view/frontend/layout/checkout_index_index.xml | 2 +- 8 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml index be5917f36ba62..500a2459192ea 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml @@ -411,6 +411,6 @@ - + diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml index cb7ac6cb26d42..f4b996bcaa12d 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml @@ -9,7 +9,7 @@ - + diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml index d468c2a843414..5d6173d564e20 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml @@ -9,7 +9,7 @@ - + diff --git a/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml b/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml index b2c17400a81e5..e009e753a8bd0 100644 --- a/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml @@ -15,6 +15,5 @@ - diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml index 2798a934f1915..78e295bb5557f 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml @@ -15,8 +15,8 @@ - - + + diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml index d1a23150b2983..2ea45b4fc1ffb 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml @@ -18,8 +18,8 @@ - - + + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml index f6281eb9fd04a..f937a16420e78 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml @@ -59,6 +59,6 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml index a9d1349d10f68..a61c83d274f16 100644 --- a/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml @@ -7,6 +7,6 @@ --> - + From 0a5b3a6349f32c270e8388a8919c68995cba2a58 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Thu, 6 Aug 2015 17:04:37 +0300 Subject: [PATCH 19/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../Checkout/view/frontend/layout/checkout_index_index.xml | 2 +- .../view/adminhtml/layout/newsletter_queue_preview.xml | 2 +- .../view/adminhtml/layout/newsletter_template_preview.xml | 2 +- .../Newsletter/view/frontend/layout/customer_account.xml | 1 - .../adminhtml/layout/paypal_billing_agreement_ordersgrid.xml | 4 ++-- .../view/adminhtml/layout/paypal_billing_agreement_view.xml | 4 ++-- .../view/adminhtml/layout/sales_transaction_child_block.xml | 2 +- .../Sales/view/frontend/layout/checkout_index_index.xml | 2 +- 8 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml index be5917f36ba62..500a2459192ea 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml @@ -411,6 +411,6 @@ - + diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml index cb7ac6cb26d42..f4b996bcaa12d 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml @@ -9,7 +9,7 @@ - + diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml index d468c2a843414..5d6173d564e20 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml @@ -9,7 +9,7 @@ - + diff --git a/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml b/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml index b2c17400a81e5..e009e753a8bd0 100644 --- a/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml @@ -15,6 +15,5 @@ - diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml index 2798a934f1915..78e295bb5557f 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml @@ -15,8 +15,8 @@ - - + + diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml index d1a23150b2983..2ea45b4fc1ffb 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_view.xml @@ -18,8 +18,8 @@ - - + + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml index f6281eb9fd04a..f937a16420e78 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml @@ -59,6 +59,6 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml index a9d1349d10f68..a61c83d274f16 100644 --- a/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Sales/view/frontend/layout/checkout_index_index.xml @@ -7,6 +7,6 @@ --> - + From 39651692e3ac94a07709d735e2f5083f0bdfaff3 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Fri, 7 Aug 2015 16:09:35 +0300 Subject: [PATCH 20/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../adminhtml/layout/catalog_product_attribute_edit_popup.xml | 2 +- ...alog_product_attribute_edit_product_tab_variations_popup.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml mode change 100644 => 100755 app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_attribute_edit_product_tab_variations_popup.xml diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml old mode 100644 new mode 100755 index 82899deca4005..094d3f74037a1 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> - + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_attribute_edit_product_tab_variations_popup.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_attribute_edit_product_tab_variations_popup.xml old mode 100644 new mode 100755 index 5f979c8085927..8ffec72e74e4a --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_attribute_edit_product_tab_variations_popup.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_attribute_edit_product_tab_variations_popup.xml @@ -5,6 +5,6 @@ * See COPYING.txt for license details. */ --> - + From 5086ffdb7895871849fee3fd214197ba184bd40b Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Fri, 7 Aug 2015 16:56:21 +0300 Subject: [PATCH 21/87] MAGETWO-40723: 'All store view' option is absent in Store View select for Cms pages and blocks --- .../Listing/Column/Cms/OptionsTest.php | 123 ++++++++++++++++++ .../Component/Listing/Column/Cms/Options.php | 54 ++++++++ .../ui_component/cms_block_listing.xml | 2 +- .../ui_component/cms_page_listing.xml | 2 +- .../Listing/Column/Store/Options.php | 30 ++++- 5 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/Cms/OptionsTest.php create mode 100644 app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php diff --git a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/Cms/OptionsTest.php b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/Cms/OptionsTest.php new file mode 100644 index 0000000000000..37e2e54c25c16 --- /dev/null +++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/Cms/OptionsTest.php @@ -0,0 +1,123 @@ +systemStoreMock = $this->getMockBuilder('Magento\Store\Model\System\Store') + ->disableOriginalConstructor() + ->getMock(); + + $this->websiteMock = $this->getMock( + 'Magento\Store\Model\Website', + ['getId', 'getName'], + [], + '', + false + ); + + $this->groupMock = $this->getMock('Magento\Store\Model\Group', [], [], '', false); + + $this->storeMock = $this->getMock('Magento\Store\Model\Store', [], [], '', false); + + $this->escaperMock = $this->getMock('Magento\Framework\Escaper', [], [], '', false); + + $this->options = $objectManager->getObject( + 'Magento\Cms\Ui\Component\Listing\Column\Cms\Options', + [ + 'systemStore' => $this->systemStoreMock, + 'escaper' => $this->escaperMock + ] + ); + } + + public function testToOptionArray() + { + $websiteCollection = [$this->websiteMock]; + $groupCollection = [$this->groupMock]; + $storeCollection = [$this->storeMock]; + + $expectedOptions = [ + [ + 'label' => __('All Store Views'), + 'value' => '0' + ], + [ + 'label' => 'Main Website', + 'value' => [ + [ + 'label' => ' Main Website Store', + 'value' => [ + [ + 'label' => ' Default Store View', + 'value' => '1' + ] + ] + ] + ] + ] + ]; + + $this->systemStoreMock->expects($this->once())->method('getWebsiteCollection')->willReturn($websiteCollection); + $this->systemStoreMock->expects($this->once())->method('getGroupCollection')->willReturn($groupCollection); + $this->systemStoreMock->expects($this->once())->method('getStoreCollection')->willReturn($storeCollection); + + $this->websiteMock->expects($this->atLeastOnce())->method('getId')->willReturn('1'); + $this->websiteMock->expects($this->any())->method('getName')->willReturn('Main Website'); + + $this->groupMock->expects($this->atLeastOnce())->method('getWebsiteId')->willReturn('1'); + $this->groupMock->expects($this->atLeastOnce())->method('getId')->willReturn('1'); + $this->groupMock->expects($this->atLeastOnce())->method('getName')->willReturn('Main Website Store'); + + $this->storeMock->expects($this->atLeastOnce())->method('getGroupId')->willReturn('1'); + $this->storeMock->expects($this->atLeastOnce())->method('getName')->willReturn('Default Store View'); + $this->storeMock->expects($this->atLeastOnce())->method('getId')->willReturn('1'); + + $this->escaperMock->expects($this->atLeastOnce())->method('escapeHtml')->willReturnMap( + [ + ['Default Store View', null, 'Default Store View'], + ['Main Website Store', null, 'Main Website Store'], + ['Main Website', null, 'Main Website'] + ] + ); + + $this->assertEquals($expectedOptions, $this->options->toOptionArray()); + } +} diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php new file mode 100644 index 0000000000000..cbdbc56e30ea2 --- /dev/null +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php @@ -0,0 +1,54 @@ +options !== null) { + return $this->options; + } + $websiteCollection = $this->systemStore->getWebsiteCollection(); + $groupCollection = $this->systemStore->getGroupCollection(); + $storeCollection = $this->systemStore->getStoreCollection(); + + $this->currentOptions['All Store Views']['label'] = __('All Store Views'); + $this->currentOptions['All Store Views']['value'] = self::ALL_STORE_VIEWS; + + $this->generateCurrentOptions($websiteCollection, $groupCollection, $storeCollection); + + $this->options = array_values($this->currentOptions); + + return $this->options; + } +} diff --git a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml index c1e9dad73c743..831577c18cf50 100644 --- a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml +++ b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml @@ -147,7 +147,7 @@ - Magento\Store\Ui\Component\Listing\Column\Store\Options + Magento\Cms\Ui\Component\Listing\Column\Cms\Options diff --git a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_listing.xml b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_listing.xml index 0c39341b9fc6f..1276a89b3b425 100644 --- a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_listing.xml +++ b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_listing.xml @@ -159,7 +159,7 @@ - Magento\Store\Ui\Component\Listing\Column\Store\Options + Magento\Cms\Ui\Component\Listing\Column\Cms\Options diff --git a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php index 4cbef52f9fc6c..e83a5951f55ac 100644 --- a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php +++ b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php @@ -33,6 +33,11 @@ class Options implements OptionSourceInterface */ protected $options; + /** + * @var array + */ + protected $currentOptions; + /** * Constructor * @@ -59,7 +64,23 @@ public function toOptionArray() $groupCollection = $this->systemStore->getGroupCollection(); $storeCollection = $this->systemStore->getStoreCollection(); - $currentOptions = []; + $this->generateCurrentOptions($websiteCollection, $groupCollection, $storeCollection); + + $this->options = array_values($this->currentOptions); + + return $this->options; + } + + /** + * Generate current options + * + * @param array $websiteCollection + * @param array $groupCollection + * @param array $storeCollection + * @return void + */ + protected function generateCurrentOptions(array $websiteCollection, array $groupCollection, array $storeCollection) + { /** @var \Magento\Store\Model\Website $website */ foreach ($websiteCollection as $website) { $groups = []; @@ -84,12 +105,9 @@ public function toOptionArray() } if (!empty($groups)) { $name = $this->escaper->escapeHtml($website->getName()); - $currentOptions[$name]['label'] = $name; - $currentOptions[$name]['value'] = array_values($groups); + $this->currentOptions[$name]['label'] = $name; + $this->currentOptions[$name]['value'] = array_values($groups); } } - $this->options = array_values($currentOptions); - - return $this->options; } } From 052e80d6b35933341289251ce45b70ce70ce4894 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Fri, 7 Aug 2015 18:06:17 +0300 Subject: [PATCH 22/87] MAGETWO-41073: Refactor remove directive to @remove or @display directive --- .../adminhtml/layout/catalog_product_attribute_edit_popup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml index 094d3f74037a1..4737e775592b5 100755 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml @@ -7,7 +7,7 @@ --> - + From c77a4e13eb84186548484f35643ec3535ac4fde5 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Mon, 10 Aug 2015 13:53:20 +0300 Subject: [PATCH 23/87] MAGETWO-41078: Stabilize story --- .../Test/Unit/Layout/Reader/ContainerTest.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) mode change 100644 => 100755 lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php old mode 100644 new mode 100755 index ca67b6f5d5f1c..41e99ab524fb6 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php @@ -148,6 +148,7 @@ public function processDataProvider() Container::CONTAINER_OPT_HTML_ID => 'id_add', Container::CONTAINER_OPT_HTML_CLASS => 'new', Container::CONTAINER_OPT_LABEL => 'Add', + Container::CONTAINER_OPT_DISPLAY => null, ], ], 'getStructureCondition' => $this->once(), @@ -167,6 +168,7 @@ public function processDataProvider() Container::CONTAINER_OPT_HTML_ID => null, Container::CONTAINER_OPT_HTML_CLASS => null, Container::CONTAINER_OPT_LABEL => null, + Container::CONTAINER_OPT_DISPLAY => null, ], ], 'getStructureCondition' => $this->once(), @@ -196,6 +198,27 @@ public function processDataProvider() 'getStructureCondition' => $this->never(), 'setStructureCondition' => $this->never(), 'setRemoveCondition' => $this->once(), + ], + 'referenceContainerDisplayFalse' => [ + 'elementCurrent' => $this->getElement( + '', + 'referenceContainer' + ), + 'containerName' => 'reference', + 'structureElement' => [], + 'expectedData' => [ + 'attributes' => [ + Container::CONTAINER_OPT_HTML_TAG => 'span', + Container::CONTAINER_OPT_HTML_ID => 'id_add', + Container::CONTAINER_OPT_HTML_CLASS => 'new', + Container::CONTAINER_OPT_LABEL => 'Add', + Container::CONTAINER_OPT_DISPLAY => 'true', + ], + ], + 'getStructureCondition' => $this->once(), + 'setStructureCondition' => $this->once(), + 'setRemoveCondition' => $this->never(), ] ]; } From 887ff60fc3c35bc0fed3725bb7f2c2d56beb1628 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Mon, 10 Aug 2015 14:26:09 +0300 Subject: [PATCH 24/87] MAGETWO-41078: Stabilize story --- .../Magento/Framework/View/LayoutDirectivesTest.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) mode change 100644 => 100755 dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php old mode 100644 new mode 100755 index 86be1ce1a2843..3b8d06db7db16 --- a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php @@ -75,11 +75,21 @@ protected function _getLayoutModel($fixtureFile) public function testRenderElement() { $layout = $this->_getLayoutModel('render.xml'); - $this->assertEmpty($layout->renderElement('nonexisting_element')); $this->assertEquals('124', $layout->renderElement('container_one')); $this->assertEquals('12', $layout->renderElement('block_one')); } + /** + * @expectedException \OutOfBoundsException + * @expectedExceptionMessage No element found with ID 'nonexisting_element' + * @magentoAppIsolation enabled + */ + public function testRenderNonExistentElementShouldThrowException() + { + $layout = $this->_getLayoutModel('render.xml'); + $this->assertEmpty($layout->renderElement('nonexisting_element')); + } + /** * Invoke getBlock() while layout is being generated * From 6de5022b7ff0c5ffb393f6ff028cf91059bbe22b Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Mon, 10 Aug 2015 14:48:07 +0300 Subject: [PATCH 25/87] MAGETWO-41078: Stabilize story --- .../Framework/View/Test/Unit/Layout/Reader/ContainerTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php index 41e99ab524fb6..67ca5239018c6 100755 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php @@ -107,6 +107,7 @@ public function testProcess( /** * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function processDataProvider() { @@ -202,7 +203,7 @@ public function processDataProvider() 'referenceContainerDisplayFalse' => [ 'elementCurrent' => $this->getElement( '', + . ' display="true"/>', 'referenceContainer' ), 'containerName' => 'reference', From 07370fd5d6846ba2486c2ee53ea73c33b1fd4760 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Mon, 10 Aug 2015 15:33:02 +0300 Subject: [PATCH 26/87] MAGETWO-40723: 'All store view' option is absent in Store View select for Cms pages and blocks - Method generateCurrentOptions updated; - Constructor removed from Cms Options; --- .../Component/Listing/Column/Cms/Options.php | 18 +------------- .../Listing/Column/Store/Options.php | 24 ++++++++----------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php index cbdbc56e30ea2..96cd0c6de6321 100644 --- a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php @@ -19,15 +19,6 @@ class Options extends StoreOptions */ const ALL_STORE_VIEWS = '0'; - /** - * @param SystemStore $systemStore - * @param Escaper $escaper - */ - public function __construct(SystemStore $systemStore, Escaper $escaper) - { - parent::__construct($systemStore, $escaper); - } - /** * Get options * @@ -35,17 +26,10 @@ public function __construct(SystemStore $systemStore, Escaper $escaper) */ public function toOptionArray() { - if ($this->options !== null) { - return $this->options; - } - $websiteCollection = $this->systemStore->getWebsiteCollection(); - $groupCollection = $this->systemStore->getGroupCollection(); - $storeCollection = $this->systemStore->getStoreCollection(); - $this->currentOptions['All Store Views']['label'] = __('All Store Views'); $this->currentOptions['All Store Views']['value'] = self::ALL_STORE_VIEWS; - $this->generateCurrentOptions($websiteCollection, $groupCollection, $storeCollection); + $this->generateCurrentOptions(); $this->options = array_values($this->currentOptions); diff --git a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php index e83a5951f55ac..49d34f6160e96 100644 --- a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php +++ b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php @@ -36,7 +36,7 @@ class Options implements OptionSourceInterface /** * @var array */ - protected $currentOptions; + protected $currentOptions = []; /** * Constructor @@ -57,14 +57,7 @@ public function __construct(SystemStore $systemStore, Escaper $escaper) */ public function toOptionArray() { - if ($this->options !== null) { - return $this->options; - } - $websiteCollection = $this->systemStore->getWebsiteCollection(); - $groupCollection = $this->systemStore->getGroupCollection(); - $storeCollection = $this->systemStore->getStoreCollection(); - - $this->generateCurrentOptions($websiteCollection, $groupCollection, $storeCollection); + $this->generateCurrentOptions(); $this->options = array_values($this->currentOptions); @@ -74,13 +67,16 @@ public function toOptionArray() /** * Generate current options * - * @param array $websiteCollection - * @param array $groupCollection - * @param array $storeCollection - * @return void + * @return array|void */ - protected function generateCurrentOptions(array $websiteCollection, array $groupCollection, array $storeCollection) + protected function generateCurrentOptions() { + if ($this->options !== null) { + return $this->options; + } + $websiteCollection = $this->systemStore->getWebsiteCollection(); + $groupCollection = $this->systemStore->getGroupCollection(); + $storeCollection = $this->systemStore->getStoreCollection(); /** @var \Magento\Store\Model\Website $website */ foreach ($websiteCollection as $website) { $groups = []; From 43bbc817478bb2078d7d4402476ad862fe2fe8d1 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Mon, 10 Aug 2015 15:35:03 +0300 Subject: [PATCH 27/87] MAGETWO-40723: 'All store view' option is absent in Store View select for Cms pages and blocks - Class Escaper removed from usage; --- app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php index 96cd0c6de6321..3607a48810073 100644 --- a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php @@ -5,7 +5,6 @@ */ namespace Magento\Cms\Ui\Component\Listing\Column\Cms; -use Magento\Framework\Escaper; use Magento\Store\Model\System\Store as SystemStore; use Magento\Store\Ui\Component\Listing\Column\Store\Options as StoreOptions; From f4a7dc5ff555b3b0e598db9a37e61578b089bee8 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Mon, 10 Aug 2015 15:42:30 +0300 Subject: [PATCH 28/87] MAGETWO-40723: 'All store view' option is absent in Store View select for Cms pages and blocks - System Store class removed from usage; --- app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php index 3607a48810073..65fca754e72dc 100644 --- a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php @@ -5,7 +5,6 @@ */ namespace Magento\Cms\Ui\Component\Listing\Column\Cms; -use Magento\Store\Model\System\Store as SystemStore; use Magento\Store\Ui\Component\Listing\Column\Store\Options as StoreOptions; /** From 387dfef69152d9053f8bf16bb8ecf86ed0032c11 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Mon, 10 Aug 2015 16:35:51 +0300 Subject: [PATCH 29/87] MAGETWO-40723: 'All store view' option is absent in Store View select for Cms pages and blocks - Method generateCurrentOptions updated; --- .../Cms/Ui/Component/Listing/Column/Cms/Options.php | 4 ++++ .../Store/Ui/Component/Listing/Column/Store/Options.php | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php index 65fca754e72dc..f94376305c255 100644 --- a/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/Cms/Options.php @@ -24,6 +24,10 @@ class Options extends StoreOptions */ public function toOptionArray() { + if ($this->options !== null) { + return $this->options; + } + $this->currentOptions['All Store Views']['label'] = __('All Store Views'); $this->currentOptions['All Store Views']['value'] = self::ALL_STORE_VIEWS; diff --git a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php index 49d34f6160e96..d55c1f620f007 100644 --- a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php +++ b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php @@ -57,6 +57,10 @@ public function __construct(SystemStore $systemStore, Escaper $escaper) */ public function toOptionArray() { + if ($this->options !== null) { + return $this->options; + } + $this->generateCurrentOptions(); $this->options = array_values($this->currentOptions); @@ -67,13 +71,10 @@ public function toOptionArray() /** * Generate current options * - * @return array|void + * @return void */ protected function generateCurrentOptions() { - if ($this->options !== null) { - return $this->options; - } $websiteCollection = $this->systemStore->getWebsiteCollection(); $groupCollection = $this->systemStore->getGroupCollection(); $storeCollection = $this->systemStore->getStoreCollection(); From be20c645e7924648411706b138f319319532fdce Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Tue, 11 Aug 2015 15:37:56 +0300 Subject: [PATCH 30/87] MAGETWO-40683: [Github] Wrong Home CMS Page --- app/code/Magento/CmsUrlRewrite/etc/{adminhtml => }/events.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/code/Magento/CmsUrlRewrite/etc/{adminhtml => }/events.xml (79%) diff --git a/app/code/Magento/CmsUrlRewrite/etc/adminhtml/events.xml b/app/code/Magento/CmsUrlRewrite/etc/events.xml similarity index 79% rename from app/code/Magento/CmsUrlRewrite/etc/adminhtml/events.xml rename to app/code/Magento/CmsUrlRewrite/etc/events.xml index 5403719ab7318..55e330c5e05a3 100644 --- a/app/code/Magento/CmsUrlRewrite/etc/adminhtml/events.xml +++ b/app/code/Magento/CmsUrlRewrite/etc/events.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> - + From b222bb4a7cb48f291ac9d28a7e4465696da36ce9 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Tue, 11 Aug 2015 18:01:24 +0300 Subject: [PATCH 31/87] MAGETWO-41076: Get rid of remove directive --- .../catalog_product_attribute_edit_popup.xml | 2 +- ...catalog_product_view_type_configurable.xml | 2 +- app/etc/di.xml | 5 -- .../Framework/View/Layout/Reader/Remove.php | 42 ----------- .../Test/Unit/Layout/Reader/RemoveTest.php | 74 ------------------- 5 files changed, 2 insertions(+), 123 deletions(-) mode change 100644 => 100755 app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml mode change 100644 => 100755 app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml mode change 100644 => 100755 app/etc/di.xml delete mode 100644 lib/internal/Magento/Framework/View/Layout/Reader/Remove.php delete mode 100644 lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/RemoveTest.php diff --git a/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml b/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml old mode 100644 new mode 100755 index bac339489c98f..2f803ced7e5cb --- a/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml +++ b/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> - + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml old mode 100644 new mode 100755 index 71bdc2ce6783c..278270a42d0c8 --- a/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml @@ -10,7 +10,7 @@ - + diff --git a/app/etc/di.xml b/app/etc/di.xml old mode 100644 new mode 100755 index 7b8aea5446305..742d3d0089bfd --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -424,7 +424,6 @@ Magento\Framework\View\Layout\Reader\Container Magento\Framework\View\Layout\Reader\Block Magento\Framework\View\Layout\Reader\Move - Magento\Framework\View\Layout\Reader\Remove Magento\Framework\View\Layout\Reader\UiComponent @@ -448,7 +447,6 @@ Magento\Framework\View\Layout\Reader\Container Magento\Framework\View\Layout\Reader\Block Magento\Framework\View\Layout\Reader\Move - Magento\Framework\View\Layout\Reader\Remove Magento\Framework\View\Layout\Reader\UiComponent @@ -467,7 +465,6 @@ Magento\Framework\View\Layout\Reader\Container Magento\Framework\View\Layout\Reader\Block Magento\Framework\View\Layout\Reader\Move - Magento\Framework\View\Layout\Reader\Remove Magento\Framework\View\Layout\Reader\UiComponent @@ -484,7 +481,6 @@ Magento\Framework\View\Layout\Reader\Container Magento\Framework\View\Layout\Reader\Block Magento\Framework\View\Layout\Reader\Move - Magento\Framework\View\Layout\Reader\Remove Magento\Framework\View\Layout\Reader\UiComponent @@ -926,7 +922,6 @@ Magento\Framework\View\Layout\Reader\Container Magento\Framework\View\Layout\Reader\Move - Magento\Framework\View\Layout\Reader\Remove diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Remove.php b/lib/internal/Magento/Framework/View/Layout/Reader/Remove.php deleted file mode 100644 index 6ae075a6c0ac2..0000000000000 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Remove.php +++ /dev/null @@ -1,42 +0,0 @@ -getScheduledStructure(); - $scheduledStructure->setElementToRemoveList((string)$currentElement->getAttribute('name')); - return $this; - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/RemoveTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/RemoveTest.php deleted file mode 100644 index 0c0588ecd5430..0000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/RemoveTest.php +++ /dev/null @@ -1,74 +0,0 @@ -context = $this->getMockBuilder('Magento\Framework\View\Layout\Reader\Context') - ->disableOriginalConstructor() - ->getMock(); - $this->scheduledStructure = $this->getMockBuilder('Magento\Framework\View\Layout\ScheduledStructure') - ->disableOriginalConstructor()->setMethods(['setElementToRemoveList', '__wakeup']) - ->getMock(); - $this->model = new Remove(); - } - - public function testGetSupportedNodes() - { - $data[] = \Magento\Framework\View\Layout\Reader\Remove::TYPE_REMOVE; - $this->assertEquals($data, $this->model->getSupportedNodes()); - } - - /** - * @dataProvider processDataProvider - */ - public function testProcess($xml) - { - $this->element = new \Magento\Framework\View\Layout\Element($xml); - $this->context->expects($this->any()) - ->method('getScheduledStructure') - ->will($this->returnValue($this->scheduledStructure)); - $this->scheduledStructure->expects($this->once())->method('setElementToRemoveList')->with('header'); - $this->model->interpret($this->context, $this->element, $this->element); - } - - public function processDataProvider() - { - return [ - [ - '', - ] - ]; - } -} From 430c314d882e24e8f5b3df9f9e27883f3664f069 Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Wed, 12 Aug 2015 12:51:38 +0300 Subject: [PATCH 32/87] MAGETWO-41076: Get rid of remove directive --- .../Framework/View/Layout/_files/_layout_update.xml | 10 +++++----- .../View/_files/layout_directives_test/remove.xml | 6 +++--- .../_files/layout_directives_test/remove_broken.xml | 2 +- .../default/Magento_Core/layout_test_handle_main.xml | 10 +++++----- .../Magento/Framework/View/Layout/etc/body.xsd | 1 - .../Framework/View/Layout/etc/layout_generic.xsd | 1 - 6 files changed, 14 insertions(+), 16 deletions(-) mode change 100644 => 100755 dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml mode change 100644 => 100755 dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml mode change 100644 => 100755 dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml mode change 100644 => 100755 dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml mode change 100644 => 100755 lib/internal/Magento/Framework/View/Layout/etc/body.xsd mode change 100644 => 100755 lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml old mode 100644 new mode 100755 index 99db6b298d653..51150b0fe56c8 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml @@ -22,10 +22,10 @@ - - - - + + + + popup.phtml @@ -33,7 +33,7 @@ - + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml old mode 100644 new mode 100755 index 55b2f851bb3df..cd906df4586d2 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml @@ -9,11 +9,11 @@ - - + + - + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml old mode 100644 new mode 100755 index 1e63211f6690d..5cffdd38799cd --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml @@ -7,7 +7,7 @@ --> - + test.broken.block diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml old mode 100644 new mode 100755 index 9b59c31d03704..4e9b9587ed67a --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml @@ -7,10 +7,10 @@ --> - - - - + + + + popup.phtml @@ -18,7 +18,7 @@ - + diff --git a/lib/internal/Magento/Framework/View/Layout/etc/body.xsd b/lib/internal/Magento/Framework/View/Layout/etc/body.xsd old mode 100644 new mode 100755 index 3b187137d61fc..94922875f16a2 --- a/lib/internal/Magento/Framework/View/Layout/etc/body.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/body.xsd @@ -15,7 +15,6 @@ - diff --git a/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd b/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd old mode 100644 new mode 100755 index a9f0432bfc4be..a584c5403d9af --- a/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd @@ -15,7 +15,6 @@ - From 1f19462c6b03d37a9771d9e42e76dbab97b6350e Mon Sep 17 00:00:00 2001 From: vpaladiychuk Date: Wed, 12 Aug 2015 15:33:53 +0300 Subject: [PATCH 33/87] MAGETWO-41076: Get rid of remove directive --- .../Test/Legacy/_files/obsolete_classes.php | 1 + .../View/Test/Unit/Layout/ReaderPoolTest.php | 25 +++---------------- 2 files changed, 4 insertions(+), 22 deletions(-) mode change 100644 => 100755 dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php mode change 100644 => 100755 lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php old mode 100644 new mode 100755 index cafe3396d6509..9cbda3d9c78c4 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -3824,4 +3824,5 @@ ['Magento\Checkout\Model\Observer', 'corresponding classes in Magento\Checkout\Observer\*'], ['Magento\CurrencySymbol\Model\Observer', 'corresponding classes in Magento\CurrencySymbol\Observer\*'], ['Magento\Catalog\Model\Product\Image\View'], + ['Magento\Framework\View\Layout\Reader\Remove'], ]; diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php old mode 100644 new mode 100755 index 884b941bf6191..83a1500dd4a33 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php @@ -29,10 +29,7 @@ protected function setUp() 'Magento\Framework\View\Layout\ReaderPool', [ 'readerFactory' => $this->readerFactoryMock, - 'readers' => [ - 'move' => 'Magento\Framework\View\Layout\Reader\Move', - 'remove' => 'Magento\Framework\View\Layout\Reader\Remove', - ] + 'readers' => ['move' => 'Magento\Framework\View\Layout\Reader\Move'] ] ); } @@ -57,25 +54,9 @@ public function testInterpret() $moveReaderMock->method('getSupportedNodes') ->willReturn(['move']); - /** - * @var \Magento\Framework\View\Layout\Reader\Remove|\PHPUnit_Framework_MockObject_MockObject $removeReaderMock - */ - $removeReaderMock = $this->getMockBuilder('Magento\Framework\View\Layout\Reader\Remove') - ->disableOriginalConstructor()->getMock(); - $removeReaderMock->expects($this->exactly(2))->method('interpret') - ->with() - ->willReturn($this->returnSelf()); - $removeReaderMock->method('getSupportedNodes') - ->willReturn(['remove']); - - $this->readerFactoryMock->expects($this->exactly(2)) + $this->readerFactoryMock->expects($this->once()) ->method('create') - ->will($this->returnValueMap( - [ - ['Magento\Framework\View\Layout\Reader\Move', [], $moveReaderMock], - ['Magento\Framework\View\Layout\Reader\Remove', [], $removeReaderMock], - ] - )); + ->willReturnMap([['Magento\Framework\View\Layout\Reader\Move', [], $moveReaderMock]]); $this->pool->interpret($contextMock, $currentElement); $this->pool->interpret($contextMock, $currentElement); From 3bb7dc15d66c5d842618318540ef094b62eae449 Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 12 Aug 2015 11:48:12 -0500 Subject: [PATCH 34/87] MAGETWO-38497: Implemented Swagger REST API schema generation in Magento --- .../Api/AdminTokenServiceInterface.php | 10 +- .../Api/CustomerTokenServiceInterface.php | 4 +- app/code/Magento/Webapi/Controller/Rest.php | 107 ++- app/code/Magento/Webapi/Controller/Soap.php | 35 +- .../Webapi/Controller/Soap/Request.php | 68 -- .../Controller/Soap/Request/Handler.php | 13 +- .../Webapi/Model/AbstractSchemaGenerator.php | 149 +++ .../{Soap => }/Config/ClassReflector.php | 22 +- .../Magento/Webapi/Model/Config/Converter.php | 1 + .../Magento/Webapi/Model/Rest/Swagger.php | 108 +++ .../Webapi/Model/Rest/Swagger/Generator.php | 853 ++++++++++++++++++ .../Magento/Webapi/Model/ServiceMetadata.php | 271 ++++++ app/code/Magento/Webapi/Model/Soap/Config.php | 216 +---- app/code/Magento/Webapi/Model/Soap/Server.php | 8 +- .../Webapi/Model/Soap/Wsdl/Generator.php | 201 +---- .../Webapi/Test/Unit/Controller/RestTest.php | 136 +-- .../Controller/Soap/Request/HandlerTest.php | 14 +- .../Test/Unit/Controller/Soap/RequestTest.php | 110 --- .../Webapi/Test/Unit/Controller/SoapTest.php | 57 +- .../{Soap => }/Config/ClassReflectorTest.php | 6 +- .../Unit/Model/Rest/Swagger/GeneratorTest.php | 426 +++++++++ .../Test/Unit/Model/ServiceMetadataTest.php | 293 ++++++ .../Test/Unit/Model/Soap/ConfigTest.php | 95 +- .../Test/Unit/Model/Soap/ServerTest.php | 4 +- .../Unit/Model/Soap/Wsdl/GeneratorTest.php | 50 +- .../Service/V1/AllSoapAndRestInterface.php | 4 + .../Service/V1/Entity/AllSoapAndRest.php | 7 + .../Service/V2/AllSoapAndRestInterface.php | 4 + .../Service/V2/Entity/AllSoapAndRest.php | 9 + .../JsonGenerationFromDataObjectTest.php | 364 ++++++++ .../WsdlGenerationFromDataObjectTest.php | 8 +- .../Webapi/ServiceNameCollisionTest.php | 6 +- .../Test/Legacy/_files/obsolete_classes.php | 1 - .../Test/Unit/TypeProcessorTest.php | 5 + .../Framework/Reflection/TypeProcessor.php | 85 +- .../Magento/Framework/Webapi/Request.php | 47 + .../Webapi/Test/Unit/RequestTest.php | 52 ++ 37 files changed, 3066 insertions(+), 783 deletions(-) delete mode 100644 app/code/Magento/Webapi/Controller/Soap/Request.php create mode 100644 app/code/Magento/Webapi/Model/AbstractSchemaGenerator.php rename app/code/Magento/Webapi/Model/{Soap => }/Config/ClassReflector.php (87%) create mode 100644 app/code/Magento/Webapi/Model/Rest/Swagger.php create mode 100644 app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php create mode 100644 app/code/Magento/Webapi/Model/ServiceMetadata.php delete mode 100644 app/code/Magento/Webapi/Test/Unit/Controller/Soap/RequestTest.php rename app/code/Magento/Webapi/Test/Unit/Model/{Soap => }/Config/ClassReflectorTest.php (92%) create mode 100644 app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php create mode 100644 app/code/Magento/Webapi/Test/Unit/Model/ServiceMetadataTest.php create mode 100644 dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php create mode 100644 lib/internal/Magento/Framework/Webapi/Test/Unit/RequestTest.php diff --git a/app/code/Magento/Integration/Api/AdminTokenServiceInterface.php b/app/code/Magento/Integration/Api/AdminTokenServiceInterface.php index 3c2999851a9db..02e2c85d8b34c 100644 --- a/app/code/Magento/Integration/Api/AdminTokenServiceInterface.php +++ b/app/code/Magento/Integration/Api/AdminTokenServiceInterface.php @@ -6,10 +6,6 @@ namespace Magento\Integration\Api; -use Magento\Framework\Exception\AuthenticationException; -use Magento\Framework\Exception\InputException; -use Magento\Framework\Exception\LocalizedException; - /** * Interface providing token generation for Admins * @@ -23,9 +19,9 @@ interface AdminTokenServiceInterface * @param string $username * @param string $password * @return string Token created - * @throws InputException For invalid input - * @throws AuthenticationException - * @throws LocalizedException + * @throws \Magento\Framework\Exception\InputException For invalid input + * @throws \Magento\Framework\Exception\AuthenticationException + * @throws \Magento\Framework\Exception\LocalizedException */ public function createAdminAccessToken($username, $password); diff --git a/app/code/Magento/Integration/Api/CustomerTokenServiceInterface.php b/app/code/Magento/Integration/Api/CustomerTokenServiceInterface.php index 245d39bc4a63e..218a6f0d4acba 100644 --- a/app/code/Magento/Integration/Api/CustomerTokenServiceInterface.php +++ b/app/code/Magento/Integration/Api/CustomerTokenServiceInterface.php @@ -6,8 +6,6 @@ namespace Magento\Integration\Api; -use Magento\Framework\Exception\AuthenticationException; - /** * Interface providing token generation for Customers * @@ -21,7 +19,7 @@ interface CustomerTokenServiceInterface * @param string $username * @param string $password * @return string Token created - * @throws AuthenticationException + * @throws \Magento\Framework\Exception\AuthenticationException */ public function createCustomerAccessToken($username, $password); diff --git a/app/code/Magento/Webapi/Controller/Rest.php b/app/code/Magento/Webapi/Controller/Rest.php index dc68d6cd3b67d..f850dcdc495aa 100644 --- a/app/code/Magento/Webapi/Controller/Rest.php +++ b/app/code/Magento/Webapi/Controller/Rest.php @@ -23,9 +23,15 @@ * TODO: Consider warnings suppression removal * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class Rest implements \Magento\Framework\App\FrontControllerInterface { + /** + * schema request key + */ + const REQUEST_PARAM_SCHEMA = 'schema'; + /** * @var Router */ @@ -101,6 +107,11 @@ class Rest implements \Magento\Framework\App\FrontControllerInterface */ protected $serviceOutputProcessor; + /** + * @var \Magento\Webapi\Model\Rest\Swagger\Generator + */ + protected $swaggerGenerator; + /** * Initialize dependencies * @@ -117,6 +128,7 @@ class Rest implements \Magento\Framework\App\FrontControllerInterface * @param FieldsFilter $fieldsFilter * @param ParamsOverrider $paramsOverrider * @param ServiceOutputProcessor $serviceOutputProcessor + * @param \Magento\Webapi\Model\Rest\Swagger\Generator $swaggerGenerator, * * TODO: Consider removal of warning suppression * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -134,7 +146,8 @@ public function __construct( \Magento\Framework\App\AreaList $areaList, FieldsFilter $fieldsFilter, ParamsOverrider $paramsOverrider, - ServiceOutputProcessor $serviceOutputProcessor + ServiceOutputProcessor $serviceOutputProcessor, + \Magento\Webapi\Model\Rest\Swagger\Generator $swaggerGenerator ) { $this->_router = $router; $this->_request = $request; @@ -149,6 +162,7 @@ public function __construct( $this->fieldsFilter = $fieldsFilter; $this->paramsOverrider = $paramsOverrider; $this->serviceOutputProcessor = $serviceOutputProcessor; + $this->swaggerGenerator = $swaggerGenerator; } /** @@ -164,29 +178,11 @@ public function dispatch(\Magento\Framework\App\RequestInterface $request) $this->areaList->getArea($this->_appState->getAreaCode()) ->load(\Magento\Framework\App\Area::PART_TRANSLATE); try { - $this->checkPermissions(); - $route = $this->getCurrentRoute(); - if ($route->isSecure() && !$this->_request->isSecure()) { - throw new \Magento\Framework\Webapi\Exception(__('Operation allowed only in HTTPS')); - } - /** @var array $inputData */ - $inputData = $this->_request->getRequestData(); - $serviceMethodName = $route->getServiceMethod(); - $serviceClassName = $route->getServiceClass(); - $inputData = $this->paramsOverrider->override($inputData, $route->getParameters()); - $inputParams = $this->serviceInputProcessor->process($serviceClassName, $serviceMethodName, $inputData); - $service = $this->_objectManager->get($serviceClassName); - /** @var \Magento\Framework\Api\AbstractExtensibleObject $outputData */ - $outputData = call_user_func_array([$service, $serviceMethodName], $inputParams); - $outputData = $this->serviceOutputProcessor->process( - $outputData, - $serviceClassName, - $serviceMethodName - ); - if ($this->_request->getParam(FieldsFilter::FILTER_PARAMETER) && is_array($outputData)) { - $outputData = $this->fieldsFilter->filter($outputData); + if ($this->isSchemaRequest()) { + $this->processSchemaRequest(); + } else { + $this->processApiRequest(); } - $this->_response->prepareResponse($outputData); } catch (\Exception $e) { $maskedException = $this->_errorProcessor->maskException($e); $this->_response->setException($maskedException); @@ -194,6 +190,16 @@ public function dispatch(\Magento\Framework\App\RequestInterface $request) return $this->_response; } + /** + * Check if current request is schema request. + * + * @return bool + */ + protected function isSchemaRequest() + { + return $this->_request->getParam(self::REQUEST_PARAM_SCHEMA) !== null; + } + /** * Retrieve current route. * @@ -239,4 +245,59 @@ protected function isAllowed($aclResources) } return true; } + + /** + * Execute schema request + * + * @return void + */ + protected function processSchemaRequest() + { + $requestedServices = $this->_request->getRequestedServices(); + $requestedServices = $requestedServices == 'all' + ? array_keys($this->swaggerGenerator->getListOfServices()) + : $requestedServices; + $responseBody = $this->swaggerGenerator->generate( + $requestedServices, + $this->_request->getScheme(), + $this->_request->getHttpHost(), + $this->_request->getRequestUri() + ); + $this->_response->setBody($responseBody)->setHeader('Content-Type', 'application/json'); + } + + /** + * Execute API request + * + * @return void + * @throws AuthorizationException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Webapi\Exception + */ + protected function processApiRequest() + { + $this->checkPermissions(); + $route = $this->getCurrentRoute(); + if ($route->isSecure() && !$this->_request->isSecure()) { + throw new \Magento\Framework\Webapi\Exception(__('Operation allowed only in HTTPS')); + } + /** @var array $inputData */ + $inputData = $this->_request->getRequestData(); + $serviceMethodName = $route->getServiceMethod(); + $serviceClassName = $route->getServiceClass(); + $inputData = $this->paramsOverrider->override($inputData, $route->getParameters()); + $inputParams = $this->serviceInputProcessor->process($serviceClassName, $serviceMethodName, $inputData); + $service = $this->_objectManager->get($serviceClassName); + /** @var \Magento\Framework\Api\AbstractExtensibleObject $outputData */ + $outputData = call_user_func_array([$service, $serviceMethodName], $inputParams); + $outputData = $this->serviceOutputProcessor->process( + $outputData, + $serviceClassName, + $serviceMethodName + ); + if ($this->_request->getParam(FieldsFilter::FILTER_PARAMETER) && is_array($outputData)) { + $outputData = $this->fieldsFilter->filter($outputData); + } + $this->_response->prepareResponse($outputData); + } } diff --git a/app/code/Magento/Webapi/Controller/Soap.php b/app/code/Magento/Webapi/Controller/Soap.php index cc040657fd435..bb64d7c03c70e 100644 --- a/app/code/Magento/Webapi/Controller/Soap.php +++ b/app/code/Magento/Webapi/Controller/Soap.php @@ -9,6 +9,7 @@ use Magento\Framework\Exception\AuthorizationException; use Magento\Framework\Webapi\ErrorProcessor; +use Magento\Framework\Webapi\Request; use Magento\Framework\Webapi\Response; /** @@ -39,7 +40,7 @@ class Soap implements \Magento\Framework\App\FrontControllerInterface protected $_wsdlGenerator; /** - * @var \Magento\Webapi\Controller\Soap\Request + * @var Request */ protected $_request; @@ -74,7 +75,7 @@ class Soap implements \Magento\Framework\App\FrontControllerInterface protected $rendererFactory; /** - * @param Soap\Request $request + * @param Request $request * @param Response $response * @param \Magento\Webapi\Model\Soap\Wsdl\Generator $wsdlGenerator * @param \Magento\Webapi\Model\Soap\Server $soapServer @@ -87,7 +88,7 @@ class Soap implements \Magento\Framework\App\FrontControllerInterface * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Webapi\Controller\Soap\Request $request, + Request $request, \Magento\Framework\Webapi\Response $response, \Magento\Webapi\Model\Soap\Wsdl\Generator $wsdlGenerator, \Magento\Webapi\Model\Soap\Server $soapServer, @@ -123,8 +124,11 @@ public function dispatch(\Magento\Framework\App\RequestInterface $request) $this->areaList->getArea($this->_appState->getAreaCode())->load(\Magento\Framework\App\Area::PART_TRANSLATE); try { if ($this->_isWsdlRequest()) { + $this->validateWsdlRequest(); $responseBody = $this->_wsdlGenerator->generate( $this->_request->getRequestedServices(), + $this->_request->getScheme(), + $this->_request->getHttpHost(), $this->_soapServer->generateUri() ); $this->_setResponseContentType(self::CONTENT_TYPE_WSDL_REQUEST); @@ -246,4 +250,29 @@ protected function _setResponseBody($responseBody) ); return $this; } + + /** + * Validate wsdl request + * + * @return void + * @throws \Magento\Framework\Webapi\Exception + */ + protected function validateWsdlRequest() + { + $wsdlParam = \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL; + $servicesParam = Request::REQUEST_PARAM_SERVICES; + $requestParams = array_keys($this->_request->getParams()); + $allowedParams = [$wsdlParam, $servicesParam]; + $notAllowedParameters = array_diff($requestParams, $allowedParams); + if (count($notAllowedParameters)) { + $notAllowed = implode(', ', $notAllowedParameters); + $message = __( + 'Not allowed parameters: %1. Please use only %2 and %3.', + $notAllowed, + $wsdlParam, + $servicesParam + ); + throw new \Magento\Framework\Webapi\Exception($message); + } + } } diff --git a/app/code/Magento/Webapi/Controller/Soap/Request.php b/app/code/Magento/Webapi/Controller/Soap/Request.php deleted file mode 100644 index 331f9090a62bd..0000000000000 --- a/app/code/Magento/Webapi/Controller/Soap/Request.php +++ /dev/null @@ -1,68 +0,0 @@ -getParams()); - $allowedParams = [$wsdlParam, $servicesParam]; - $notAllowedParameters = array_diff($requestParams, $allowedParams); - if (count($notAllowedParameters)) { - $notAllowed = implode(', ', $notAllowedParameters); - $message = __( - 'Not allowed parameters: %1. Please use only %2 and %3.', - $notAllowed, - $wsdlParam, - $servicesParam - ); - throw new \Magento\Framework\Webapi\Exception($message); - } - - $param = $this->getParam($servicesParam); - return $this->_convertRequestParamToServiceArray($param); - } - - /** - * Extract the resources query param value and return associative array of the form 'resource' => 'version' - * - * @param string $param eg
 testModule1AllSoapAndRestV1,testModule2AllSoapNoRestV1 
- * @return array
 eg array (
-     *      'testModule1AllSoapAndRest' => 'V1',
-     *       'testModule2AllSoapNoRest' => 'V1',
-     *      )
- * @throws \Magento\Framework\Webapi\Exception - */ - protected function _convertRequestParamToServiceArray($param) - { - $serviceSeparator = ','; - $serviceVerPattern = "[a-zA-Z\d]*V[\d]+"; - $regexp = "/^({$serviceVerPattern})([{$serviceSeparator}]{$serviceVerPattern})*\$/"; - //Check if the $param is of valid format - if (empty($param) || !preg_match($regexp, $param)) { - $message = __('Incorrect format of WSDL request URI or Requested services are missing.'); - throw new \Magento\Framework\Webapi\Exception($message); - } - //Split the $param string to create an array of 'service' => 'version' - $serviceVersionArray = explode($serviceSeparator, $param); - $serviceArray = []; - foreach ($serviceVersionArray as $service) { - $serviceArray[] = $service; - } - return $serviceArray; - } -} diff --git a/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php b/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php index ec73bd7236c10..66ea4fa9b2992 100644 --- a/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php +++ b/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php @@ -12,10 +12,11 @@ use Magento\Framework\Exception\AuthorizationException; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Webapi\ServiceInputProcessor; -use Magento\Webapi\Controller\Soap\Request as SoapRequest; +use Magento\Framework\Webapi\Request as SoapRequest; use Magento\Framework\Webapi\Exception as WebapiException; use Magento\Webapi\Model\Soap\Config as SoapConfig; use Magento\Framework\Reflection\MethodsMap; +use Magento\Webapi\Model\ServiceMetadata; /** * Handler of requests to SOAP server. @@ -98,16 +99,16 @@ public function __call($operation, $arguments) { $requestedServices = $this->_request->getRequestedServices(); $serviceMethodInfo = $this->_apiConfig->getServiceMethodInfo($operation, $requestedServices); - $serviceClass = $serviceMethodInfo[SoapConfig::KEY_CLASS]; - $serviceMethod = $serviceMethodInfo[SoapConfig::KEY_METHOD]; + $serviceClass = $serviceMethodInfo[ServiceMetadata::KEY_CLASS]; + $serviceMethod = $serviceMethodInfo[ServiceMetadata::KEY_METHOD]; // check if the operation is a secure operation & whether the request was made in HTTPS - if ($serviceMethodInfo[SoapConfig::KEY_IS_SECURE] && !$this->_request->isSecure()) { + if ($serviceMethodInfo[ServiceMetadata::KEY_IS_SECURE] && !$this->_request->isSecure()) { throw new WebapiException(__("Operation allowed only in HTTPS")); } $isAllowed = false; - foreach ($serviceMethodInfo[SoapConfig::KEY_ACL_RESOURCES] as $resource) { + foreach ($serviceMethodInfo[ServiceMetadata::KEY_ACL_RESOURCES] as $resource) { if ($this->_authorization->isAllowed($resource)) { $isAllowed = true; break; @@ -118,7 +119,7 @@ public function __call($operation, $arguments) throw new AuthorizationException( __( AuthorizationException::NOT_AUTHORIZED, - ['resources' => implode(', ', $serviceMethodInfo[SoapConfig::KEY_ACL_RESOURCES])] + ['resources' => implode(', ', $serviceMethodInfo[ServiceMetadata::KEY_ACL_RESOURCES])] ) ); } diff --git a/app/code/Magento/Webapi/Model/AbstractSchemaGenerator.php b/app/code/Magento/Webapi/Model/AbstractSchemaGenerator.php new file mode 100644 index 0000000000000..24534bce281e2 --- /dev/null +++ b/app/code/Magento/Webapi/Model/AbstractSchemaGenerator.php @@ -0,0 +1,149 @@ +cache = $cache; + $this->typeProcessor = $typeProcessor; + $this->storeManager = $storeManager; + $this->customAttributeTypeLocator = $customAttributeTypeLocator; + $this->serviceMetadata = $serviceMetadata; + } + + /** + * Retrieve an array of services + * + * @return array + */ + public function getListOfServices() + { + return $this->serviceMetadata->getServicesConfig(); + } + + /** + * Generate schema based on requested services (uses cache) + * + * @param array $requestedServices + * @param string $requestScheme + * @param string $requestHost + * @param string $endPointUrl + * @return string + */ + public function generate($requestedServices, $requestScheme, $requestHost, $endPointUrl) + { + /** Sort requested services by names to prevent caching of the same schema file more than once. */ + ksort($requestedServices); + $currentStore = $this->storeManager->getStore(); + $cacheId = get_class($this). hash('md5', serialize($requestedServices) . $currentStore->getCode()); + $cachedSchemaContent = $this->cache->load($cacheId); + if ($cachedSchemaContent !== false) { + return $cachedSchemaContent; + } + $requestedServiceMetadata = []; + foreach ($requestedServices as $serviceName) { + $requestedServiceMetadata[$serviceName] = $this->getServiceMetadata($serviceName); + } + + $this->collectCallInfo($requestedServiceMetadata); + $schemaContent = $this->generateSchema($requestedServiceMetadata, $requestScheme, $requestHost, $endPointUrl); + $this->cache->save($schemaContent, $cacheId, [\Magento\Framework\App\Cache\Type\Webapi::CACHE_TAG]); + + return $schemaContent; + } + + /** + * Generate schema based on requested services' metadata. + * + * @param array $requestedServiceMetadata + * @param string $requestScheme + * @param string $requestHost + * @param string $requestUri + * @return string + */ + abstract protected function generateSchema($requestedServiceMetadata, $requestScheme, $requestHost, $requestUri); + + /** + * Get service metadata + * + * @param string $serviceName + * @return string[] + */ + abstract protected function getServiceMetadata($serviceName); + + /** + * Get name of complexType for message element. + * + * @param string $messageName + * @return string + */ + public function getElementComplexTypeName($messageName) + { + return ucfirst($messageName); + } + + /** + * Collect data about complex types call info. + * + * Walks through all requested services and checks all methods 'in' and 'out' parameters. + * + * @param array $requestedServiceMetadata + * @return void + */ + protected function collectCallInfo($requestedServiceMetadata) + { + foreach ($requestedServiceMetadata as $serviceName => $serviceData) { + foreach ($serviceData['methods'] as $methodName => $methodData) { + $this->typeProcessor->processInterfaceCallInfo($methodData['interface'], $serviceName, $methodName); + } + } + } +} diff --git a/app/code/Magento/Webapi/Model/Soap/Config/ClassReflector.php b/app/code/Magento/Webapi/Model/Config/ClassReflector.php similarity index 87% rename from app/code/Magento/Webapi/Model/Soap/Config/ClassReflector.php rename to app/code/Magento/Webapi/Model/Config/ClassReflector.php index 1936cb89cae90..2bd5ac75d0fc7 100644 --- a/app/code/Magento/Webapi/Model/Soap/Config/ClassReflector.php +++ b/app/code/Magento/Webapi/Model/Config/ClassReflector.php @@ -3,7 +3,7 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Webapi\Model\Soap\Config; +namespace Magento\Webapi\Model\Config; use Zend\Code\Reflection\MethodReflection; @@ -105,6 +105,10 @@ public function extractMethodData(\Zend\Code\Reflection\MethodReflection $method 'required' => true, ]; } + $exceptions = $this->_typeProcessor->getExceptions($method); + if (!empty($exceptions)) { + $methodData['interface']['out']['throws'] = $exceptions; + } return $methodData; } @@ -131,4 +135,20 @@ protected function extractMethodDescription(\Zend\Code\Reflection\MethodReflecti } return $this->_typeProcessor->getDescription($docBlock); } + + /** + * Retrieve class full documentation description. + * + * @param string $className + * @return string + */ + public function extractClassDescription($className) + { + $classReflection = new \Zend\Code\Reflection\ClassReflection($className); + $docBlock = $classReflection->getDocBlock(); + if (!$docBlock) { + return ''; + } + return $this->_typeProcessor->getDescription($docBlock); + } } diff --git a/app/code/Magento/Webapi/Model/Config/Converter.php b/app/code/Magento/Webapi/Model/Config/Converter.php index c9b557f099fa5..e7e55abef5d00 100644 --- a/app/code/Magento/Webapi/Model/Config/Converter.php +++ b/app/code/Magento/Webapi/Model/Config/Converter.php @@ -27,6 +27,7 @@ class Converter implements \Magento\Framework\Config\ConverterInterface const KEY_SOURCE = 'source'; const KEY_METHOD = 'method'; const KEY_METHODS = 'methods'; + const KEY_DESCRIPTION = 'description'; /**#@-*/ /** diff --git a/app/code/Magento/Webapi/Model/Rest/Swagger.php b/app/code/Magento/Webapi/Model/Rest/Swagger.php new file mode 100644 index 0000000000000..de87e13b79db0 --- /dev/null +++ b/app/code/Magento/Webapi/Model/Rest/Swagger.php @@ -0,0 +1,108 @@ + self::SWAGGER_VERSION, + 'info' => [ + 'version' => '', + 'title' => '', + ], + ]; + parent::__construct($data); + } + + /** + * Add a path + * + * @param string $path + * @param string $httpOperation + * @param string[] $pathInfo + * @return $this + */ + public function addPath($path, $httpOperation, $pathInfo) + { + $this->_data['paths'][$path][$httpOperation] = $pathInfo; + return $this; + } + + /** + * Add a tag + * + * @param string $tagInfo + * @return $this + */ + public function addTag($tagInfo) + { + $this->_data['tags'][] = $tagInfo; + return $this; + } + + /** + * Get JSON encoded REST schema + * + * @return string + */ + public function toSchema() + { + return json_encode($this->toArray(), JSON_UNESCAPED_SLASHES); + } + + /** + * Add Info section data + * + * @param array $info + * @return $this + */ + public function setInfo($info) + { + if (! is_array($info)) { + return $this; + } + if (isset($info['title'])) { + $this->_data['info']['title'] = $info['title']; + } + if (isset($info['version'])) { + $this->_data['info']['version'] = $info['version']; + } + return $this; + } + + /** + * Set base path + * + * @param string $basePath + * @return $this + */ + public function setBasePath($basePath) + { + $this->_data['basePath'] = $basePath; + return $this; + } +} diff --git a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php new file mode 100644 index 0000000000000..56c83a24dc12f --- /dev/null +++ b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php @@ -0,0 +1,853 @@ + tag information, + * class2Name => tag information, + * ... + * ] + * + * @var array + */ + protected $tags = []; + + /** + * A map of definition + * + * example: + * [ + * definitionName1 => definition, + * definitionName2 => definition, + * ... + * ] + * Note: definitionName is converted from class name + * @var array + */ + protected $definitions = []; + + /** + * List of simple parameter types not to be processed by the definitions generator + * Contains mapping to the internal swagger simple types + * + * @var string[] + */ + protected $simpleTypeList = [ + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'int' => 'integer', + 'integer' => 'integer', + 'double' => 'number', + 'float' => 'number', + 'number' => 'number', + 'string' => 'string', + TypeProcessor::ANY_TYPE => 'string', + TypeProcessor::NORMALIZED_ANY_TYPE => 'string', + ]; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\App\Cache\Type\Webapi $cache + * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param \Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface $customAttributeTypeLocator + * @param \Magento\Webapi\Model\ServiceMetadata $serviceMetadata + * @param SwaggerFactory $swaggerFactory + * @param \Magento\Framework\App\ProductMetadataInterface $productMetadata + */ + public function __construct( + \Magento\Framework\App\Cache\Type\Webapi $cache, + \Magento\Framework\Reflection\TypeProcessor $typeProcessor, + \Magento\Store\Model\StoreManagerInterface $storeManager, + \Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface $customAttributeTypeLocator, + \Magento\Webapi\Model\ServiceMetadata $serviceMetadata, + SwaggerFactory $swaggerFactory, + ProductMetadataInterface $productMetadata + ) { + $this->swaggerFactory = $swaggerFactory; + $this->productMetadata = $productMetadata; + parent::__construct($cache, $typeProcessor, $storeManager, $customAttributeTypeLocator, $serviceMetadata); + } + + /** + * {@inheritdoc} + */ + protected function generateSchema($requestedServiceMetadata, $requestScheme, $requestHost, $endPointUrl) + { + /** @var Swagger $swagger */ + $swagger = $this->swaggerFactory->create(); + + $swagger->setInfo($this->getGeneralInfo()); + + $this->addCustomAttributeTypes(); + $swagger->setHost($requestHost); + $swagger->setBasePath(strstr(str_replace($requestScheme . $requestHost, '', $endPointUrl), '?', true)); + $swagger->setSchemes([$requestScheme]); + + foreach ($requestedServiceMetadata as $serviceName => $serviceData) { + if (!isset($this->tags[$serviceName])) { + $this->tags[$serviceName] = $this->generateTagInfo($serviceName, $serviceData); + $swagger->addTag($this->tags[$serviceName]); + } + foreach ($serviceData[Converter::KEY_ROUTES] as $uri => $httpMethods) { + $uri = $this->convertPathParams($uri); + foreach ($httpMethods as $httpOperation => $httpMethodData) { + $httpOperation = strtolower($httpOperation); + $phpMethodData = $serviceData[Converter::KEY_METHODS][$httpMethodData[Converter::KEY_METHOD]]; + $httpMethodData[Converter::KEY_METHOD] = $phpMethodData; + $httpMethodData['uri'] = $uri; + $httpMethodData['httpOperation'] = $httpOperation; + $swagger->addPath( + $this->convertPathParams($uri), + $httpOperation, + $this->generatePathInfo($httpOperation, $httpMethodData, $serviceName) + ); + } + } + } + $swagger->setDefinitions($this->getDefinitions()); + + return $swagger->toSchema(); + } + + /** + * Get the 'Info' section data + * + * @return string[] + */ + protected function getGeneralInfo() + { + $versionParts = explode('.', $this->productMetadata->getVersion()); + if (!isset($versionParts[0]) || !isset($versionParts[1])) { + return []; // Major and minor version are not set - return empty response + } + $majorMinorVersion = $versionParts[0] . '.' . $versionParts[1]; + + return [ + 'version' => $majorMinorVersion, + 'title' => $this->productMetadata->getName() . ' ' . $this->productMetadata->getEdition(), + ]; + } + + /** + * Generate path info based on method data + * + * @param string $methodName + * @param array $httpMethodData + * @param string $tagName + * @return array + */ + protected function generatePathInfo($methodName, $httpMethodData, $tagName) + { + $methodData = $httpMethodData[Converter::KEY_METHOD]; + $pathInfo = [ + 'tags' => [$tagName], + 'description' => $methodData['documentation'], + 'operationId' => $this->typeProcessor->getOperationName($tagName, $methodData[Converter::KEY_METHOD]) . + ucfirst($methodName) + ]; + + $parameters = $this->generateMethodParameters($httpMethodData); + if ($parameters) { + $pathInfo['parameters'] = $parameters; + } + $pathInfo['responses'] = $this->generateMethodResponses($methodData); + + return $pathInfo; + } + + /** + * Generate response based on method data + * + * @param array $methodData + * @return array + */ + protected function generateMethodResponses($methodData) + { + $responses = []; + + if (isset($methodData['interface']['out']['parameters']) + && is_array($methodData['interface']['out']['parameters']) + ) { + $parameters = $methodData['interface']['out']['parameters']; + $responses = $this->generateMethodSuccessResponse($parameters, $responses); + } + + /** Handle authorization exceptions that may not be documented */ + if (isset($methodData['resources'])) { + foreach ($methodData['resources'] as $resourceName) { + if ($resourceName !== 'anonymous') { + $responses[WebapiException::HTTP_UNAUTHORIZED]['description'] = self::UNAUTHORIZED_DESCRIPTION; + $responses[WebapiException::HTTP_UNAUTHORIZED]['schema']['$ref'] = self::ERROR_SCHEMA; + break; + } + } + } + + if (isset($methodData['interface']['out']['throws']) + && is_array($methodData['interface']['out']['throws']) + ) { + foreach ($methodData['interface']['out']['throws'] as $exceptionClass) { + $responses = $this->generateMethodExceptionErrorResponses($exceptionClass, $responses); + } + } + $responses['default']['description'] = 'Unexpected error'; + $responses['default']['schema']['$ref'] = self::ERROR_SCHEMA; + + return $responses; + } + + /** + * Generate parameters based on method data + * + * @param array $httpMethodData + * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + private function generateMethodParameters($httpMethodData) + { + $bodySchema = []; + $parameters = []; + + $phpMethodData = $httpMethodData[Converter::KEY_METHOD]; + /** Return nothing if necessary fields are not set */ + if ( + !isset($phpMethodData['interface']['in']['parameters']) + || !isset($httpMethodData['uri']) + || !isset($httpMethodData['httpOperation']) + ) { + return []; + } + + foreach ($phpMethodData['interface']['in']['parameters'] as $parameterName => $parameterInfo) { + /** Omit forced parameters */ + if ( + isset($httpMethodData['parameters'][$parameterName]['force']) + && $httpMethodData['parameters'][$parameterName]['force'] + ) { + continue; + } + + if (!isset($parameterInfo['type'])) { + return []; + } + $description = isset($parameterInfo['documentation']) ? $parameterInfo['documentation'] : null; + + /** Get location of parameter */ + if (strpos($httpMethodData['uri'], '{' . $parameterName . '}') !== false) { + $parameters[] = $this->generateMethodPathParameter($parameterName, $parameterInfo, $description); + } elseif (strtoupper($httpMethodData['httpOperation']) === 'GET') { + $parameters = $this->generateMethodQueryParameters( + $parameterName, + $parameterInfo, + $description, + $parameters + ); + } else { + $bodySchema = $this->generateBodySchema( + $parameterName, + $parameterInfo, + $description, + $bodySchema + ); + + } + } + + /** + * Add all the path params that don't correspond directly the PHP parameters + */ + preg_match_all('#\\{([^\\{\\}]*)\\}#', $httpMethodData['uri'], $allPathParams); + $remainingPathParams = array_diff( + $allPathParams[1], + array_keys($phpMethodData['interface']['in']['parameters']) + ); + foreach ($remainingPathParams as $pathParam) { + $parameters[] = [ + 'name' => $pathParam, + 'in' => 'path', + 'type' => 'string', + 'required' => true + ]; + } + + if ($bodySchema) { + $bodyParam = []; + $bodyParam['name'] = '$body'; + $bodyParam['in'] = 'body'; + $bodyParam['schema'] = $bodySchema; + $parameters[] = $bodyParam; + } + return $parameters; + } + + /** + * Creates an array for the given query parameter + * + * @param string $name + * @param string $type + * @param string $description + * @param bool|null $required + * @return array + */ + private function createQueryParam($name, $type, $description, $required = null) + { + $param = [ + 'name' => $name, + 'in' => 'query', + ]; + + $param = array_merge($param, $this->getObjectSchema($type, $description)); + + if (isset($required)) { + $param['required'] = $required; + } + return $param; + } + + /** + * Generate Tag Info for given service + * + * @param string $serviceName + * @param array $serviceData + * @return string[] + */ + protected function generateTagInfo($serviceName, $serviceData) + { + $tagInfo = []; + $tagInfo['name'] = $serviceName; + if (!empty($serviceData) && is_array($serviceData)) { + $tagInfo['description'] = $serviceData[Converter::KEY_DESCRIPTION]; + } + return $tagInfo; + } + + /** + * Generate definition for given type + * + * @param string $typeName + * @param string $description + * @return array + */ + protected function getObjectSchema($typeName, $description = '') + { + $simpleType = $this->getSimpleType($typeName); + if ($simpleType == false) { + $result = ['type' => 'array']; + if (!empty($description)) { + $result['description'] = $description; + } + $trimedTypeName = rtrim($typeName, '[]'); + if ($simpleType = $this->getSimpleType($trimedTypeName)) { + $result['items'] = ['type' => $simpleType]; + } else { + if (strpos($typeName, '[]')) { + $result['items'] = ['$ref' => $this->getDefinitionReference($trimedTypeName)]; + } else { + $result = ['$ref' => $this->getDefinitionReference($trimedTypeName)]; + } + if (!$this->isDefinitionExists($trimedTypeName)) { + $definitionKey = $this->toLowerCaseDashSeparated($trimedTypeName); + $this->definitions[$definitionKey] = []; + $this->definitions[$definitionKey] = $this->generateDefinition($trimedTypeName); + } + } + } else { + $result = ['type' => $simpleType]; + if (!empty($description)) { + $result['description'] = $description; + } + } + return $result; + } + + /** + * Generate definition for given type + * + * @param string $typeName + * @return array + */ + protected function generateDefinition($typeName) + { + $properties = []; + $requiredProperties = []; + $typeData = $this->typeProcessor->getTypeData($typeName); + if (isset($typeData['parameters'])) { + foreach ($typeData['parameters'] as $parameterName => $parameterData) { + $properties[$parameterName] = $this->getObjectSchema( + $parameterData['type'], + $parameterData['documentation'] + ); + if ($parameterData['required']) { + $requiredProperties[] = $parameterName; + } + } + } + $definition = ['type' => 'object']; + if (isset($typeData['documentation'])) { + $definition['description'] = $typeData['documentation']; + } + if (!empty($properties)) { + $definition['properties'] = $properties; + } + if (!empty($requiredProperties)) { + $definition['required'] = $requiredProperties; + } + return $definition; + } + + /** + * Get definitions + * + * @return array + * Todo: create interface for error response + */ + protected function getDefinitions() + { + return array_merge( + [ + 'error-response' => [ + 'type' => 'object', + 'properties' => [ + 'message' => [ + 'type' => 'string', + 'description' => 'Error message', + ], + 'errors' => [ + '$ref' => '#/definitions/error-errors', + ], + 'code' => [ + 'type' => 'integer', + 'description' => 'Error code', + ], + 'parameters' => [ + '$ref' => '#/definitions/error-parameters', + ], + 'trace' => [ + 'type' => 'string', + 'description' => 'Stack trace', + ], + ], + 'required' => ['message'], + ], + 'error-errors' => [ + 'type' => 'array', + 'description' => 'Errors list', + 'items' => [ + '$ref' => '#/definitions/error-errors-item', + ], + ], + 'error-errors-item' => [ + 'type' => 'object', + 'description' => 'Error details', + 'properties' => [ + 'message' => [ + 'type' => 'string', + 'description' => 'Error message', + ], + 'parameters' => [ + '$ref' => '#/definitions/error-parameters', + ], + ], + ], + 'error-parameters' => [ + 'type' => 'array', + 'description' => 'Error parameters list', + 'items' => [ + '$ref' => '#/definitions/error-parameters-item', + ], + ], + 'error-parameters-item' => [ + 'type' => 'object', + 'description' => 'Error parameters item', + 'properties' => [ + 'resources' => [ + 'type' => 'string', + 'description' => 'ACL resource', + ], + 'fieldName' => [ + 'type' => 'string', + 'description' => 'Missing or invalid field name' + ], + 'fieldValue' => [ + 'type' => 'string', + 'description' => 'Incorrect field value' + ], + ], + ], + ], + $this->definitions + ); + } + + /** + * Get definition reference + * + * @param string $typeName + * @return string + */ + protected function getDefinitionReference($typeName) + { + return '#/definitions/' . $this->toLowerCaseDashSeparated($typeName); + } + + /** + * Get the CamelCased type name in 'hyphen-separated-lowercase-words' format + * + * e.g. test-module5-v1-entity-all-soap-and-rest + * + * @param string $typeName + * @return string + */ + protected function toLowerCaseDashSeparated($typeName) + { + return strtolower(preg_replace('/(.)([A-Z])/', "$1-$2", $typeName)); + } + + /** + * Check if definition exists + * + * @param string $typeName + * @return bool + */ + protected function isDefinitionExists($typeName) + { + return isset($this->definitions[$this->toLowerCaseDashSeparated($typeName)]); + } + + /** + * Create and add custom attribute types + * + * @return void + */ + protected function addCustomAttributeTypes() + { + foreach ($this->customAttributeTypeLocator->getAllServiceDataInterfaces() as $customAttributeClass) { + $this->typeProcessor->register($customAttributeClass); + } + } + + /** + * Get service metadata + * + * @param string $serviceName + * @return array + */ + protected function getServiceMetadata($serviceName) + { + return $this->serviceMetadata->getRouteMetadata($serviceName); + } + + /** + * Get the simple type supported by Swagger, or false if type is not simple + * + * @param string $type + * @return bool|string + */ + protected function getSimpleType($type) + { + if (array_key_exists($type, $this->simpleTypeList)) { + return $this->simpleTypeList[$type]; + } else { + return false; + } + } + + /** + * Return the parameter names to describe a given parameter, mapped to the respective type + * + * Query parameters may be complex types, and multiple parameters will be listed in the schema to outline + * the structure of the type. + * + * @param string $name + * @param string $type + * @param string $description + * @param string $prefix + * @return string[] + */ + protected function getQueryParamNames($name, $type, $description, $prefix = '') + { + if ($this->typeProcessor->isTypeSimple($type)) { + // Primitive type or array of primitive types + return [ + $this->handlePrimitive($name, $prefix) => [ + 'type' => substr($type, -2) === '[]' ? $type : $this->getSimpleType($type), + 'description' => $description + ] + ]; + } + if ($this->typeProcessor->isArrayType($type)) { + // Array of complex type + $arrayType = substr($type, 0, -2); + return $this->handleComplex($name, $arrayType, $prefix, true); + } else { + // Complex type + return $this->handleComplex($name, $type, $prefix, false); + } + } + + /** + * Recursively generate the query param names for a complex type + * + * @param string $name + * @param string $type + * @param string $prefix + * @param bool $isArray + * @return string[] + */ + private function handleComplex($name, $type, $prefix, $isArray) + { + $parameters = $this->typeProcessor->getTypeData($type)['parameters']; + $queryNames = []; + foreach ($parameters as $subParameterName => $subParameterInfo) { + $subParameterType = $subParameterInfo['type']; + $subParameterDescription = isset($subParameterInfo['documentation']) + ? $subParameterInfo['documentation'] + : null; + $subPrefix = $prefix + ? $prefix . '[' . $name . ']' + : $name; + if ($isArray) { + $subPrefix .= self::ARRAY_SIGNIFIER; + } + $queryNames = array_merge( + $queryNames, + $this->getQueryParamNames($subParameterName, $subParameterType, $subParameterDescription, $subPrefix) + ); + } + return $queryNames; + } + + /** + * Generate the query param name for a primitive type + * + * @param string $name + * @param string $prefix + * @return string + */ + private function handlePrimitive($name, $prefix) + { + return $prefix + ? $prefix . '[' . $name . ']' + : $name; + } + + /** + * Convert path parameters from :param to {param} + * + * @param string $uri + * @return string + */ + private function convertPathParams($uri) + { + $parts = explode('/', $uri); + for ($i=0; $i < count($parts); $i++) { + if (strpos($parts[$i], ':') === 0) { + $parts[$i] = '{' . substr($parts[$i], 1) . '}'; + } + } + return implode('/', $parts); + } + + /** + * Generate method path parameter + * + * @param string $parameterName + * @param array $parameterInfo + * @param string $description + * @return string[] + */ + private function generateMethodPathParameter($parameterName, $parameterInfo, $description) + { + $param = [ + 'name' => $parameterName, + 'in' => 'path', + 'type' => $this->getSimpleType($parameterInfo['type']), + 'required' => true + ]; + if ($description) { + $param['description'] = $description; + return $param; + } + return $param; + } + + /** + * Generate method query parameters + * + * @param string $parameterName + * @param array $parameterInfo + * @param string $description + * @param array $parameters + * @return array + */ + private function generateMethodQueryParameters($parameterName, $parameterInfo, $description, $parameters) + { + $queryParams = $this->getQueryParamNames($parameterName, $parameterInfo['type'], $description); + if (count($queryParams) === 1) { + // handle simple query parameter (includes the 'required' field) + $parameters[] = $this->createQueryParam( + $parameterName, + $parameterInfo['type'], + $description, + $parameterInfo['required'] + ); + } else { + /** + * Complex query parameters are represented by a set of names which describes the object's fields. + * + * Omits the 'required' field. + */ + foreach ($queryParams as $name => $queryParamInfo) { + $parameters[] = $this->createQueryParam( + $name, + $queryParamInfo['type'], + $queryParamInfo['description'] + ); + } + } + return $parameters; + } + + /** + * Generate body schema + * + * @param string $parameterName + * @param array $parameterInfo + * @param string $description + * @param array $bodySchema + * @return array + */ + private function generateBodySchema($parameterName, $parameterInfo, $description, $bodySchema) + { + $required = isset($parameterInfo['required']) ? $parameterInfo['required'] : null; + /* + * There can only be one body parameter, multiple PHP parameters are represented as different + * properties of the body. + */ + if ($required) { + $bodySchema['required'][] = $parameterName; + } + $bodySchema['properties'][$parameterName] = $this->getObjectSchema( + $parameterInfo['type'], + $description + ); + return $bodySchema; + } + + /** + * Generate method 200 response + * + * @param array $parameters + * @param array $responses + * @return array + */ + private function generateMethodSuccessResponse($parameters, $responses) + { + if (isset($parameters['result']) && is_array($parameters['result'])) { + $description = ''; + if (isset($parameters['result']['documentation'])) { + $description = $parameters['result']['documentation']; + } + $schema = []; + if (isset($parameters['result']['type'])) { + $schema = $this->getObjectSchema($parameters['result']['type'], $description); + } + $responses['200']['description'] = '200 Success.'; + if (!empty($schema)) { + $responses['200']['schema'] = $schema; + } + } + return $responses; + } + + /** + * Generate method exception error responses + * + * @param array $exceptionClass + * @param array $responses + * @return array + */ + private function generateMethodExceptionErrorResponses($exceptionClass, $responses) + { + $httpCode = '500'; + $description = 'Internal Server error'; + if (is_subclass_of($exceptionClass, '\Magento\Framework\Exception\LocalizedException')) { + // Map HTTP codes for LocalizedExceptions according to exception type + if (is_subclass_of($exceptionClass, '\Magento\Framework\Exception\NoSuchEntityException')) { + $httpCode = WebapiException::HTTP_NOT_FOUND; + $description = '404 Not Found'; + } elseif (is_subclass_of($exceptionClass, '\Magento\Framework\Exception\AuthorizationException') + || is_subclass_of($exceptionClass, '\Magento\Framework\Exception\AuthenticationException') + ) { + $httpCode = WebapiException::HTTP_UNAUTHORIZED; + $description = self::UNAUTHORIZED_DESCRIPTION; + } else { + // Input, Expired, InvalidState exceptions will fall to here + $httpCode = WebapiException::HTTP_BAD_REQUEST; + $description = '400 Bad Request'; + } + } + $responses[$httpCode]['description'] = $description; + $responses[$httpCode]['schema']['$ref'] = self::ERROR_SCHEMA; + + return $responses; + } +} diff --git a/app/code/Magento/Webapi/Model/ServiceMetadata.php b/app/code/Magento/Webapi/Model/ServiceMetadata.php new file mode 100644 index 0000000000000..68af76f494293 --- /dev/null +++ b/app/code/Magento/Webapi/Model/ServiceMetadata.php @@ -0,0 +1,271 @@ +config = $config; + $this->cache = $cache; + $this->classReflector = $classReflector; + $this->services = $this->initServicesMetadata(); + } + + /** + * Collect the list of services metadata + * + * @return array + */ + protected function initServicesMetadata() + { + $services = []; + foreach ($this->config->getServices()[Converter::KEY_SERVICES] as $serviceClass => $serviceVersionData) { + foreach ($serviceVersionData as $version => $serviceData) { + $serviceName = $this->getServiceName($serviceClass, $version); + foreach ($serviceData[Converter::KEY_METHODS] as $methodName => $methodMetadata) { + $services[$serviceName][self::KEY_SERVICE_METHODS][$methodName] = [ + self::KEY_METHOD => $methodName, + self::KEY_IS_REQUIRED => (bool)$methodMetadata[Converter::KEY_SECURE], + self::KEY_IS_SECURE => $methodMetadata[Converter::KEY_SECURE], + self::KEY_ACL_RESOURCES => $methodMetadata[Converter::KEY_ACL_RESOURCES], + ]; + $services[$serviceName][self::KEY_CLASS] = $serviceClass; + } + $reflectedMethodsMetadata = $this->classReflector->reflectClassMethods( + $serviceClass, + $services[$serviceName][self::KEY_SERVICE_METHODS] + ); + $services[$serviceName][self::KEY_SERVICE_METHODS] = array_merge_recursive( + $services[$serviceName][self::KEY_SERVICE_METHODS], + $reflectedMethodsMetadata + ); + $services[$serviceName][Converter::KEY_DESCRIPTION] = $this->classReflector->extractClassDescription( + $serviceClass + ); + } + } + + return $services; + } + + /** + * Return services loaded from cache if enabled or from files merged previously + * + * @return array + */ + public function getServicesConfig() + { + if (null === $this->services) { + $servicesConfig = $this->cache->load(self::SERVICES_CACHE_ID); + if ($servicesConfig && is_string($servicesConfig)) { + $this->services = unserialize($servicesConfig); + } else { + $this->services = $this->initServicesMetadata(); + $this->cache->save(serialize($this->services), self::SERVICES_CACHE_ID); + } + } + return $this->services; + } + + /** + * Retrieve specific service interface data. + * + * @param string $serviceName + * @return array + * @throws \RuntimeException + */ + public function getServiceMetadata($serviceName) + { + $servicesConfig = $this->getServicesConfig(); + if (!isset($servicesConfig[$serviceName]) || !is_array($servicesConfig[$serviceName])) { + throw new \RuntimeException(__('Requested service is not available: "%1"', $serviceName)); + } + return $servicesConfig[$serviceName]; + } + + /** + * Translate service interface name into service name. + * + * Example: + *
+     * - 'Magento\Customer\Api\CustomerAccountInterface', 'V1', false => customerCustomerAccount
+     * - 'Magento\Customer\Api\CustomerAddressInterface', 'V1', true  => customerCustomerAddressV1
+     * 
+ * + * @param string $interfaceName + * @param string $version + * @param bool $preserveVersion Should version be preserved during interface name conversion into service name + * @return string + * @throws \InvalidArgumentException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + public function getServiceName($interfaceName, $version, $preserveVersion = true) + { + if (!preg_match(\Magento\Webapi\Model\Config::SERVICE_CLASS_PATTERN, $interfaceName, $matches)) { + $apiClassPattern = "#^(.+?)\\\\(.+?)\\\\Api\\\\(.+?)(Interface)?$#"; + preg_match($apiClassPattern, $interfaceName, $matches); + } + + if (!empty($matches)) { + $moduleNamespace = $matches[1]; + $moduleName = $matches[2]; + $moduleNamespace = ($moduleNamespace == 'Magento') ? '' : $moduleNamespace; + if ($matches[4] === 'Interface') { + $matches[4] = $matches[3]; + } + $serviceNameParts = explode('\\', trim($matches[4], '\\')); + if ($moduleName == $serviceNameParts[0]) { + /** Avoid duplication of words in service name */ + $moduleName = ''; + } + $parentServiceName = $moduleNamespace . $moduleName . array_shift($serviceNameParts); + array_unshift($serviceNameParts, $parentServiceName); + if ($preserveVersion) { + $serviceNameParts[] = $version; + } + } elseif (preg_match(\Magento\Webapi\Model\Config::API_PATTERN, $interfaceName, $matches)) { + $moduleNamespace = $matches[1]; + $moduleName = $matches[2]; + $moduleNamespace = ($moduleNamespace == 'Magento') ? '' : $moduleNamespace; + $serviceNameParts = explode('\\', trim($matches[3], '\\')); + if ($moduleName == $serviceNameParts[0]) { + /** Avoid duplication of words in service name */ + $moduleName = ''; + } + $parentServiceName = $moduleNamespace . $moduleName . array_shift($serviceNameParts); + array_unshift($serviceNameParts, $parentServiceName); + if ($preserveVersion) { + $serviceNameParts[] = $version; + } + } else { + throw new \InvalidArgumentException(sprintf('The service interface name "%s" is invalid.', $interfaceName)); + } + return lcfirst(implode('', $serviceNameParts)); + } + + /** + * Retrieve specific service interface data with route. + * + * @param string $serviceName + * @return array + * @throws \RuntimeException + */ + public function getRouteMetadata($serviceName) + { + $routesConfig = $this->getRoutesConfig(); + if (!isset($routesConfig[$serviceName]) || !is_array($routesConfig[$serviceName])) { + throw new \RuntimeException(__('Requested service is not available: "%1"', $serviceName)); + } + return $routesConfig[$serviceName]; + } + + /** + * Return routes loaded from cache if enabled or from files merged previously + * + * @return array + */ + public function getRoutesConfig() + { + if (null === $this->routes) { + $routesConfig = $this->cache->load(self::ROUTES_CACHE_ID); + if ($routesConfig && is_string($routesConfig)) { + $this->routes = unserialize($routesConfig); + } else { + $this->routes = $this->initRoutesMetadata(); + $this->cache->save(serialize($this->routes), self::ROUTES_CACHE_ID); + } + } + return $this->routes; + } + + /** + * Collect the list of services with routes and request types for use in REST. + * + * @return array + */ + protected function initRoutesMetadata() + { + $routes = $this->getServicesConfig(); + foreach ($this->config->getServices()[Converter::KEY_ROUTES] as $url => $routeData) { + foreach ($routeData as $method => $data) { + $serviceClass = $data[Converter::KEY_SERVICE][Converter::KEY_SERVICE_CLASS]; + $version = explode('/', ltrim($url, '/'))[0]; + $serviceName = $this->getServiceName($serviceClass, $version); + $methodName = $data[Converter::KEY_SERVICE][Converter::KEY_METHOD]; + $routes[$serviceName][Converter::KEY_ROUTES][$url][$method][Converter::KEY_METHOD] = $methodName; + $routes[$serviceName][Converter::KEY_ROUTES][$url][$method][Converter::KEY_DATA_PARAMETERS] + = $data[Converter::KEY_DATA_PARAMETERS]; + + } + } + return $routes; + } +} diff --git a/app/code/Magento/Webapi/Model/Soap/Config.php b/app/code/Magento/Webapi/Model/Soap/Config.php index 98e38cd8424ab..5fca8bf5d654a 100644 --- a/app/code/Magento/Webapi/Model/Soap/Config.php +++ b/app/code/Magento/Webapi/Model/Soap/Config.php @@ -5,10 +5,9 @@ */ namespace Magento\Webapi\Model\Soap; -use Magento\Framework\App\Cache\Type\Webapi as WebApiCache; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Filesystem\Directory\ReadInterface; -use Magento\Webapi\Model\Config\Converter; +use Magento\Webapi\Model\ServiceMetadata; /** * Webapi Config Model for Soap. @@ -17,42 +16,12 @@ */ class Config { - /**#@+ - * Keys that a used for service config internal representation. - */ - const KEY_CLASS = 'class'; - - const KEY_IS_SECURE = 'isSecure'; - - const KEY_SERVICE_METHODS = 'methods'; - - const KEY_METHOD = 'method'; - - const KEY_IS_REQUIRED = 'inputRequired'; - - const KEY_ACL_RESOURCES = 'resources'; - - const CACHE_ID = 'soap-services-config'; - - /**#@-*/ - /** @var ReadInterface */ protected $modulesDirectory; - /** @var \Magento\Webapi\Model\Config */ - protected $config; - /** @var \Magento\Framework\ObjectManagerInterface */ protected $objectManager; - /** - * SOAP services should be stored separately as the list of available operations - * is collected using reflection, not taken from config as for REST - * - * @var array - */ - protected $soapServices; - /** * List of SOAP operations available in the system * @@ -60,45 +29,30 @@ class Config */ protected $soapOperations; - /** - * @var \Magento\Webapi\Model\Soap\Config\ClassReflector - */ - protected $classReflector; - - /** - * @var WebApiCache - */ - protected $cache; - /** @var \Magento\Framework\Registry */ protected $registry; + /** @var \Magento\Webapi\Model\ServiceMetadata */ + protected $serviceMetadata; + /** * Initialize dependencies. * * @param \Magento\Framework\ObjectManagerInterface $objectManager * @param \Magento\Framework\Filesystem $filesystem - * @param \Magento\Webapi\Model\Config $config - * @param \Magento\Webapi\Model\Soap\Config\ClassReflector $classReflector - * @param WebApiCache $cache * @param \Magento\Framework\Registry $registry + * @param \Magento\Webapi\Model\ServiceMetadata $serviceMetadata */ public function __construct( \Magento\Framework\ObjectManagerInterface $objectManager, \Magento\Framework\Filesystem $filesystem, - \Magento\Webapi\Model\Config $config, - \Magento\Webapi\Model\Soap\Config\ClassReflector $classReflector, - WebApiCache $cache, - \Magento\Framework\Registry $registry + \Magento\Framework\Registry $registry, + \Magento\Webapi\Model\ServiceMetadata $serviceMetadata ) { $this->modulesDirectory = $filesystem->getDirectoryRead(DirectoryList::MODULES); - $this->config = $config; $this->objectManager = $objectManager; - $this->classReflector = $classReflector; - $this->cache = $cache; $this->registry = $registry; - //Initialize cache - $this->soapServices = $this->initServicesMetadata(); + $this->serviceMetadata = $serviceMetadata; } /** @@ -120,15 +74,15 @@ protected function getSoapOperations($requestedServices) if (null == $this->soapOperations) { $this->soapOperations = []; foreach ($this->getRequestedSoapServices($requestedServices) as $serviceName => $serviceData) { - foreach ($serviceData[self::KEY_SERVICE_METHODS] as $methodData) { - $method = $methodData[self::KEY_METHOD]; - $class = $serviceData[self::KEY_CLASS]; + foreach ($serviceData[ServiceMetadata::KEY_SERVICE_METHODS] as $methodData) { + $method = $methodData[ServiceMetadata::KEY_METHOD]; + $class = $serviceData[ServiceMetadata::KEY_CLASS]; $operationName = $serviceName . ucfirst($method); $this->soapOperations[$operationName] = [ - self::KEY_CLASS => $class, - self::KEY_METHOD => $method, - self::KEY_IS_SECURE => $methodData[self::KEY_IS_SECURE], - self::KEY_ACL_RESOURCES => $methodData[self::KEY_ACL_RESOURCES], + ServiceMetadata::KEY_CLASS => $class, + ServiceMetadata::KEY_METHOD => $method, + ServiceMetadata::KEY_IS_SECURE => $methodData[ServiceMetadata::KEY_IS_SECURE], + ServiceMetadata::KEY_ACL_RESOURCES => $methodData[ServiceMetadata::KEY_ACL_RESOURCES], ]; } } @@ -136,59 +90,6 @@ protected function getSoapOperations($requestedServices) return $this->soapOperations; } - /** - * Return services loaded from cache if enabled or from files merged previously - * - * @return array - */ - public function getSoapServicesConfig() - { - if (null === $this->soapServices) { - $soapServicesConfig = $this->cache->load(self::CACHE_ID); - if ($soapServicesConfig && is_string($soapServicesConfig)) { - $this->soapServices = unserialize($soapServicesConfig); - } else { - $this->soapServices = $this->initServicesMetadata(); - $this->cache->save(serialize($this->soapServices), self::CACHE_ID); - } - } - return $this->soapServices; - } - - /** - * Collect the list of services with their operations available in SOAP. - * - * @return array - */ - protected function initServicesMetadata() - { - $soapServices = []; - foreach ($this->config->getServices()[Converter::KEY_SERVICES] as $serviceClass => $serviceVersionData) { - foreach ($serviceVersionData as $version => $serviceData) { - $serviceName = $this->getServiceName($serviceClass, $version); - foreach ($serviceData[Converter::KEY_METHODS] as $methodName => $methodMetadata) { - $soapServices[$serviceName][self::KEY_SERVICE_METHODS][$methodName] = [ - self::KEY_METHOD => $methodName, - self::KEY_IS_REQUIRED => (bool)$methodMetadata[Converter::KEY_SECURE], - self::KEY_IS_SECURE => $methodMetadata[Converter::KEY_SECURE], - self::KEY_ACL_RESOURCES => $methodMetadata[Converter::KEY_ACL_RESOURCES], - ]; - $soapServices[$serviceName][self::KEY_CLASS] = $serviceClass; - } - $reflectedMethodsMetadata = $this->classReflector->reflectClassMethods( - $serviceClass, - $soapServices[$serviceName][self::KEY_SERVICE_METHODS] - ); - $soapServices[$serviceName][self::KEY_SERVICE_METHODS] = array_merge_recursive( - $soapServices[$serviceName][self::KEY_SERVICE_METHODS], - $reflectedMethodsMetadata - ); - } - } - - return $soapServices; - } - /** * Retrieve service method information, including service class, method name, and isSecure attribute value. * @@ -208,10 +109,10 @@ public function getServiceMethodInfo($soapOperation, $requestedServices) ); } return [ - self::KEY_CLASS => $soapOperations[$soapOperation][self::KEY_CLASS], - self::KEY_METHOD => $soapOperations[$soapOperation][self::KEY_METHOD], - self::KEY_IS_SECURE => $soapOperations[$soapOperation][self::KEY_IS_SECURE], - self::KEY_ACL_RESOURCES => $soapOperations[$soapOperation][self::KEY_ACL_RESOURCES] + ServiceMetadata::KEY_CLASS => $soapOperations[$soapOperation][ServiceMetadata::KEY_CLASS], + ServiceMetadata::KEY_METHOD => $soapOperations[$soapOperation][ServiceMetadata::KEY_METHOD], + ServiceMetadata::KEY_IS_SECURE => $soapOperations[$soapOperation][ServiceMetadata::KEY_IS_SECURE], + ServiceMetadata::KEY_ACL_RESOURCES => $soapOperations[$soapOperation][ServiceMetadata::KEY_ACL_RESOURCES] ]; } @@ -224,7 +125,7 @@ public function getServiceMethodInfo($soapOperation, $requestedServices) public function getRequestedSoapServices(array $requestedServices) { $services = []; - $soapServicesConfig = $this->getSoapServicesConfig(); + $soapServicesConfig = $this->serviceMetadata->getServicesConfig(); foreach ($requestedServices as $serviceName) { if (isset($soapServicesConfig[$serviceName])) { $services[$serviceName] = $soapServicesConfig[$serviceName]; @@ -243,83 +144,8 @@ public function getRequestedSoapServices(array $requestedServices) */ public function getSoapOperation($interfaceName, $methodName, $version) { - $serviceName = $this->getServiceName($interfaceName, $version); + $serviceName = $this->serviceMetadata->getServiceName($interfaceName, $version); $operationName = $serviceName . ucfirst($methodName); return $operationName; } - - /** - * Retrieve specific service interface data. - * - * @param string $serviceName - * @return array - * @throws \RuntimeException - */ - public function getServiceMetadata($serviceName) - { - $soapServicesConfig = $this->getSoapServicesConfig(); - if (!isset($soapServicesConfig[$serviceName]) || !is_array($soapServicesConfig[$serviceName])) { - throw new \RuntimeException(__('Requested service is not available: "%1"', $serviceName)); - } - return $soapServicesConfig[$serviceName]; - } - - /** - * Translate service interface name into service name. - * Example: - *
-     * - 'Magento\Customer\Service\V1\CustomerAccountInterface', false => customerCustomerAccount
-     * - 'Magento\Customer\Service\V1\CustomerAddressInterface', true  => customerCustomerAddressV1
-     * 
- * - * @param string $interfaceName - * @param string $version - * @param bool $preserveVersion Should version be preserved during interface name conversion into service name - * @return string - * @throws \InvalidArgumentException - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - public function getServiceName($interfaceName, $version, $preserveVersion = true) - { - if (!preg_match(\Magento\Webapi\Model\Config::SERVICE_CLASS_PATTERN, $interfaceName, $matches)) { - $apiClassPattern = "#^(.+?)\\\\(.+?)\\\\Api\\\\(.+?)(Interface)?$#"; - preg_match($apiClassPattern, $interfaceName, $matches); - } - - if (!empty($matches)) { - $moduleNamespace = $matches[1]; - $moduleName = $matches[2]; - $moduleNamespace = ($moduleNamespace == 'Magento') ? '' : $moduleNamespace; - if ($matches[4] === 'Interface') { - $matches[4] = $matches[3]; - } - $serviceNameParts = explode('\\', trim($matches[4], '\\')); - if ($moduleName == $serviceNameParts[0]) { - /** Avoid duplication of words in service name */ - $moduleName = ''; - } - $parentServiceName = $moduleNamespace . $moduleName . array_shift($serviceNameParts); - array_unshift($serviceNameParts, $parentServiceName); - if ($preserveVersion) { - $serviceNameParts[] = $version; - } - } elseif (preg_match(\Magento\Webapi\Model\Config::API_PATTERN, $interfaceName, $matches)) { - $moduleNamespace = $matches[1]; - $moduleName = $matches[2]; - $moduleNamespace = ($moduleNamespace == 'Magento') ? '' : $moduleNamespace; - $serviceNameParts = explode('\\', trim($matches[3], '\\')); - if ($moduleName == $serviceNameParts[0]) { - /** Avoid duplication of words in service name */ - $moduleName = ''; - } - $parentServiceName = $moduleNamespace . $moduleName . array_shift($serviceNameParts); - array_unshift($serviceNameParts, $parentServiceName); - if ($preserveVersion) { - $serviceNameParts[] = $version; - } - } else { - throw new \InvalidArgumentException(sprintf('The service interface name "%s" is invalid.', $interfaceName)); - } - return lcfirst(implode('', $serviceNameParts)); - } } diff --git a/app/code/Magento/Webapi/Model/Soap/Server.php b/app/code/Magento/Webapi/Model/Soap/Server.php index 356afdbad8778..3d4ee5b7e344d 100644 --- a/app/code/Magento/Webapi/Model/Soap/Server.php +++ b/app/code/Magento/Webapi/Model/Soap/Server.php @@ -7,6 +7,8 @@ */ namespace Magento\Webapi\Model\Soap; +use Magento\Framework\Webapi\Request; + class Server { const SOAP_DEFAULT_ENCODING = 'UTF-8'; @@ -34,7 +36,7 @@ class Server protected $_configScope; /** - * @var \Magento\Webapi\Controller\Soap\Request + * @var Request */ protected $_request; @@ -63,7 +65,7 @@ class Server * * @param \Magento\Framework\App\AreaList $areaList * @param \Magento\Framework\Config\ScopeInterface $configScope - * @param \Magento\Webapi\Controller\Soap\Request $request + * @param Request $request * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Webapi\Model\Soap\ServerFactory $soapServerFactory * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor @@ -73,7 +75,7 @@ class Server public function __construct( \Magento\Framework\App\AreaList $areaList, \Magento\Framework\Config\ScopeInterface $configScope, - \Magento\Webapi\Controller\Soap\Request $request, + Request $request, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Webapi\Model\Soap\ServerFactory $soapServerFactory, \Magento\Framework\Reflection\TypeProcessor $typeProcessor, diff --git a/app/code/Magento/Webapi/Model/Soap/Wsdl/Generator.php b/app/code/Magento/Webapi/Model/Soap/Wsdl/Generator.php index e412de30599a1..3e7c6934f54c4 100644 --- a/app/code/Magento/Webapi/Model/Soap/Wsdl/Generator.php +++ b/app/code/Magento/Webapi/Model/Soap/Wsdl/Generator.php @@ -6,6 +6,7 @@ */ namespace Magento\Webapi\Model\Soap\Wsdl; +use Magento\Webapi\Model\AbstractSchemaGenerator; use Magento\Webapi\Model\Soap\Fault; use Magento\Webapi\Model\Soap\Wsdl; use Magento\Webapi\Model\Soap\WsdlFactory; @@ -13,10 +14,11 @@ /** * WSDL generator. */ -class Generator +class Generator extends AbstractSchemaGenerator { + /** WSDL name */ const WSDL_NAME = 'MagentoWSDL'; - const WSDL_CACHE_ID = 'WSDL'; + /** * WSDL factory instance. * @@ -24,118 +26,39 @@ class Generator */ protected $_wsdlFactory; - /** - * @var \Magento\Framework\App\Cache\Type\Webapi - */ - protected $_cache; - - /** - * @var \Magento\Webapi\Model\Soap\Config - */ - protected $_apiConfig; - - /** @var \Magento\Framework\Reflection\TypeProcessor */ - protected $_typeProcessor; - - /** - * The list of registered complex types. - * - * @var string[] - */ - protected $_registeredTypes = []; - - /** - * @var \Magento\Store\Model\StoreManagerInterface - */ - protected $storeManager; - - /** - * @var \Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface - */ - protected $customAttributeTypeLocator = null; - /** * Initialize dependencies. * - * @param \Magento\Webapi\Model\Soap\Config $apiConfig - * @param WsdlFactory $wsdlFactory * @param \Magento\Framework\App\Cache\Type\Webapi $cache * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface $customAttributeTypeLocator + * @param \Magento\Webapi\Model\ServiceMetadata $serviceMetadata + * @param WsdlFactory $wsdlFactory */ public function __construct( - \Magento\Webapi\Model\Soap\Config $apiConfig, - WsdlFactory $wsdlFactory, \Magento\Framework\App\Cache\Type\Webapi $cache, \Magento\Framework\Reflection\TypeProcessor $typeProcessor, \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface $customAttributeTypeLocator + \Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface $customAttributeTypeLocator, + \Magento\Webapi\Model\ServiceMetadata $serviceMetadata, + WsdlFactory $wsdlFactory ) { - $this->_apiConfig = $apiConfig; $this->_wsdlFactory = $wsdlFactory; - $this->_cache = $cache; - $this->_typeProcessor = $typeProcessor; - $this->storeManager = $storeManager; - $this->customAttributeTypeLocator = $customAttributeTypeLocator; + parent::__construct($cache, $typeProcessor, $storeManager, $customAttributeTypeLocator, $serviceMetadata); } /** - * Retrieve an array of services - * - * @return array + * {@inheritdoc} */ - public function getListOfServices() + protected function generateSchema($requestedServiceMetadata, $requestScheme, $requestHost, $endPointUrl) { - return $this->_apiConfig->getSoapServicesConfig(); - } - - /** - * Generate WSDL file based on requested services (uses cache) - * - * @param array $requestedServices - * @param string $endPointUrl - * @return string - * @throws \Exception - */ - public function generate($requestedServices, $endPointUrl) - { - /** Sort requested services by names to prevent caching of the same wsdl file more than once. */ - ksort($requestedServices); - $currentStore = $this->storeManager->getStore(); - $cacheId = self::WSDL_CACHE_ID . hash('md5', serialize($requestedServices) . $currentStore->getCode()); - $cachedWsdlContent = $this->_cache->load($cacheId); - if ($cachedWsdlContent !== false) { - return $cachedWsdlContent; - } - $services = []; - foreach ($requestedServices as $serviceName) { - $services[$serviceName] = $this->_apiConfig->getServiceMetadata($serviceName); - } - - $wsdlContent = $this->_generate($services, $endPointUrl); - $this->_cache->save($wsdlContent, $cacheId, [\Magento\Framework\App\Cache\Type\Webapi::CACHE_TAG]); - - return $wsdlContent; - } - - /** - * Generate WSDL file based on requested services. - * - * @param array $requestedServices - * @param string $endPointUrl - * @return string - * @throws \Magento\Framework\Webapi\Exception - */ - protected function _generate($requestedServices, $endPointUrl) - { - $this->_collectCallInfo($requestedServices); $wsdl = $this->_wsdlFactory->create(self::WSDL_NAME, $endPointUrl); $wsdl->addSchemaTypeSection(); $faultMessageName = $this->_addGenericFaultComplexTypeNodes($wsdl); $wsdl = $this->addCustomAttributeTypes($wsdl); - foreach ($requestedServices as $serviceClass => $serviceData) { + foreach ($requestedServiceMetadata as $serviceClass => $serviceData) { $portTypeName = $this->getPortTypeName($serviceClass); $bindingName = $this->getBindingName($serviceClass); $portType = $wsdl->addPortType($portTypeName); @@ -146,7 +69,7 @@ protected function _generate($requestedServices, $endPointUrl) $wsdl->addService($serviceName, $portName, Wsdl::TYPES_NS . ':' . $bindingName, $endPointUrl, SOAP_1_2); foreach ($serviceData['methods'] as $methodName => $methodData) { - $operationName = $this->getOperationName($serviceClass, $methodName); + $operationName = $this->typeProcessor->getOperationName($serviceClass, $methodName); $bindingDataPrototype = ['use' => 'literal']; $inputBinding = $bindingDataPrototype; $inputMessageName = $this->_createOperationInput($wsdl, $operationName, $methodData); @@ -189,8 +112,8 @@ protected function _generate($requestedServices, $endPointUrl) protected function addCustomAttributeTypes($wsdl) { foreach ($this->customAttributeTypeLocator->getAllServiceDataInterfaces() as $customAttributeClass) { - $typeName = $this->_typeProcessor->register($customAttributeClass); - $wsdl->addComplexType($this->_typeProcessor->getArrayItemType($typeName)); + $typeName = $this->typeProcessor->register($customAttributeClass); + $wsdl->addComplexType($this->typeProcessor->getArrayItemType($typeName)); } return $wsdl; } @@ -225,7 +148,7 @@ protected function _createOperationInput(Wsdl $wsdl, $operationName, $methodData 'parameters' => $inputParameters, 'callInfo' => $callInfo, ]; - $this->_typeProcessor->setTypeData($complexTypeName, $typeData); + $this->typeProcessor->setTypeData($complexTypeName, $typeData); $wsdl->addComplexType($complexTypeName); $wsdl->addMessage( $inputMessageName, @@ -263,7 +186,7 @@ protected function _createOperationOutput(Wsdl $wsdl, $operationName, $methodDat 'parameters' => $methodData['interface']['out']['parameters'], 'callInfo' => $callInfo, ]; - $this->_typeProcessor->setTypeData($complexTypeName, $typeData); + $this->typeProcessor->setTypeData($complexTypeName, $typeData); $wsdl->addComplexType($complexTypeName); $wsdl->addMessage( $outputMessageName, @@ -276,17 +199,6 @@ protected function _createOperationOutput(Wsdl $wsdl, $operationName, $methodDat return Wsdl::TYPES_NS . ':' . $outputMessageName; } - /** - * Get name of complexType for message element. - * - * @param string $messageName - * @return string - */ - public function getElementComplexTypeName($messageName) - { - return ucfirst($messageName); - } - /** * Get name for service portType node. * @@ -331,18 +243,6 @@ public function getServiceName($serviceName) return $serviceName . 'Service'; } - /** - * Get name of operation based on service and method names. - * - * @param string $serviceName - * @param string $methodName - * @return string - */ - public function getOperationName($serviceName, $methodName) - { - return $serviceName . ucfirst($methodName); - } - /** * Get input message node name for operation. * @@ -365,54 +265,6 @@ public function getOutputMessageName($operationName) return $operationName . 'Response'; } - /** - * Collect data about complex types call info. - * - * Walks through all requested services and checks all methods 'in' and 'out' parameters. - * - * @param array $requestedServices - * @return void - */ - protected function _collectCallInfo($requestedServices) - { - foreach ($requestedServices as $serviceName => $serviceData) { - foreach ($serviceData['methods'] as $methodName => $methodData) { - $this->_processInterfaceCallInfo($methodData['interface'], $serviceName, $methodName); - } - } - } - - /** - * Process call info data from interface. - * - * @param array $interface - * @param string $serviceName - * @param string $methodName - * @return void - */ - protected function _processInterfaceCallInfo($interface, $serviceName, $methodName) - { - foreach ($interface as $direction => $interfaceData) { - $direction = ($direction == 'in') ? 'requiredInput' : 'returned'; - foreach ($interfaceData['parameters'] as $parameterData) { - $parameterType = $parameterData['type']; - if (!$this->_typeProcessor->isTypeSimple($parameterType) - && !$this->_typeProcessor->isTypeAny($parameterType) - ) { - $operation = $this->getOperationName($serviceName, $methodName); - if ($parameterData['required']) { - $condition = ($direction == 'requiredInput') ? 'yes' : 'always'; - } else { - $condition = ($direction == 'requiredInput') ? 'no' : 'conditionally'; - } - $callInfo = []; - $callInfo[$direction][$condition]['calls'][] = $operation; - $this->_typeProcessor->setTypeData($parameterType, ['callInfo' => $callInfo]); - } - } - } - } - /** * Add WSDL elements related to generic SOAP fault, which are common for all operations: element, type and message. * @@ -478,9 +330,9 @@ protected function _addGenericFaultComplexTypeNodes($wsdl) ], ], ]; - $this->_typeProcessor->setTypeData($faultParamsComplexType, $faultParamsData); - $this->_typeProcessor->setTypeData($wrappedErrorComplexType, $wrappedErrorData); - $this->_typeProcessor->setTypeData($complexTypeName, $genericFaultTypeData); + $this->typeProcessor->setTypeData($faultParamsComplexType, $faultParamsData); + $this->typeProcessor->setTypeData($wrappedErrorComplexType, $wrappedErrorData); + $this->typeProcessor->setTypeData($complexTypeName, $genericFaultTypeData); $wsdl->addComplexType($complexTypeName); $wsdl->addMessage( $faultMessageName, @@ -493,4 +345,15 @@ protected function _addGenericFaultComplexTypeNodes($wsdl) return Wsdl::TYPES_NS . ':' . $faultMessageName; } + + /** + * Get service metadata + * + * @param string $serviceName + * @return string[] + */ + protected function getServiceMetadata($serviceName) + { + return $this->serviceMetadata->getServiceMetadata($serviceName); + } } diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php index 30a175b6024bf..30096b5cb5a4e 100644 --- a/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php @@ -15,6 +15,7 @@ * Test Rest controller. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class RestTest extends \PHPUnit_Framework_TestCase { @@ -33,31 +34,16 @@ class RestTest extends \PHPUnit_Framework_TestCase */ protected $_responseMock; - /** - * @var \Magento\Webapi\Controller\Rest\Router - */ - protected $_routerMock; - /** * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Webapi\Controller\Rest\Router\Route */ protected $_routeMock; - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $_objectManagerMock; - /** * @var \stdClass */ protected $_serviceMock; - /** - * @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject - */ - protected $_appStateMock; - /** * @var \Magento\Framework\Oauth\OauthInterface */ @@ -68,65 +54,47 @@ class RestTest extends \PHPUnit_Framework_TestCase */ protected $_authorizationMock; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $areaListMock; - /** * @var \Magento\Framework\Webapi\ServiceInputProcessor|\PHPUnit_Framework_MockObject_MockObject */ protected $serviceInputProcessorMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $areaMock; - - /** - * @var \Magento\Webapi\Controller\Rest\ParamsOverrider|\PHPUnit_Framework_MockObject_MockObject - */ - protected $paramsOverriderMock; - - /** - * @var \Magento\Framework\Reflection\DataObjectProcessor|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Webapi\Model\Rest\Swagger\Generator | \PHPUnit_Framework_MockObject_MockObject */ - protected $dataObjectProcessorMock; + protected $swaggerGeneratorMock; const SERVICE_METHOD = 'testMethod'; const SERVICE_ID = 'Magento\Webapi\Controller\TestService'; - protected function mockArguments() + protected function setUp() { $this->_requestMock = $this->getMockBuilder('Magento\Framework\Webapi\Rest\Request') - ->setMethods(['isSecure', 'getRequestData'])->disableOriginalConstructor()->getMock(); + ->setMethods(['isSecure', 'getRequestData', 'getParams', 'getParam', 'getRequestedServices'])->disableOriginalConstructor()->getMock(); $this->_responseMock = $this->getMockBuilder('Magento\Framework\Webapi\Rest\Response') - ->setMethods(['sendResponse', 'getHeaders', 'prepareResponse'])->disableOriginalConstructor()->getMock(); - $this->_routerMock = $this->getMockBuilder('Magento\Webapi\Controller\Rest\Router')->setMethods(['match']) + ->setMethods(['sendResponse', 'prepareResponse'])->disableOriginalConstructor()->getMock(); + $routerMock = $this->getMockBuilder('Magento\Webapi\Controller\Rest\Router')->setMethods(['match']) ->disableOriginalConstructor()->getMock(); $this->_routeMock = $this->getMockBuilder('Magento\Webapi\Controller\Rest\Router\Route') ->setMethods(['isSecure', 'getServiceMethod', 'getServiceClass', 'getAclResources', 'getParameters']) ->disableOriginalConstructor()->getMock(); - $this->_objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface'); + $objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface'); $this->_serviceMock = $this->getMockBuilder(self::SERVICE_ID)->setMethods([self::SERVICE_METHOD]) ->disableOriginalConstructor()->getMock(); - $this->_appStateMock = $this->getMockBuilder('Magento\Framework\App\State') - ->disableOriginalConstructor()->getMock(); $this->_oauthServiceMock = $this->getMockBuilder('\Magento\Framework\Oauth\OauthInterface') ->setMethods(['validateAccessTokenRequest'])->getMockForAbstractClass(); $this->_authorizationMock = $this->getMockBuilder('Magento\Framework\AuthorizationInterface') ->disableOriginalConstructor()->getMock(); - $this->paramsOverriderMock = $this->getMockBuilder('Magento\Webapi\Controller\Rest\ParamsOverrider') + $paramsOverriderMock = $this->getMockBuilder('Magento\Webapi\Controller\Rest\ParamsOverrider') ->setMethods(['overrideParams']) ->disableOriginalConstructor()->getMock(); - $this->dataObjectProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\DataObjectProcessor') + $dataObjectProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\DataObjectProcessor') ->disableOriginalConstructor()->setMethods(['getMethodReturnType'])->getMockForAbstractClass(); - } - - protected function setUp() - { - $this->mockArguments(); + $this->swaggerGeneratorMock = $this->getMockBuilder('Magento\Webapi\Model\Rest\Swagger\Generator') + ->disableOriginalConstructor() + ->setMethods(['generate', 'getListOfServices']) + ->getMockForAbstractClass(); $layoutMock = $this->getMockBuilder('Magento\Framework\View\LayoutInterface') ->disableOriginalConstructor()->getMock(); @@ -135,43 +103,93 @@ protected function setUp() $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->serviceInputProcessorMock = $this->getMockBuilder('\Magento\Framework\Webapi\ServiceInputProcessor') ->disableOriginalConstructor()->setMethods(['process'])->getMock(); - $this->areaListMock = $this->getMock('\Magento\Framework\App\AreaList', [], [], '', false); - $this->areaMock = $this->getMock('Magento\Framework\App\AreaInterface'); - $this->areaListMock->expects($this->any())->method('getArea')->will($this->returnValue($this->areaMock)); + $areaListMock = $this->getMock('\Magento\Framework\App\AreaList', [], [], '', false); + $areaMock = $this->getMock('Magento\Framework\App\AreaInterface'); + $areaListMock->expects($this->any())->method('getArea')->will($this->returnValue($areaMock)); /** Init SUT. */ $this->_restController = $objectManager->getObject('Magento\Webapi\Controller\Rest', [ 'request' => $this->_requestMock, 'response' => $this->_responseMock, - 'router' => $this->_routerMock, - 'objectManager' => $this->_objectManagerMock, - 'appState' => $this->_appStateMock, + 'router' => $routerMock, + 'objectManager' => $objectManagerMock, 'layout' => $layoutMock, 'oauthService' => $this->_oauthServiceMock, 'authorization' => $this->_authorizationMock, 'serviceInputProcessor' => $this->serviceInputProcessorMock, 'errorProcessor' => $errorProcessorMock, - 'areaList' => $this->areaListMock, - 'paramsOverrider' => $this->paramsOverriderMock, - 'dataObjectProcessor' => $this->dataObjectProcessorMock + 'areaList' => $areaListMock, + 'paramsOverrider' => $paramsOverriderMock, + 'dataObjectProcessor' => $dataObjectProcessorMock, + 'swaggerGenerator' => $this->swaggerGeneratorMock ] ); // Set default expectations used by all tests $this->_routeMock->expects($this->any())->method('getServiceClass')->will($this->returnValue(self::SERVICE_ID)); $this->_routeMock->expects($this->any())->method('getServiceMethod') ->will($this->returnValue(self::SERVICE_METHOD)); - $this->_routerMock->expects($this->any())->method('match')->will($this->returnValue($this->_routeMock)); - $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnValue($this->_serviceMock)); + $routerMock->expects($this->any())->method('match')->will($this->returnValue($this->_routeMock)); + $objectManagerMock->expects($this->any())->method('get')->will($this->returnValue($this->_serviceMock)); $this->_responseMock->expects($this->any())->method('prepareResponse')->will($this->returnValue([])); $this->_serviceMock->expects($this->any())->method(self::SERVICE_METHOD)->will($this->returnValue(null)); - $this->dataObjectProcessorMock->expects($this->any())->method('getMethodReturnType') + $dataObjectProcessorMock->expects($this->any())->method('getMethodReturnType') ->with(self::SERVICE_ID, self::SERVICE_METHOD) ->will($this->returnValue('null')); - $this->paramsOverriderMock->expects($this->any())->method('overrideParams')->will($this->returnValue([])); + $paramsOverriderMock->expects($this->any())->method('overrideParams')->will($this->returnValue([])); parent::setUp(); } + public function testDispatchSchemaRequest() + { + $params = [ + \Magento\Webapi\Controller\Rest::REQUEST_PARAM_SCHEMA => 1, + \Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES => 'foo', + ]; + $this->_requestMock->expects($this->any()) + ->method('getParam') + ->will($this->returnValue(\Magento\Webapi\Controller\Rest::REQUEST_PARAM_SCHEMA, 1)); + $this->_requestMock->expects($this->any()) + ->method('getParams') + ->will($this->returnValue($params)); + $schema = 'Some WSDL content'; + $this->swaggerGeneratorMock->expects($this->any())->method('generate')->will($this->returnValue($schema)); + + $this->_restController->dispatch($this->_requestMock); + $this->assertEquals($schema, $this->_responseMock->getBody()); + } + + public function testDispatchAllSchemaRequest() + { + $params = [ + \Magento\Webapi\Controller\Rest::REQUEST_PARAM_SCHEMA => 1, + \Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES => 'all', + ]; + $this->_requestMock->expects($this->any()) + ->method('getParam') + ->will( + $this->returnValueMap( + [ + [\Magento\Webapi\Controller\Rest::REQUEST_PARAM_SCHEMA, null, 1], + [\Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES, null, 'all'] + ] + ) + ); + $this->_requestMock->expects($this->any()) + ->method('getParams') + ->will($this->returnValue($params)); + $this->_requestMock->expects($this->any()) + ->method('getRequestedServices') + ->will($this->returnValue('all')); + $schema = 'Some WSDL content'; + $this->swaggerGeneratorMock->expects($this->any())->method('generate')->will($this->returnValue($schema)); + $this->swaggerGeneratorMock->expects($this->once())->method('getListOfServices') + ->willReturn(['listOfServices']); + + $this->_restController->dispatch($this->_requestMock); + $this->assertEquals($schema, $this->_responseMock->getBody()); + } + /** * Test Secure Request and Secure route combinations * 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 43dc35c0b0364..d5789ee98aad3 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 @@ -9,7 +9,7 @@ namespace Magento\Webapi\Test\Unit\Controller\Soap\Request; use Magento\Framework\Api\SimpleDataObjectConverter; -use Magento\Webapi\Model\Soap\Config as SoapConfig; +use Magento\Webapi\Model\ServiceMetadata; /** * Test for \Magento\Webapi\Controller\Soap\Request\Handler. @@ -25,7 +25,7 @@ class HandlerTest extends \PHPUnit_Framework_TestCase /** @var \PHPUnit_Framework_MockObject_MockObject */ protected $_apiConfigMock; - /** @var \Magento\Webapi\Controller\Soap\Request */ + /** @var \Magento\Framework\Webapi\Request */ protected $_requestMock; /** @var \PHPUnit_Framework_MockObject_MockObject */ @@ -51,7 +51,7 @@ protected function setUp() /** Prepare mocks for SUT constructor. */ $this->_apiConfigMock = $this->getMockBuilder('Magento\Webapi\Model\Soap\Config') ->setMethods(['getServiceMethodInfo'])->disableOriginalConstructor()->getMock(); - $this->_requestMock = $this->getMock('Magento\Webapi\Controller\Soap\Request', [], [], '', false); + $this->_requestMock = $this->getMock('Magento\Framework\Webapi\Request', [], [], '', false); $this->_objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface'); $this->_authorizationMock = $this->getMock('Magento\Framework\AuthorizationInterface', [], [], '', false); $this->_dataObjectConverter = $this->getMock( @@ -115,10 +115,10 @@ public function testCall() ->will( $this->returnValue( [ - SoapConfig::KEY_CLASS => $className, - SoapConfig::KEY_METHOD => $methodName, - SoapConfig::KEY_IS_SECURE => $isSecure, - SoapConfig::KEY_ACL_RESOURCES => $aclResources, + ServiceMetadata::KEY_CLASS => $className, + ServiceMetadata::KEY_METHOD => $methodName, + ServiceMetadata::KEY_IS_SECURE => $isSecure, + ServiceMetadata::KEY_ACL_RESOURCES => $aclResources, ] ) ); diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/Soap/RequestTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/Soap/RequestTest.php deleted file mode 100644 index f896fb653e15c..0000000000000 --- a/app/code/Magento/Webapi/Test/Unit/Controller/Soap/RequestTest.php +++ /dev/null @@ -1,110 +0,0 @@ -getMock('Magento\Framework\App\AreaList', [], [], '', false); - $areaListMock->expects($this->once())->method('getFrontName')->will($this->returnValue('soap')); - - /** Initialize SUT. */ - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->_soapRequest = $objectManager->getObject( - 'Magento\Webapi\Controller\Soap\Request', - [ - 'areaList' => $areaListMock - ] - ); - - parent::setUp(); - } - - protected function tearDown() - { - unset($this->_soapRequest); - parent::tearDown(); - } - - public function testGetRequestedServicesNotAllowedParametersException() - { - /** Prepare mocks for SUT constructor. */ - $wsdlParam = \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL; - $servicesParam = \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_SERVICES; - // Set two not allowed parameters and all allowed - $requestParams = ['param_1' => 'foo', 'param_2' => 'bar', $wsdlParam => true, $servicesParam => true]; - $this->_soapRequest->setParams($requestParams); - $exceptionMessage = 'Not allowed parameters: param_1, param_2. Please use only wsdl and services.'; - /** Execute SUT. */ - try { - $this->_soapRequest->getRequestedServices(); - $this->fail("Exception is expected to be raised"); - } catch (\Magento\Framework\Webapi\Exception $e) { - $this->assertInstanceOf('Magento\Framework\Webapi\Exception', $e, 'Exception type is invalid'); - $this->assertEquals($exceptionMessage, $e->getMessage(), 'Exception message is invalid'); - $this->assertEquals( - \Magento\Framework\Webapi\Exception::HTTP_BAD_REQUEST, - $e->getHttpCode(), - 'HTTP code is invalid' - ); - } - } - - public function testGetRequestedServicesEmptyRequestedServicesException() - { - /** Prepare mocks for SUT constructor. */ - $requestParams = [\Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_SERVICES => null]; - $this->_soapRequest->setParams($requestParams); - $exceptionMessage = 'Incorrect format of WSDL request URI or Requested services are missing.'; - /** Execute SUT. */ - try { - $this->_soapRequest->getRequestedServices(); - $this->fail("Exception is expected to be raised"); - } catch (\Magento\Framework\Webapi\Exception $e) { - $this->assertInstanceOf('Magento\Framework\Webapi\Exception', $e, 'Exception type is invalid'); - $this->assertEquals($exceptionMessage, $e->getMessage(), 'Exception message is invalid'); - $this->assertEquals( - \Magento\Framework\Webapi\Exception::HTTP_BAD_REQUEST, - $e->getHttpCode(), - 'HTTP code is invalid' - ); - } - } - - /** - * @dataProvider providerTestGetRequestedServicesSuccess - * @param $requestParamServices - * @param $expectedResult - */ - public function testGetRequestedServicesSuccess($requestParamServices, $expectedResult) - { - $requestParams = [ - \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL => true, - \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_SERVICES => $requestParamServices, - ]; - $this->_soapRequest->setParams($requestParams); - $this->assertEquals($expectedResult, $this->_soapRequest->getRequestedServices()); - } - - public function providerTestGetRequestedServicesSuccess() - { - $testModuleA = 'testModule1AllSoapAndRestV1'; - $testModuleB = 'testModule1AllSoapAndRestV2'; - $testModuleC = 'testModule2AllSoapNoRestV1'; - return [ - ["{$testModuleA},{$testModuleB}", [$testModuleA, $testModuleB]], - ["{$testModuleA},{$testModuleC}", [$testModuleA, $testModuleC]], - ["{$testModuleA}", [$testModuleA]] - ]; - } -} diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/SoapTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/SoapTest.php index b65d6f2929477..1266bb53ce614 100644 --- a/app/code/Magento/Webapi/Test/Unit/Controller/SoapTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Controller/SoapTest.php @@ -25,7 +25,7 @@ class SoapTest extends \PHPUnit_Framework_TestCase protected $_wsdlGeneratorMock; /** - * @var \Magento\Webapi\Controller\Soap\Request + * @var \Magento\Framework\Webapi\Request */ protected $_requestMock; @@ -64,9 +64,9 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['generate']) ->getMock(); - $this->_requestMock = $this->getMockBuilder('Magento\Webapi\Controller\Soap\Request') + $this->_requestMock = $this->getMockBuilder('Magento\Framework\Webapi\Request') ->disableOriginalConstructor() - ->setMethods(['getParam', 'getRequestedServices']) + ->setMethods(['getParams', 'getParam', 'getRequestedServices']) ->getMock(); $this->_responseMock = $this->getMockBuilder('Magento\Framework\Webapi\Response') ->disableOriginalConstructor() @@ -122,7 +122,14 @@ protected function setUp() */ public function testDispatchWsdl() { + $params = [ + \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL => 1, + \Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES => 'foo', + ]; $this->_mockGetParam(\Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL, 1); + $this->_requestMock->expects($this->once()) + ->method('getParams') + ->will($this->returnValue($params)); $wsdl = 'Some WSDL content'; $this->_wsdlGeneratorMock->expects($this->any())->method('generate')->will($this->returnValue($wsdl)); @@ -130,6 +137,48 @@ public function testDispatchWsdl() $this->assertEquals($wsdl, $this->_responseMock->getBody()); } + public function testDispatchInvalidWsdlRequest() + { + $params = [ + \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL => 1, + 'param_1' => 'foo', + 'param_2' => 'bar,' + ]; + $this->_mockGetParam(\Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL, 1); + $this->_requestMock->expects($this->once()) + ->method('getParams') + ->will($this->returnValue($params)); + $this->_errorProcessorMock->expects( + $this->any() + )->method( + 'maskException' + )->will( + $this->returnValue(new \Magento\Framework\Webapi\Exception(__('message'))) + ); + $wsdl = 'Some WSDL content'; + $this->_wsdlGeneratorMock->expects($this->any())->method('generate')->will($this->returnValue($wsdl)); + $encoding = "utf-8"; + $this->_soapServerMock->expects($this->any())->method('getApiCharset')->will($this->returnValue($encoding)); + $this->_soapController->dispatch($this->_requestMock); + + $expectedMessage = << + + + + + env:Sender + + + message + + + + +EXPECTED_MESSAGE; + $this->assertXmlStringEqualsXmlString($expectedMessage, $this->_responseMock->getBody()); + } + /** * Test successful SOAP action request dispatch. */ @@ -187,7 +236,7 @@ public function testDispatchWithException() protected function _mockGetParam($param, $value) { $this->_requestMock->expects( - $this->once() + $this->any() )->method( 'getParam' )->with( diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Soap/Config/ClassReflectorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Config/ClassReflectorTest.php similarity index 92% rename from app/code/Magento/Webapi/Test/Unit/Model/Soap/Config/ClassReflectorTest.php rename to app/code/Magento/Webapi/Test/Unit/Model/Config/ClassReflectorTest.php index cf94b5264c2b6..4e024140231c7 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Soap/Config/ClassReflectorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Config/ClassReflectorTest.php @@ -3,7 +3,7 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Webapi\Test\Unit\Model\Soap\Config; +namespace Magento\Webapi\Test\Unit\Model\Config; /** * Test for class reflector. @@ -13,7 +13,7 @@ class ClassReflectorTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Framework\Reflection\TypeProcessor|\PHPUnit_Framework_MockObject_MockObject */ protected $_typeProcessor; - /** @var \Magento\Webapi\Model\Soap\Config\ClassReflector */ + /** @var \Magento\Webapi\Model\Config\ClassReflector */ protected $_classReflector; /** @@ -35,7 +35,7 @@ protected function setUp() )->will( $this->returnValueMap([['string', 'str'], ['int', 'int']]) ); - $this->_classReflector = new \Magento\Webapi\Model\Soap\Config\ClassReflector($this->_typeProcessor); + $this->_classReflector = new \Magento\Webapi\Model\Config\ClassReflector($this->_typeProcessor); } public function testReflectClassMethods() diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php new file mode 100644 index 0000000000000..e710d682bdfb2 --- /dev/null +++ b/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php @@ -0,0 +1,426 @@ +serviceMetadataMock = $this->getMockBuilder( + 'Magento\Webapi\Model\ServiceMetadata' + )->disableOriginalConstructor()->getMock(); + + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $swagger = $this->objectManager->getObject('Magento\Webapi\Model\Rest\Swagger'); + $this->swaggerFactoryMock = $this->getMockBuilder( + 'Magento\Webapi\Model\Rest\SwaggerFactory' + )->setMethods( + ['create'] + )->disableOriginalConstructor()->getMock(); + $this->swaggerFactoryMock->expects($this->any())->method('create')->will($this->returnValue($swagger)); + + $this->cacheMock = $this->getMockBuilder( + 'Magento\Framework\App\Cache\Type\Webapi' + )->disableOriginalConstructor()->getMock(); + $this->cacheMock->expects($this->any())->method('load')->will($this->returnValue(false)); + $this->cacheMock->expects($this->any())->method('save')->will($this->returnValue(true)); + + $this->typeProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\TypeProcessor') + ->disableOriginalConstructor() + ->getMock(); + $this->typeProcessorMock->expects($this->any()) + ->method('getOperationName') + ->will($this->returnValue(self::OPERATION_NAME)); + + $this->customAttributeTypeLocatorMock = $this->getMockBuilder( + 'Magento\Framework\Webapi\CustomAttributeTypeLocatorInterface' + )->disableOriginalConstructor() + ->getMock(); + $this->customAttributeTypeLocatorMock->expects($this->any()) + ->method('getAllServiceDataInterfaces') + ->willReturn(['$customAttributeClass']); + + $this->storeManagerMock = $this->getMockBuilder( + 'Magento\Store\Model\StoreManagerInterface' + )->setMethods(['getStore'])->disableOriginalConstructor()->getMockForAbstractClass(); + + $storeMock = $this->getMockBuilder( + 'Magento\Store\Model\Store' + )->disableOriginalConstructor()->getMock(); + + $this->storeManagerMock->expects($this->any()) + ->method('getStore') + ->will($this->returnValue($storeMock)); + + $storeMock->expects($this->any()) + ->method('getCode') + ->will($this->returnValue('store_code')); + + $this->generator = $this->objectManager->getObject( + 'Magento\Webapi\Model\Rest\Swagger\Generator', + [ + 'swaggerFactory' => $this->swaggerFactoryMock, + 'cache' => $this->cacheMock, + 'typeProcessor' => $this->typeProcessorMock, + 'storeManager' => $this->storeManagerMock, + 'serviceMetadata' => $this->serviceMetadataMock, + 'customAttributeTypeLocator' => $this->customAttributeTypeLocatorMock, + ] + ); + } + + /** + * @param string[] $serviceMetadata + * @param string[] $typeData + * @param string $schema + * @dataProvider generateDataProvider + */ + public function testGenerate($serviceMetadata, $typeData, $schema) + { + $service = 'testModule5AllSoapAndRestV2'; + $requestedService = [$service]; + + $this->serviceMetadataMock->expects($this->any()) + ->method('getRouteMetadata') + ->willReturn($serviceMetadata); + $this->typeProcessorMock->expects($this->any()) + ->method('getTypeData') + ->willReturnMap( + [ + ['TestModule5V2EntityAllSoapAndRest', $typeData], + ] + ); + + $this->typeProcessorMock->expects($this->any()) + ->method('isTypeSimple') + ->willReturnMap( + [ + ['int', true], + ] + ); + + $basePath = '/rest/default'; + $this->assertEquals( + $schema, + $this->generator->generate( + $requestedService, + 'http://', + 'magento.host', + $basePath . '?swagger=1&services=' . $service + ) + ); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function generateDataProvider() + { + return [ + [ + [ + 'methods' => [ + 'create' => [ + 'method' => 'create', + 'inputRequired' => false, + 'isSecure' => false, + 'resources' => ['Magento_TestModule5::resource3'], + 'documentation' => 'Add new item.', + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'item' => [ + 'type' => 'TestModule5V2EntityAllSoapAndRest', + 'documentation' => null, + 'required' => true, + ], + ], + ], + 'out' => [ + 'parameters' => [ + 'result' => [ + 'type' => 'TestModule5V2EntityAllSoapAndRest', + 'documentation' => null, + 'required' => true, + ], + ], + 'throws' => ['\Magento\Framework\Exception\LocalizedException'], + ], + ], + ], + ], + 'class' => 'Magento\TestModule5\Service\V2\AllSoapAndRestInterface', + 'description' => 'AllSoapAndRestInterface', + 'routes' => [ + '/V1/testModule5' => [ + 'POST' => [ + 'method' => 'create', + 'parameters' => [], + ], + ], + ], + ], + [ + 'documentation' => 'Some Data Object', + 'parameters' => [ + 'price' => [ + 'type' => 'int', + 'required' => true, + 'documentation' => "" + ] + ] + ], + // @codingStandardsIgnoreStart + '{"swagger":"2.0","info":{"version":"","title":""},"host":"magento.host","basePath":"/rest/default","schemes":["http://"],"tags":[{"name":"testModule5AllSoapAndRestV2","description":"AllSoapAndRestInterface"}],"paths":{"/V1/testModule5":{"post":{"tags":["testModule5AllSoapAndRestV2"],"description":"Add new item.","operationId":"' . self::OPERATION_NAME . 'Post","parameters":[{"name":"$body","in":"body","schema":{"required":["item"],"properties":{"item":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}}}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}}},"definitions":{"error-response":{"type":"object","properties":{"message":{"type":"string","description":"Error message"},"errors":{"$ref":"#/definitions/error-errors"},"code":{"type":"integer","description":"Error code"},"parameters":{"$ref":"#/definitions/error-parameters"},"trace":{"type":"string","description":"Stack trace"}},"required":["message"]},"error-errors":{"type":"array","description":"Errors list","items":{"$ref":"#/definitions/error-errors-item"}},"error-errors-item":{"type":"object","description":"Error details","properties":{"message":{"type":"string","description":"Error message"},"parameters":{"$ref":"#/definitions/error-parameters"}}},"error-parameters":{"type":"array","description":"Error parameters list","items":{"$ref":"#/definitions/error-parameters-item"}},"error-parameters-item":{"type":"object","description":"Error parameters item","properties":{"resources":{"type":"string","description":"ACL resource"},"fieldName":{"type":"string","description":"Missing or invalid field name"},"fieldValue":{"type":"string","description":"Incorrect field value"}}},"test-module5-v2-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object","properties":{"price":{"type":"integer"}},"required":["price"]}}}' + // @codingStandardsIgnoreEnd + ], + [ + [ + 'methods' => [ + 'items' => [ + 'method' => 'items', + 'inputRequired' => false, + 'isSecure' => false, + 'resources' => ['Magento_TestModule5::resource1'], + 'documentation' => 'Retrieve existing item.', + 'interface' => [ + 'out' => [ + 'parameters' => [ + 'result' => [ + 'type' => 'TestModule5V2EntityAllSoapAndRest', + 'documentation' => "", + 'required' => true, + ], + ], + 'throws' => ['\Magento\Framework\Exception\LocalizedException'], + ], + ], + ], + ], + 'class' => 'Magento\TestModule5\Service\V2\AllSoapAndRestInterface', + 'description' => 'AllSoapAndRestInterface', + 'routes' => [ + '/V1/testModule5' => [ + 'GET' => [ + 'method' => 'items', + 'parameters' => [], + ], + ], + ], + ], + [ + 'documentation' => 'Some Data Object', + 'parameters' => [ + 'price' => [ + 'type' => 'int', + 'required' => true, + 'documentation' => "" + ] + ] + ], + // @codingStandardsIgnoreStart + '{"swagger":"2.0","info":{"version":"","title":""},"host":"magento.host","basePath":"/rest/default","schemes":["http://"],"tags":[{"name":"testModule5AllSoapAndRestV2","description":"AllSoapAndRestInterface"}],"paths":{"/V1/testModule5":{"get":{"tags":["testModule5AllSoapAndRestV2"],"description":"Retrieve existing item.","operationId":"' . self::OPERATION_NAME . 'Get","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}}},"definitions":{"error-response":{"type":"object","properties":{"message":{"type":"string","description":"Error message"},"errors":{"$ref":"#/definitions/error-errors"},"code":{"type":"integer","description":"Error code"},"parameters":{"$ref":"#/definitions/error-parameters"},"trace":{"type":"string","description":"Stack trace"}},"required":["message"]},"error-errors":{"type":"array","description":"Errors list","items":{"$ref":"#/definitions/error-errors-item"}},"error-errors-item":{"type":"object","description":"Error details","properties":{"message":{"type":"string","description":"Error message"},"parameters":{"$ref":"#/definitions/error-parameters"}}},"error-parameters":{"type":"array","description":"Error parameters list","items":{"$ref":"#/definitions/error-parameters-item"}},"error-parameters-item":{"type":"object","description":"Error parameters item","properties":{"resources":{"type":"string","description":"ACL resource"},"fieldName":{"type":"string","description":"Missing or invalid field name"},"fieldValue":{"type":"string","description":"Incorrect field value"}}},"test-module5-v2-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object","properties":{"price":{"type":"integer"}},"required":["price"]}}}' + // @codingStandardsIgnoreEnd + ], + ]; + } + + /** + * @param string $typeName + * @param array $result + * @dataProvider testGetObjectSchemaDataProvider + */ + public function testGetObjectSchema($typeName, $description, $result) + { + $property = new \ReflectionProperty($this->generator, 'definitions'); + $property->setAccessible(true); + $property->setValue($this->generator, ['customer-data-customer-interface' => []]); + + $method = new \ReflectionMethod($this->generator, 'getObjectSchema'); + $method->setAccessible(true); + $actual = $method->invoke($this->generator, $typeName, $description); + + $this->assertSame(json_encode($result), json_encode($actual)); + } + + public function testGetObjectSchemaDataProvider() + { + return [ + [ + 'string', + '', + ['type' => 'string'] + ], + [ + 'string[]', + '', + ['type' => 'array', 'items' => ['type' => 'string']] + ], + [ + 'CustomerDataCustomerInterface', + '', + ['$ref' => '#/definitions/customer-data-customer-interface'] + ], + [ + 'CustomerDataCustomerInterface[]', + '', + ['type' => 'array', 'items' => ['$ref' => '#/definitions/customer-data-customer-interface']] + ], + [ + 'CustomerDataCustomerInterface[]', + 'Customer interface', + [ + 'type' => 'array', + 'description' => 'Customer interface', + 'items' => ['$ref' => '#/definitions/customer-data-customer-interface']], + ] + ]; + } + + /** + * @param array $typeData + * @param array $expected + * @dataProvider testGenerateDefinitionDataProvider + */ + public function testGenerateDefinition($typeData, $expected) + { + $getTypeData = function ($type) use ($typeData) { + return $typeData[$type]; + }; + + $this->typeProcessorMock + ->method('getTypeData') + ->will($this->returnCallback($getTypeData)); + + $method = new \ReflectionMethod($this->generator, 'generateDefinition'); + $method->setAccessible(true); + $actual = $method->invoke($this->generator, key($typeData)); + + ksort($expected); + ksort($actual); + + $this->assertSame(json_encode($expected), json_encode($actual)); + } + + public function testGenerateDefinitionDataProvider() + { + return [ + [ + [ + 'CustomerDataCustomerInterface' => [ + 'documentation' => 'Customer entity', + 'parameters' => [ + 'id' => [ + 'type' => 'int', + 'required' => false, + 'documentation' => 'Customer id' + ], + 'group_id' => [ + 'type' => 'int', + 'required' => false, + 'documentation' => 'Customer group ID' + ], + 'email' => [ + 'type' => 'string', + 'required' => false, + 'documentation' => 'Customer email' + ], + 'addresses' => [ + 'type' => 'CustomerDataAddressInterface[]', + 'required' => false, + 'documentation' => 'Customer addresses' + ] + ] + ], + 'CustomerDataAddressInterface' => [ + 'documentation' => 'Customer entity', + 'parameters' => [ + 'id' => [ + 'type' => 'int', + 'required' => false, + 'documentation' => 'Customer id' + ], + 'group_id' => [ + 'type' => 'int', + 'required' => false, + 'documentation' => 'Customer group ID' + ], + ] + ] + ], + [ + 'type' => 'object', + 'description' => 'Customer entity', + 'properties' => [ + 'id' => [ + 'type' => 'integer', + 'description' => 'Customer id' + ], + 'group_id' => [ + 'type' => 'integer', + 'description' => 'Customer group ID' + ], + 'email' => [ + 'type' => 'string', + 'description' => 'Customer email', + ], + 'addresses' => [ + 'type' => 'array', + 'description' => 'Customer addresses', + 'items' => [ + '$ref' => '#/definitions/customer-data-address-interface' + ] + ] + ] + ] + ] + ]; + } + + public function testGetDefinitionReference() + { + $method = new \ReflectionMethod($this->generator, 'getDefinitionReference'); + $method->setAccessible(true); + $actual = $method->invoke($this->generator, 'CustomerDataAddressInterface'); + + $this->assertEquals('#/definitions/customer-data-address-interface', $actual); + } +} diff --git a/app/code/Magento/Webapi/Test/Unit/Model/ServiceMetadataTest.php b/app/code/Magento/Webapi/Test/Unit/Model/ServiceMetadataTest.php new file mode 100644 index 0000000000000..56533b14ac4b2 --- /dev/null +++ b/app/code/Magento/Webapi/Test/Unit/Model/ServiceMetadataTest.php @@ -0,0 +1,293 @@ + [ + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'customerId' => [ + 'force' => true, + 'value' => '%customer_id%', + ], + 'requiredInputParameter' => [ + 'required' => true, + ], + ], + ], + 'out' => [ + 'parameters' => [ + 'outputParameter' => [ + 'type' => 'string', + ], + ], + ], + ], + ], + ]; + $classReflection = $this->getMock( + 'Magento\Webapi\Model\Config\ClassReflector', + ['reflectClassMethods', 'extractClassDescription'], + [], + '', + false + ); + $classReflection->expects($this->any()) + ->method('reflectClassMethods') + ->will($this->returnValue($interfaceParameters)); + $classReflection->expects($this->any()) + ->method('extractClassDescription') + ->will($this->returnValue('classDescription')); + + $servicesConfig = [ + 'services' => [ + 'Magento\Customer\Api\AccountManagementInterface' => [ + 'V1' => [ + 'methods' => [ + 'activateById' => [ + 'resources' => [ + [ + 'Magento_Customer::manage', + ], + ], + 'secure' => false, + ], + ], + ], + ], + 'Magento\Customer\Api\CustomerRepositoryInterface' => [ + 'V1' => [ + 'methods' => [ + 'getById' => [ + 'resources' => [ + [ + 'Magento_Customer::customer', + ], + ], + 'secure' => false, + ], + ], + ], + ], + ], + 'routes' => [ + '/V1/customers/me/activate' => [ + 'PUT' => [ + 'secure' => false, + 'service' => [ + 'class' => 'Magento\Customer\Api\AccountManagementInterface', + 'method' => 'activateById', + ], + 'resources' => [ + 'self' => true, + ], + 'parameters' => [ + 'customerId' => [ + 'force' => true, + 'value' => '%customer_id%', + ], + ], + ], + ], + '/V1/customers/:customerId' => [ + 'GET' => [ + 'secure' => false, + 'service' => [ + 'class' => 'Magento\Customer\Api\CustomerRepositoryInterface', + 'method' => 'getById', + ], + 'resources' => [ + 'Magento_Customer::customer' => true, + ], + 'parameters' => [ + ], + ], + ], + ] + ]; + + /** + * @var $cacheMock \Magento\Framework\App\Cache\Type\Webapi + */ + $cacheMock = $this->getMockBuilder('Magento\Framework\App\Cache\Type\Webapi') + ->disableOriginalConstructor() + ->getMock(); + + /** @var $readerMock \Magento\Webapi\Model\Config\Reader */ + $readerMock = $this->getMockBuilder('Magento\Webapi\Model\Config\Reader') + ->disableOriginalConstructor() + ->getMock(); + $readerMock->expects($this->any())->method('read')->will($this->returnValue($servicesConfig)); + + /** @var $config \Magento\Webapi\Model\Config */ + $config = new \Magento\Webapi\Model\Config($cacheMock, $readerMock); + + /** @var $config \Magento\Webapi\Model\ServiceMetadata */ + $this->serviceMetadata = new \Magento\Webapi\Model\ServiceMetadata($config, $cacheMock, $classReflection); + + parent::setUp(); + } + + /** + * Test identifying service name including subservices using class name. + * + * @dataProvider serviceNameDataProvider + */ + public function testGetServiceName($className, $version, $preserveVersion, $expected) + { + $actual = $this->serviceMetadata->getServiceName($className, $version, $preserveVersion); + $this->assertEquals($expected, $actual); + } + + /** + * Dataprovider for testGetServiceName + * + * @return string + */ + public function serviceNameDataProvider() + { + return [ + ['Magento\Customer\Api\AccountManagementInterface', 'V1', false, 'customerAccountManagement'], + ['Magento\Customer\Api\AddressRepositoryInterface', 'V1', true, 'customerAddressRepositoryV1'], + ]; + } + + /** + * @expectedException \InvalidArgumentException + * @dataProvider dataProviderForTestGetServiceNameInvalidName + */ + public function testGetServiceNameInvalidName($interfaceClassName, $version) + { + $this->serviceMetadata->getServiceName($interfaceClassName, $version); + } + + /** + * Dataprovider for testGetServiceNameInvalidName + * + * @return string + */ + public function dataProviderForTestGetServiceNameInvalidName() + { + return [ + ['BarV1Interface', 'V1'], // Missed vendor, module, 'Service' + ['Service\\V1Interface', 'V1'], // Missed vendor and module + ['Magento\\Foo\\Service\\BarVxInterface', 'V1'], // Version number should be a number + ['Magento\\Foo\\Service\\BarInterface', 'V1'], // Version missed + ['Magento\\Foo\\Service\\BarV1', 'V1'], // 'Interface' missed + ['Foo\\Service\\BarV1Interface', 'V1'], // Module missed + ['Foo\\BarV1Interface', 'V1'] // Module and 'Service' missed + ]; + } + + public function testGetServiceMetadata() + { + $expectedResult = [ + 'methods' => [ + 'activateById' => [ + 'method' => 'activateById', + 'inputRequired' => '', + 'isSecure' => '', + 'resources' => [['Magento_Customer::manage']], + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'customerId' => [ + 'force' => true, + 'value' => '%customer_id%', + ], + 'requiredInputParameter' => [ + 'required' => true, + ], + ], + ], + 'out' => [ + 'parameters' => [ + 'outputParameter' => [ + 'type' => 'string', + ], + ], + ], + ], + ], + ], + 'class' => 'Magento\Customer\Api\AccountManagementInterface', + 'description' => 'classDescription', + ]; + $result = $this->serviceMetadata->getServiceMetadata('customerAccountManagementV1'); + $this->assertEquals($expectedResult, $result); + } + + public function testGetRouteMetadata() + { + $expectedResult = [ + 'methods' => [ + 'activateById' => [ + 'method' => 'activateById', + 'inputRequired' => '', + 'isSecure' => '', + 'resources' => [['Magento_Customer::manage']], + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'customerId' => [ + 'force' => true, + 'value' => '%customer_id%', + ], + 'requiredInputParameter' => [ + 'required' => true, + ], + ], + ], + 'out' => [ + 'parameters' => [ + 'outputParameter' => [ + 'type' => 'string', + ], + ], + ], + ], + ], + ], + 'class' => 'Magento\Customer\Api\AccountManagementInterface', + 'description' => 'classDescription', + 'routes' => [ + '/V1/customers/me/activate' => [ + 'PUT' => [ + 'method' => 'activateById', + 'parameters' => [ + 'customerId' => [ + 'force' => true, + 'value' => '%customer_id%' + ] + ] + ] + ] + ] + ]; + $result = $this->serviceMetadata->getRouteMetadata('customerAccountManagementV1'); + $this->assertEquals($expectedResult, $result); + } +} + +require_once realpath(__DIR__ . '/../_files/test_interfaces.php'); diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php index 6c747b1f54a97..e2241e9466ba6 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php @@ -23,18 +23,22 @@ class ConfigTest extends \PHPUnit_Framework_TestCase */ protected function setUp() { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $typeProcessor = $objectManager->getObject('Magento\Framework\Reflection\TypeProcessor'); + $objectManagerMock = $this->getMockBuilder( 'Magento\Framework\App\ObjectManager' )->disableOriginalConstructor()->getMock(); + $fileSystemMock = $this->getMockBuilder('Magento\Framework\Filesystem') ->disableOriginalConstructor() ->getMock(); $classReflection = $this->getMock( - 'Magento\Webapi\Model\Soap\Config\ClassReflector', + 'Magento\Webapi\Model\Config\ClassReflector', ['reflectClassMethods'], - [], - '', - false + ['_typeProcessor' => $typeProcessor], + '' ); $classReflection->expects($this->any())->method('reflectClassMethods')->will($this->returnValue([])); @@ -89,18 +93,19 @@ protected function setUp() $readerMock = $this->getMockBuilder('Magento\Webapi\Model\Config\Reader') ->disableOriginalConstructor() ->getMock(); - $readerMock->expects($this->once())->method('read')->will($this->returnValue($servicesConfig)); + $readerMock->expects($this->any())->method('read')->will($this->returnValue($servicesConfig)); /** @var $config \Magento\Webapi\Model\Config */ $config = new \Magento\Webapi\Model\Config($cacheMock, $readerMock); + /** @var $config \Magento\Webapi\Model\ServiceMetadata */ + $serviceMetadata = new \Magento\Webapi\Model\ServiceMetadata($config, $cacheMock, $classReflection); + $this->_soapConfig = new \Magento\Webapi\Model\Soap\Config( $objectManagerMock, $fileSystemMock, - $config, - $classReflection, - $cacheMock, - $registryMock + $registryMock, + $serviceMetadata ); parent::setUp(); } @@ -119,11 +124,14 @@ public function testGetRequestedSoapServices() ], ], 'class' => 'Magento\Customer\Api\AccountManagementInterface', + 'description' => 'Interface for managing customers accounts.', ], ]; + $result = $this->_soapConfig->getRequestedSoapServices( ['customerAccountManagementV1', 'moduleBarV2', 'moduleBazV1'] ); + $this->assertEquals($expectedResult, $result); } @@ -149,75 +157,6 @@ public function testGetSoapOperation() ->getSoapOperation('Magento\Customer\Api\AccountManagementInterface', 'activate', 'V1'); $this->assertEquals($expectedResult, $soapOperation); } - - /** - * Test identifying service name including subservices using class name. - * - * @dataProvider serviceNameDataProvider - */ - public function testGetServiceName($className, $version, $preserveVersion, $expected) - { - $actual = $this->_soapConfig->getServiceName($className, $version, $preserveVersion); - $this->assertEquals($expected, $actual); - } - - /** - * Dataprovider for testGetServiceName - * - * @return string - */ - public function serviceNameDataProvider() - { - return [ - ['Magento\Customer\Api\AccountManagementInterface', 'V1', false, 'customerAccountManagement'], - ['Magento\Customer\Api\AddressRepositoryInterface', 'V1', true, 'customerAddressRepositoryV1'], - ]; - } - - /** - * @expectedException \InvalidArgumentException - * @dataProvider dataProviderForTestGetServiceNameInvalidName - */ - public function testGetServiceNameInvalidName($interfaceClassName, $version) - { - $this->_soapConfig->getServiceName($interfaceClassName, $version); - } - - /** - * Dataprovider for testGetServiceNameInvalidName - * - * @return string - */ - public function dataProviderForTestGetServiceNameInvalidName() - { - return [ - ['BarV1Interface', 'V1'], // Missed vendor, module, 'Service' - ['Service\\V1Interface', 'V1'], // Missed vendor and module - ['Magento\\Foo\\Service\\BarVxInterface', 'V1'], // Version number should be a number - ['Magento\\Foo\\Service\\BarInterface', 'V1'], // Version missed - ['Magento\\Foo\\Service\\BarV1', 'V1'], // 'Interface' missed - ['Foo\\Service\\BarV1Interface', 'V1'], // Module missed - ['Foo\\BarV1Interface', 'V1'] // Module and 'Service' missed - ]; - } - - public function testGetServiceMetadata() - { - $expectedResult = [ - 'methods' => [ - 'activate' => [ - 'method' => 'activate', - 'inputRequired' => '', - 'isSecure' => '', - 'resources' => [['Magento_Customer::manage']], - ], - ], - 'class' => 'Magento\Customer\Api\AccountManagementInterface', - ]; - $result = $this->_soapConfig->getServiceMetadata('customerAccountManagementV1'); - $this->assertEquals($expectedResult, $result); - - } } require_once realpath(__DIR__ . '/../../_files/test_interfaces.php'); diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Soap/ServerTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Soap/ServerTest.php index ebb1088380509..f91066761b6f4 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Soap/ServerTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Soap/ServerTest.php @@ -15,7 +15,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Store\Model\Store */ protected $_storeMock; - /** @var \Magento\Webapi\Controller\Soap\Request */ + /** @var \Magento\Framework\Webapi\Request */ protected $_requestMock; /** @var \Magento\Store\Model\StoreManagerInterface */ @@ -61,7 +61,7 @@ protected function setUp() $areaListMock->expects($this->any())->method('getFrontName')->will($this->returnValue('soap')); $this->_requestMock = $this->getMockBuilder( - 'Magento\Webapi\Controller\Soap\Request' + 'Magento\Framework\Webapi\Request' )->disableOriginalConstructor()->getMock(); $this->_soapServerFactory = $this->getMockBuilder( diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Soap/Wsdl/GeneratorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Soap/Wsdl/GeneratorTest.php index 1d85bb91709df..a8abc92e908bc 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Soap/Wsdl/GeneratorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Soap/Wsdl/GeneratorTest.php @@ -17,8 +17,8 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase */ protected $customAttributeTypeLocator = null; - /** @var \Magento\Webapi\Model\Soap\Config|\PHPUnit_Framework_MockObject_MockObject */ - protected $_soapConfigMock; + /** @var \Magento\Webapi\Model\ServiceMetadata|\PHPUnit_Framework_MockObject_MockObject */ + protected $serviceMetadata; /** @var \Magento\Webapi\Model\Soap\WsdlFactory|\PHPUnit_Framework_MockObject_MockObject */ protected $_wsdlFactoryMock; @@ -34,8 +34,8 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->_soapConfigMock = $this->getMockBuilder( - 'Magento\Webapi\Model\Soap\Config' + $this->serviceMetadata = $this->getMockBuilder( + 'Magento\Webapi\Model\ServiceMetadata' )->disableOriginalConstructor()->getMock(); $_wsdlMock = $this->getMockBuilder( @@ -101,12 +101,12 @@ protected function setUp() $this->_wsdlGenerator = $objectManager->getObject( 'Magento\Webapi\Model\Soap\Wsdl\Generator', [ - 'apiConfig' => $this->_soapConfigMock, 'wsdlFactory' => $this->_wsdlFactoryMock, 'cache' => $this->_cacheMock, 'typeProcessor' => $this->_typeProcessor, - 'storeManagerMock' => $this->storeManagerMock, - 'customAttributeTypeLocator' => $this->customAttributeTypeLocator + 'storeManager' => $this->storeManagerMock, + 'customAttributeTypeLocator' => $this->customAttributeTypeLocator, + 'serviceMetadata' => $this->serviceMetadata ] ); @@ -153,14 +153,6 @@ public function testGetServiceName() $this->assertEquals("testService", $this->_wsdlGenerator->getServiceName("test")); } - /** - * test getOperationName - */ - public function testGetOperationName() - { - $this->assertEquals("resNameMethodName", $this->_wsdlGenerator->getOperationName("resName", "methodName")); - } - /** * @test */ @@ -188,26 +180,18 @@ public function testHandleWithException() $genWSDL = 'generatedWSDL'; $exceptionMsg = 'exception message'; $requestedService = ['catalogProduct']; + $serviceMetadata = ['methods' => ['methodName' => ['interface' => 'aInterface']]]; - $wsdlGeneratorMock = $this->getMockBuilder( - 'Magento\Webapi\Model\Soap\Wsdl\Generator' - )->setMethods( - ['_collectCallInfo'] - )->setConstructorArgs( - [ - $this->_soapConfigMock, - $this->_wsdlFactoryMock, - $this->_cacheMock, - $this->_typeProcessor, - $this->storeManagerMock, - $this->customAttributeTypeLocator - ] - )->getMock(); - - $wsdlGeneratorMock->expects($this->once()) - ->method('_collectCallInfo') + $this->serviceMetadata->expects($this->any()) + ->method('getServiceMetadata') + ->willReturn($serviceMetadata); + $this->_typeProcessor->expects($this->once()) + ->method('processInterfaceCallInfo') ->willThrowException(new \Magento\Framework\Webapi\Exception(__($exceptionMsg))); - $this->assertEquals($genWSDL, $wsdlGeneratorMock->generate($requestedService, 'http://magento.host')); + $this->assertEquals( + $genWSDL, + $this->_wsdlGenerator->generate($requestedService, 'http://', 'magento.host', '/soap/default') + ); } } diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php index 55243d01690cc..df44a35117567 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php @@ -5,6 +5,10 @@ */ namespace Magento\TestModule5\Service\V1; +/** + * Both SOAP and REST Version ONE + * @package Magento\TestModule5\Service\V1 + */ interface AllSoapAndRestInterface { /** diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php index bcbb0e2a2c0bf..23e3b14c4d02b 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php @@ -13,8 +13,15 @@ */ class AllSoapAndRest extends \Magento\Framework\Api\AbstractExtensibleObject { + /** + * Entity ID + */ const ID = 'entity_id'; const NAME = 'name'; + + /** + * Is Enabled + */ const ENABLED = 'enabled'; const HAS_ORDERS = 'orders'; diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php index c8a997c8699ac..0a449a5dfc2ab 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php @@ -5,6 +5,10 @@ */ namespace Magento\TestModule5\Service\V2; +/** + * Both SOAP and REST Version TWO + * @package Magento\TestModule5\Service\V2 + */ interface AllSoapAndRestInterface { /** diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php index 6ffce62fabe97..f9bd1caf34f6a 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php @@ -5,8 +5,17 @@ */ namespace Magento\TestModule5\Service\V2\Entity; +/** + * Some Data Object short description. + * + * Data Object long + * multi line description. + */ class AllSoapAndRest extends \Magento\TestModule5\Service\V2\AllSoapAndRest { + /** + * Price field + */ const PRICE = 'price'; /** diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php new file mode 100644 index 0000000000000..0d1e1df7c47a5 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php @@ -0,0 +1,364 @@ +_markTestAsRestOnly("JSON generation tests are intended to be executed for REST adapter only."); + + $this->storeCode = Bootstrap::getObjectManager()->get('Magento\Store\Model\StoreManagerInterface') + ->getStore()->getCode(); + + $this->productMetadata = Bootstrap::getObjectManager()->get('Magento\Framework\App\ProductMetadataInterface'); + + parent::setUp(); + } + + public function testMultiServiceJson() + { + $this->isSingleService = false; + + $resourcePath = '?schema=1&services=testModule5AllSoapAndRestV1,testModule5AllSoapAndRestV2'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $resourcePath, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + ]; + + $schemaContent = $this->_webApiCall($serviceInfo); + $this->checkActualData($this->getExpectedMultiServiceData(), $schemaContent); + } + + public function testSingleServiceWsdl() + { + $this->isSingleService = false; + + $resourcePath = '?schema=1&services=testModule5AllSoapAndRestV2'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $resourcePath, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + ]; + + $schemaContent = $this->_webApiCall($serviceInfo); + + $this->checkActualData($this->getExpectedSingleServiceData(), $schemaContent); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Request does not match any route. + */ + public function testInvalidRestUrlNoServices() + { + $resourcePath = ''; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $resourcePath, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + ]; + + $this->_webApiCall($serviceInfo); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Incorrect format of request URI or Requested services are missing. + */ + public function testInvalidRestUrlInvalidServiceName() + { + $this->isSingleService = false; + + $resourcePath = '?schema=1&services=invalidServiceName'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $resourcePath, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + ]; + + $this->_webApiCall($serviceInfo); + } + + private function assertRecursiveArray($expected, $actual, $checkVal) + { + ksort($expected); + ksort($actual); + foreach ($expected as $expKey => $expVal) { + $this->assertArrayHasKey($expKey, $actual, 'Schema does not contain \'' . $expKey . '\' section.'); + if (is_array($expVal)) { + $this->assertTrue(is_array($actual[$expKey])); + $this->assertRecursiveArray($expVal, $actual[$expKey], $checkVal); + } elseif ($checkVal) { + $this->assertEquals($expVal, $actual[$expKey], '\'' . $expKey . '\' section content is invalid.'); + } + } + } + + public function checkActualData($expected, $actual) + { + $this->assertRecursiveArray($expected, $actual, true); + } + + public function getExpectedCommonData() + { + $versionParts = explode('.', $this->productMetadata->getVersion()); + if (!isset($versionParts[0]) || !isset($versionParts[1])) { + return []; // Major and minor version are not set - return empty response + } + $majorMinorVersion = $versionParts[0] . '.' . $versionParts[1]; + $url = str_replace('://', '', strstr($this->baseUrl, '://')); + $host = strpos($url, '/') ? strstr($url, '/', true) : $url; + $basePath = strstr(rtrim($url, '/'), '/'); + $basePath = $basePath ? trim($basePath, '/') . '/' : ''; + $basePath = '/' . $basePath . 'rest/' . $this->storeCode; + return [ + 'swagger' => '2.0', + 'info' => [ + 'version' => $majorMinorVersion, + 'title' => $this->productMetadata->getName() . ' ' .$this->productMetadata->getEdition(), + ], + 'host' => $host, + 'basePath' => $basePath, + ]; + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getExpectedMultiServiceData() + { + $expected = [ + 'tags' => [ + [ + 'name' => 'testModule5AllSoapAndRestV1', + 'description' => 'Both SOAP and REST Version ONE', + ], + [ + 'name' => 'testModule5AllSoapAndRestV2', + 'description' => 'Both SOAP and REST Version TWO', + ], + ], + 'paths' => [ + '/V1/TestModule5/{parentId}/nestedResource/{entityId}' => [ + 'put' => [ + 'tags' => [ + 'testModule5AllSoapAndRestV1', + ], + 'description' => 'Update existing item.', + 'operationId' => 'testModule5AllSoapAndRestV1NestedUpdatePut', + 'parameters' => [ + [ + 'name' => 'parentId', + 'in' => 'path', + 'type' => 'string', + 'required' => true + ], + [ + 'name' => 'entityId', + 'in' => 'path', + 'type' => 'string', + 'required' => true + ], + [ + 'name' => '$body', + 'in' => 'body', + 'schema' => [ + 'required' => [ + 'entityItem', + ], + 'properties' => [ + 'entityItem' => [ + '$ref' => '#/definitions/test-module5-v1-entity-all-soap-and-rest', + ], + ], + ], + ] + ], + 'responses' => [ + 200 => [ + 'description' => '200 Success.', + 'schema' => [ + '$ref' => '#/definitions/test-module5-v1-entity-all-soap-and-rest', + ], + ], + 401 => [ + 'description' => '401 Unauthorized', + 'schema' => [ + '$ref' => '#/definitions/error-response', + ], + ], + 'default' => [ + 'description' => 'Unexpected error', + 'schema' => [ + '$ref' => '#/definitions/error-response', + ], + ], + ], + ], + ], + ], + 'definitions' => [ + 'framework-attribute-interface' => [ + 'type' => 'object', + 'description' => 'Interface for custom attribute value.', + 'properties' => [ + 'attributeCode' => [ + 'type' => 'string', + 'description' => 'Attribute code', + ], + 'value' => [ + 'type' => 'string', + 'description' => 'Attribute value', + ], + ], + 'required' => [ + 'attributeCode', + 'value', + ], + ], + 'test-module5-v1-entity-all-soap-and-rest' => [ + 'type' => 'object', + 'description' => 'Some Data Object short description. Data Object long multi line description.', + 'properties' => [ + 'entityId' => [ + 'type' => 'integer', + 'description' => 'Item ID', + ], + 'name' => [ + 'type' => 'string', + 'description' => 'Item name', + ], + 'enabled' => [ + 'type' => 'boolean', + 'description' => 'If entity is enabled', + ], + 'orders' => [ + 'type' => 'boolean', + 'description' => 'If current entity has a property defined', + ], + 'customAttributes' => [ + 'type' => 'array', + 'description' => 'Custom attributes values.', + 'items' => [ + '$ref' => '#/definitions/framework-attribute-interface', + ], + ], + ], + 'required' => [ + 'entityId', + 'enabled', + 'orders', + ], + ], + ], + ]; + return array_merge_recursive($expected, $this->getExpectedCommonData()); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getExpectedSingleServiceData() + { + $expected = [ + 'tags' => [ + [ + 'name' => 'testModule5AllSoapAndRestV2', + 'description' => 'Both SOAP and REST Version TWO', + ], + ], + 'paths' => [ + '/V2/TestModule5/{id}' => [ + 'delete' => [ + 'tags' => [ + 'testModule5AllSoapAndRestV2', + ], + 'description' => 'Delete existing item.', + 'operationId' => 'testModule5AllSoapAndRestV2DeleteDelete', + 'parameters' => [ + [ + 'name' => 'id', + 'in' => 'path', + 'type' => 'string', + 'required' => true + ], + ], + 'responses' => [ + 200 => [ + 'description' => '200 Success.', + 'schema' => [ + '$ref' => '#/definitions/test-module5-v2-entity-all-soap-and-rest', + ], + ], + 401 => [ + 'description' => '401 Unauthorized', + 'schema' => [ + '$ref' => '#/definitions/error-response', + ], + ], + 'default' => [ + 'description' => 'Unexpected error', + 'schema' => [ + '$ref' => '#/definitions/error-response', + ], + ], + ], + ], + ], + ], + 'definitions' => [ + 'test-module5-v2-entity-all-soap-and-rest' => [ + 'type' => 'object', + 'description' => 'Some Data Object short description. Data Object long multi line description.', + 'properties' => [ + 'price' => [ + 'type' => 'integer', + ], + ], + 'required' => [ + 'price', + ], + ], + ], + ]; + return array_merge($expected, $this->getExpectedCommonData()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php index c093b3dcf0ad2..a645a22963fff 100644 --- a/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php @@ -314,7 +314,7 @@ protected function _checkReferencedTypeDeclaration($wsdlContent) $referencedType = <<< RESPONSE_TYPE - + Some Data Object short description. Data Object long multi line description. @@ -395,7 +395,7 @@ protected function _checkReferencedTypeDeclaration($wsdlContent) - + If entity is enabled false @@ -416,7 +416,7 @@ protected function _checkReferencedTypeDeclaration($wsdlContent) - + If current entity has a property defined false @@ -437,7 +437,7 @@ protected function _checkReferencedTypeDeclaration($wsdlContent) - + Custom attributes values. array diff --git a/dev/tests/integration/testsuite/Magento/Webapi/ServiceNameCollisionTest.php b/dev/tests/integration/testsuite/Magento/Webapi/ServiceNameCollisionTest.php index f568c3b307889..077ada2da8202 100644 --- a/dev/tests/integration/testsuite/Magento/Webapi/ServiceNameCollisionTest.php +++ b/dev/tests/integration/testsuite/Magento/Webapi/ServiceNameCollisionTest.php @@ -24,15 +24,15 @@ class ServiceNameCollisionTest extends \PHPUnit_Framework_TestCase public function testServiceNameCollisions() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - /** @var \Magento\Webapi\Model\Soap\Config $soapConfig */ - $soapConfig = $objectManager->get('Magento\Webapi\Model\Soap\Config'); + /** @var \Magento\Webapi\Model\ServiceMetadata $serviceMetadata */ + $serviceMetadata = $objectManager->get('Magento\Webapi\Model\ServiceMetadata'); /** @var \Magento\Webapi\Model\Config $webapiConfig */ $webapiConfig = $objectManager->get('Magento\Webapi\Model\Config'); $serviceNames = []; foreach ($webapiConfig->getServices()[Converter::KEY_SERVICES] as $serviceClassName => $serviceVersionData) { foreach ($serviceVersionData as $version => $serviceData) { - $newServiceName = $soapConfig->getServiceName($serviceClassName, $version); + $newServiceName = $serviceMetadata->getServiceName($serviceClassName, $version); $this->assertFalse(in_array($newServiceName, $serviceNames)); $serviceNames[] = $newServiceName; } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php index cafe3396d6509..8fd096b876769 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -3067,7 +3067,6 @@ ['Magento\Integration\Model\Integration\Factory', 'Magento\Integration\Model\IntegrationFactory'], ['Magento\Webapi\Model\PathProcessor', 'Magento\Webapi\Controller\PathProcessor'], ['Magento\Webapi\Helper\Data', 'Magento\Webapi\Model\Soap\Config'], - ['Magento\Webapi\Model\Config\ClassReflector', 'Magento\Webapi\Model\Soap\Config\ClassReflector'], ['Magento\Webapi\Model\Soap\Server\Factory', 'Magento\Webapi\Model\Soap\ServerFactory'], ['Magento\Webapi\Model\Soap\Wsdl\Factory', 'Magento\Webapi\Model\Soap\WsdlFactory'], [ diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeProcessorTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeProcessorTest.php index d02de6584d9eb..46fb7f7e19b8c 100644 --- a/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeProcessorTest.php +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeProcessorTest.php @@ -233,4 +233,9 @@ public function testGetParameterDescription() $paramsReflection = $methodReflection->getParameters(); $this->assertEquals('Name of the attribute', $this->_typeProcessor->getParamDescription($paramsReflection[0])); } + + public function testGetOperationName() + { + $this->assertEquals("resNameMethodName", $this->_typeProcessor->getOperationName("resName", "methodName")); + } } diff --git a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php index c05d6ba81c988..0e7a65d6e192b 100644 --- a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php @@ -136,6 +136,7 @@ public function register($type) * @param string $class * @return array * @throws \InvalidArgumentException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function _processComplexType($class) { @@ -180,10 +181,17 @@ protected function _processMethod(\Zend\Code\Reflection\MethodReflection $method if ($isGetter && !$methodReflection->getNumberOfRequiredParameters()) { $returnMetadata = $this->getGetterReturnType($methodReflection); $fieldName = $this->dataObjectGetterNameToFieldName($methodReflection->getName()); + if ($returnMetadata['description']) { + $description = $returnMetadata['description']; + } else { + $description = $this->dataObjectGetterDescriptionToFieldDescription( + $methodReflection->getDocBlock()->getShortDescription() + ); + } $this->_types[$typeName]['parameters'][$fieldName] = [ 'type' => $this->register($returnMetadata['type']), 'required' => $returnMetadata['isRequired'], - 'documentation' => $returnMetadata['description'], + 'documentation' => $description, ]; } } @@ -232,6 +240,17 @@ public function dataObjectGetterNameToFieldName($getterName) return lcfirst($fieldName); } + /** + * Convert Data Object getter short description into field description. + * + * @param string $shortDescription + * @return string + */ + protected function dataObjectGetterDescriptionToFieldDescription($shortDescription) + { + return ucfirst(substr(strstr($shortDescription, " "), 1)); + } + /** * Identify getter return type by its reflection. * @@ -285,6 +304,29 @@ public function getGetterReturnType($methodReflection) ]; } + /** + * Get possible method exceptions + * + * @param \Zend\Code\Reflection\MethodReflection $methodReflection + * @return array + */ + public function getExceptions($methodReflection) + { + $exceptions = []; + $methodDocBlock = $methodReflection->getDocBlock(); + if ($methodDocBlock->hasTag('throws')) { + $throwsTypes = $methodDocBlock->getTags('throws'); + if (is_array($throwsTypes)) { + /** @var $throwsType \Zend\Code\Reflection\DocBlock\Tag\ThrowsTag */ + foreach ($throwsTypes as $throwsType) { + $exceptions = array_merge($exceptions, $throwsType->getTypes()); + } + } + } + + return $exceptions; + } + /** * Normalize short type names to full type names. * @@ -614,4 +656,45 @@ protected function classHasMethod(ClassReflection $class, $methodName) { return $class->hasMethod($methodName) && ($class->getMethod($methodName)->getName() == $methodName); } + + /** + * Process call info data from interface. + * + * @param array $interface + * @param string $serviceName API service name + * @param string $methodName + * @return $this + */ + public function processInterfaceCallInfo($interface, $serviceName, $methodName) + { + foreach ($interface as $direction => $interfaceData) { + $direction = ($direction == 'in') ? 'requiredInput' : 'returned'; + foreach ($interfaceData['parameters'] as $parameterData) { + if (!$this->isTypeSimple($parameterData['type']) && !$this->isTypeAny($parameterData['type'])) { + $operation = $this->getOperationName($serviceName, $methodName); + if ($parameterData['required']) { + $condition = ($direction == 'requiredInput') ? 'yes' : 'always'; + } else { + $condition = ($direction == 'requiredInput') ? 'no' : 'conditionally'; + } + $callInfo = []; + $callInfo[$direction][$condition]['calls'][] = $operation; + $this->setTypeData($parameterData['type'], ['callInfo' => $callInfo]); + } + } + } + return $this; + } + + /** + * Get name of operation based on service and method names. + * + * @param string $serviceName API service name + * @param string $methodName + * @return string + */ + public function getOperationName($serviceName, $methodName) + { + return $serviceName . ucfirst($methodName); + } } diff --git a/lib/internal/Magento/Framework/Webapi/Request.php b/lib/internal/Magento/Framework/Webapi/Request.php index fdd688a313e51..c2b112bc8ed9c 100644 --- a/lib/internal/Magento/Framework/Webapi/Request.php +++ b/lib/internal/Magento/Framework/Webapi/Request.php @@ -12,9 +12,12 @@ use Magento\Framework\Config\ScopeInterface; use Magento\Framework\HTTP\PhpEnvironment\Request as HttpRequest; use Magento\Framework\Stdlib\Cookie\CookieReaderInterface; +use Magento\Framework\Phrase; class Request extends HttpRequest implements RequestInterface { + const REQUEST_PARAM_SERVICES = 'services'; + /** * Modify pathInfo: strip down the front name and query parameters. * @@ -57,4 +60,48 @@ public function getHeader($header, $default = false) } return $headerValue; } + + /** + * Identify versions of resources that should be used for API configuration generation. + * + * @return array|string + * @throws \Magento\Framework\Webapi\Exception When GET parameters are invalid + */ + public function getRequestedServices() + { + $param = $this->getParam(self::REQUEST_PARAM_SERVICES); + return $this->_convertRequestParamToServiceArray($param); + } + + /** + * Extract the resources query param value and return associative array of the form 'resource' => 'version' + * + * @param string $param eg
 testModule1AllSoapAndRestV1,testModule2AllSoapNoRestV1 
+ * @return string|array
 eg array (
+     *      'testModule1AllSoapAndRestV1',
+     *      'testModule2AllSoapNoRestV1',
+     *      )
+ * @throws \Magento\Framework\Webapi\Exception + */ + protected function _convertRequestParamToServiceArray($param) + { + $serviceSeparator = ','; + $serviceVerPattern = "[a-zA-Z\d]*V[\d]+"; + $regexp = "/^({$serviceVerPattern})([{$serviceSeparator}]{$serviceVerPattern})*\$/"; + if ($param == 'all') { + return $param; + } + //Check if the $param is of valid format + if (empty($param) || !preg_match($regexp, $param)) { + $message = new Phrase('Incorrect format of request URI or Requested services are missing.'); + throw new \Magento\Framework\Webapi\Exception($message); + } + //Split the $param string to create an array of 'service' => 'version' + $serviceVersionArray = explode($serviceSeparator, $param); + $serviceArray = []; + foreach ($serviceVersionArray as $service) { + $serviceArray[] = $service; + } + return $serviceArray; + } } diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/RequestTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/RequestTest.php new file mode 100644 index 0000000000000..fade3a6aeaeda --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/RequestTest.php @@ -0,0 +1,52 @@ +request = $objectManager->getObject('Magento\Framework\Webapi\Request'); + } + + protected function tearDown() + { + unset($this->request); + parent::tearDown(); + } + + /** + * @dataProvider providerTestGetRequestedServicesSuccess + * @param $requestParamServices + * @param $expectedResult + */ + public function testGetRequestedServicesSuccess($requestParamServices, $expectedResult) + { + $requestParams = [ + \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_WSDL => true, + \Magento\Webapi\Model\Soap\Server::REQUEST_PARAM_SERVICES => $requestParamServices, + ]; + $this->request->setParams($requestParams); + $this->assertEquals($expectedResult, $this->request->getRequestedServices()); + } + + public function providerTestGetRequestedServicesSuccess() + { + $testModuleA = 'testModule1AllSoapAndRestV1'; + $testModuleB = 'testModule1AllSoapAndRestV2'; + $testModuleC = 'testModule2AllSoapNoRestV1'; + return [ + ["{$testModuleA},{$testModuleB}", [$testModuleA, $testModuleB]], + ["{$testModuleA},{$testModuleC}", [$testModuleA, $testModuleC]], + ["{$testModuleA}", [$testModuleA]] + ]; + } +} From 564dbc5e46cada992707729d21979ccee335596f Mon Sep 17 00:00:00 2001 From: Dale Sikkema Date: Wed, 12 Aug 2015 13:45:26 -0500 Subject: [PATCH 35/87] MAGETWO-41390: Request parameters are not populated correctly in Swagger UI --- app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php index 56c83a24dc12f..0d3c8f8e6a729 100644 --- a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php +++ b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php @@ -789,6 +789,7 @@ private function generateBodySchema($parameterName, $parameterInfo, $description $parameterInfo['type'], $description ); + $bodySchema['type'] = 'object'; return $bodySchema; } From 1d063297a9273627702ec6446e5099b0a4631ce0 Mon Sep 17 00:00:00 2001 From: Dale Sikkema Date: Wed, 12 Aug 2015 13:56:37 -0500 Subject: [PATCH 36/87] MAGETWO-41062: create swagger-ui endpoint --- .../Swagger/Controller/Index/Index.php | 36 + .../Test/Unit/Controller/Index/IndexTest.php | 34 + .../Magento/Swagger/etc/frontend/routes.xml | 14 + app/code/Magento/Swagger/etc/module.xml | 10 + .../frontend/layout/swagger_index_index.xml | 48 + .../view/frontend/templates/swagger.phtml | 29 + .../Swagger/view/frontend/web/css/print.css | 1172 + .../Swagger/view/frontend/web/css/reset.css | 125 + .../Swagger/view/frontend/web/css/screen.css | 1279 + .../Swagger/view/frontend/web/css/style.css | 250 + .../view/frontend/web/css/typography.css | 26 + .../web/fonts/droid-sans-v6-latin-700.eot | Bin 0 -> 22922 bytes .../web/fonts/droid-sans-v6-latin-700.svg | 411 + .../web/fonts/droid-sans-v6-latin-700.ttf | Bin 0 -> 40513 bytes .../web/fonts/droid-sans-v6-latin-700.woff | Bin 0 -> 25992 bytes .../web/fonts/droid-sans-v6-latin-700.woff2 | Bin 0 -> 11480 bytes .../web/fonts/droid-sans-v6-latin-regular.eot | Bin 0 -> 22008 bytes .../web/fonts/droid-sans-v6-latin-regular.svg | 403 + .../web/fonts/droid-sans-v6-latin-regular.ttf | Bin 0 -> 39069 bytes .../fonts/droid-sans-v6-latin-regular.woff | Bin 0 -> 24868 bytes .../fonts/droid-sans-v6-latin-regular.woff2 | Bin 0 -> 11304 bytes .../frontend/web/images/explorer_icons.png | Bin 0 -> 5763 bytes .../frontend/web/images/favicon-16x16.png | Bin 0 -> 645 bytes .../frontend/web/images/favicon-32x32.png | Bin 0 -> 1654 bytes .../view/frontend/web/images/favicon.ico | Bin 0 -> 5430 bytes .../view/frontend/web/images/logo_small.png | Bin 0 -> 770 bytes .../frontend/web/images/pet_store_api.png | Bin 0 -> 824 bytes .../view/frontend/web/images/throbber.gif | Bin 0 -> 9257 bytes .../view/frontend/web/images/wordnik_api.png | Bin 0 -> 980 bytes .../Swagger/view/frontend/web/js/lang/en.js | 53 + .../Swagger/view/frontend/web/js/lang/es.js | 52 + .../Swagger/view/frontend/web/js/lang/pt.js | 53 + .../Swagger/view/frontend/web/js/lang/ru.js | 52 + .../view/frontend/web/js/lang/translator.js | 39 + .../view/frontend/web/js/lib/backbone-min.js | 15 + .../frontend/web/js/lib/handlebars-2.0.0.js | 28 + .../frontend/web/js/lib/highlight.7.3.pack.js | 1 + .../frontend/web/js/lib/jquery-1.8.0.min.js | 2 + .../frontend/web/js/lib/jquery.ba-bbq.min.js | 18 + .../frontend/web/js/lib/jquery.slideto.min.js | 1 + .../frontend/web/js/lib/jquery.wiggle.min.js | 8 + .../view/frontend/web/js/lib/marked.js | 1272 + .../view/frontend/web/js/lib/swagger-oauth.js | 290 + .../frontend/web/js/lib/underscore-min.js | 6 + .../frontend/web/js/lib/underscore-min.map | 1 + .../view/frontend/web/js/swagger-ui.js | 32249 ++++++++++++++++ 46 files changed, 37977 insertions(+) create mode 100644 app/code/Magento/Swagger/Controller/Index/Index.php create mode 100644 app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php create mode 100644 app/code/Magento/Swagger/etc/frontend/routes.xml create mode 100644 app/code/Magento/Swagger/etc/module.xml create mode 100644 app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml create mode 100644 app/code/Magento/Swagger/view/frontend/templates/swagger.phtml create mode 100644 app/code/Magento/Swagger/view/frontend/web/css/print.css create mode 100644 app/code/Magento/Swagger/view/frontend/web/css/reset.css create mode 100644 app/code/Magento/Swagger/view/frontend/web/css/screen.css create mode 100644 app/code/Magento/Swagger/view/frontend/web/css/style.css create mode 100644 app/code/Magento/Swagger/view/frontend/web/css/typography.css create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.eot create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.svg create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.ttf create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.woff create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.woff2 create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.eot create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.svg create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.ttf create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.woff create mode 100644 app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.woff2 create mode 100644 app/code/Magento/Swagger/view/frontend/web/images/explorer_icons.png create mode 100755 app/code/Magento/Swagger/view/frontend/web/images/favicon-16x16.png create mode 100755 app/code/Magento/Swagger/view/frontend/web/images/favicon-32x32.png create mode 100755 app/code/Magento/Swagger/view/frontend/web/images/favicon.ico create mode 100644 app/code/Magento/Swagger/view/frontend/web/images/logo_small.png create mode 100644 app/code/Magento/Swagger/view/frontend/web/images/pet_store_api.png create mode 100644 app/code/Magento/Swagger/view/frontend/web/images/throbber.gif create mode 100644 app/code/Magento/Swagger/view/frontend/web/images/wordnik_api.png create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lang/en.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lang/es.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lang/pt.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lang/ru.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lang/translator.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/backbone-min.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/handlebars-2.0.0.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/highlight.7.3.pack.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/jquery-1.8.0.min.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/jquery.ba-bbq.min.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/jquery.slideto.min.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/jquery.wiggle.min.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/marked.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/swagger-oauth.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/underscore-min.js create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/lib/underscore-min.map create mode 100644 app/code/Magento/Swagger/view/frontend/web/js/swagger-ui.js diff --git a/app/code/Magento/Swagger/Controller/Index/Index.php b/app/code/Magento/Swagger/Controller/Index/Index.php new file mode 100644 index 0000000000000..80248091b749b --- /dev/null +++ b/app/code/Magento/Swagger/Controller/Index/Index.php @@ -0,0 +1,36 @@ +pageConfig = $pageConfig; + $this->pageFactory = $pageFactory; + } + + public function execute() + { + $this->pageConfig->addBodyClass('swagger-section'); + return $this->pageFactory->create(); + } +} diff --git a/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php b/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php new file mode 100644 index 0000000000000..0143601c8995d --- /dev/null +++ b/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php @@ -0,0 +1,34 @@ +getMockBuilder('Magento\Framework\View\Page\Config') + ->disableOriginalConstructor() + ->getMock(); + $resultPageFactory = $this->getMockBuilder('Magento\Framework\View\Result\PageFactory') + ->disableOriginalConstructor() + ->getMock(); + + $pageConfigMock->expects($this->once())->method('addBodyClass')->with('swagger-section'); + $resultPageFactory->expects($this->once())->method('create'); + + $model = $objectManager->getObject( + 'Magento\Swagger\Controller\Index\Index', + [ + 'pageConfig' => $pageConfigMock, + 'pageFactory' => $resultPageFactory + ] + ); + $model->execute(); + } +} diff --git a/app/code/Magento/Swagger/etc/frontend/routes.xml b/app/code/Magento/Swagger/etc/frontend/routes.xml new file mode 100644 index 0000000000000..02b9256427512 --- /dev/null +++ b/app/code/Magento/Swagger/etc/frontend/routes.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Swagger/etc/module.xml b/app/code/Magento/Swagger/etc/module.xml new file mode 100644 index 0000000000000..06e6a83b6b213 --- /dev/null +++ b/app/code/Magento/Swagger/etc/module.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml b/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml new file mode 100644 index 0000000000000..cb93e16f36116 --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml @@ -0,0 +1,48 @@ + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Swagger/view/frontend/templates/swagger.phtml b/app/code/Magento/Swagger/view/frontend/templates/swagger.phtml new file mode 100644 index 0000000000000..3a13e4514e5cd --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/templates/swagger.phtml @@ -0,0 +1,29 @@ +getBaseUrl(), '/') . '/rest/default?schema=1&services=all'; +?> + + + + + + +
 
+
diff --git a/app/code/Magento/Swagger/view/frontend/web/css/print.css b/app/code/Magento/Swagger/view/frontend/web/css/print.css new file mode 100644 index 0000000000000..cd3aa8b6a4a84 --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/css/print.css @@ -0,0 +1,1172 @@ +/* Original style from softwaremaniacs.org (c) Ivan Sagalaev */ +.swagger-section pre code { + display: block; + padding: 0.5em; + background: #F0F0F0; +} +.swagger-section pre code, +.swagger-section pre .subst, +.swagger-section pre .tag .title, +.swagger-section pre .lisp .title, +.swagger-section pre .clojure .built_in, +.swagger-section pre .nginx .title { + color: black; +} +.swagger-section pre .string, +.swagger-section pre .title, +.swagger-section pre .constant, +.swagger-section pre .parent, +.swagger-section pre .tag .value, +.swagger-section pre .rules .value, +.swagger-section pre .rules .value .number, +.swagger-section pre .preprocessor, +.swagger-section pre .ruby .symbol, +.swagger-section pre .ruby .symbol .string, +.swagger-section pre .aggregate, +.swagger-section pre .template_tag, +.swagger-section pre .django .variable, +.swagger-section pre .smalltalk .class, +.swagger-section pre .addition, +.swagger-section pre .flow, +.swagger-section pre .stream, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .apache .cbracket, +.swagger-section pre .tex .command, +.swagger-section pre .tex .special, +.swagger-section pre .erlang_repl .function_or_atom, +.swagger-section pre .markdown .header { + color: #800; +} +.swagger-section pre .comment, +.swagger-section pre .annotation, +.swagger-section pre .template_comment, +.swagger-section pre .diff .header, +.swagger-section pre .chunk, +.swagger-section pre .markdown .blockquote { + color: #888; +} +.swagger-section pre .number, +.swagger-section pre .date, +.swagger-section pre .regexp, +.swagger-section pre .literal, +.swagger-section pre .smalltalk .symbol, +.swagger-section pre .smalltalk .char, +.swagger-section pre .go .constant, +.swagger-section pre .change, +.swagger-section pre .markdown .bullet, +.swagger-section pre .markdown .link_url { + color: #080; +} +.swagger-section pre .label, +.swagger-section pre .javadoc, +.swagger-section pre .ruby .string, +.swagger-section pre .decorator, +.swagger-section pre .filter .argument, +.swagger-section pre .localvars, +.swagger-section pre .array, +.swagger-section pre .attr_selector, +.swagger-section pre .important, +.swagger-section pre .pseudo, +.swagger-section pre .pi, +.swagger-section pre .doctype, +.swagger-section pre .deletion, +.swagger-section pre .envvar, +.swagger-section pre .shebang, +.swagger-section pre .apache .sqbracket, +.swagger-section pre .nginx .built_in, +.swagger-section pre .tex .formula, +.swagger-section pre .erlang_repl .reserved, +.swagger-section pre .prompt, +.swagger-section pre .markdown .link_label, +.swagger-section pre .vhdl .attribute, +.swagger-section pre .clojure .attribute, +.swagger-section pre .coffeescript .property { + color: #8888ff; +} +.swagger-section pre .keyword, +.swagger-section pre .id, +.swagger-section pre .phpdoc, +.swagger-section pre .title, +.swagger-section pre .built_in, +.swagger-section pre .aggregate, +.swagger-section pre .css .tag, +.swagger-section pre .javadoctag, +.swagger-section pre .phpdoc, +.swagger-section pre .yardoctag, +.swagger-section pre .smalltalk .class, +.swagger-section pre .winutils, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .go .typename, +.swagger-section pre .tex .command, +.swagger-section pre .markdown .strong, +.swagger-section pre .request, +.swagger-section pre .status { + font-weight: bold; +} +.swagger-section pre .markdown .emphasis { + font-style: italic; +} +.swagger-section pre .nginx .built_in { + font-weight: normal; +} +.swagger-section pre .coffeescript .javascript, +.swagger-section pre .javascript .xml, +.swagger-section pre .tex .formula, +.swagger-section pre .xml .javascript, +.swagger-section pre .xml .vbscript, +.swagger-section pre .xml .css, +.swagger-section pre .xml .cdata { + opacity: 0.5; +} +.swagger-section .swagger-ui-wrap { + line-height: 1; + font-family: "Droid Sans", sans-serif; + max-width: 960px; + margin-left: auto; + margin-right: auto; +} +.swagger-section .swagger-ui-wrap b, +.swagger-section .swagger-ui-wrap strong { + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap q, +.swagger-section .swagger-ui-wrap blockquote { + quotes: none; +} +.swagger-section .swagger-ui-wrap p { + line-height: 1.4em; + padding: 0 0 10px; + color: #333333; +} +.swagger-section .swagger-ui-wrap q:before, +.swagger-section .swagger-ui-wrap q:after, +.swagger-section .swagger-ui-wrap blockquote:before, +.swagger-section .swagger-ui-wrap blockquote:after { + content: none; +} +.swagger-section .swagger-ui-wrap .heading_with_menu h1, +.swagger-section .swagger-ui-wrap .heading_with_menu h2, +.swagger-section .swagger-ui-wrap .heading_with_menu h3, +.swagger-section .swagger-ui-wrap .heading_with_menu h4, +.swagger-section .swagger-ui-wrap .heading_with_menu h5, +.swagger-section .swagger-ui-wrap .heading_with_menu h6 { + display: block; + clear: none; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 60%; +} +.swagger-section .swagger-ui-wrap table { + border-collapse: collapse; + border-spacing: 0; +} +.swagger-section .swagger-ui-wrap table thead tr th { + padding: 5px; + font-size: 0.9em; + color: #666666; + border-bottom: 1px solid #999999; +} +.swagger-section .swagger-ui-wrap table tbody tr:last-child td { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap table tbody tr.offset { + background-color: #f0f0f0; +} +.swagger-section .swagger-ui-wrap table tbody tr td { + padding: 6px; + font-size: 0.9em; + border-bottom: 1px solid #cccccc; + vertical-align: top; + line-height: 1.3em; +} +.swagger-section .swagger-ui-wrap ol { + margin: 0px 0 10px; + padding: 0 0 0 18px; + list-style-type: decimal; +} +.swagger-section .swagger-ui-wrap ol li { + padding: 5px 0px; + font-size: 0.9em; + color: #333333; +} +.swagger-section .swagger-ui-wrap ol, +.swagger-section .swagger-ui-wrap ul { + list-style: none; +} +.swagger-section .swagger-ui-wrap h1 a, +.swagger-section .swagger-ui-wrap h2 a, +.swagger-section .swagger-ui-wrap h3 a, +.swagger-section .swagger-ui-wrap h4 a, +.swagger-section .swagger-ui-wrap h5 a, +.swagger-section .swagger-ui-wrap h6 a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap h1 a:hover, +.swagger-section .swagger-ui-wrap h2 a:hover, +.swagger-section .swagger-ui-wrap h3 a:hover, +.swagger-section .swagger-ui-wrap h4 a:hover, +.swagger-section .swagger-ui-wrap h5 a:hover, +.swagger-section .swagger-ui-wrap h6 a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap h1 span.divider, +.swagger-section .swagger-ui-wrap h2 span.divider, +.swagger-section .swagger-ui-wrap h3 span.divider, +.swagger-section .swagger-ui-wrap h4 span.divider, +.swagger-section .swagger-ui-wrap h5 span.divider, +.swagger-section .swagger-ui-wrap h6 span.divider { + color: #aaaaaa; +} +.swagger-section .swagger-ui-wrap a { + color: #547f00; +} +.swagger-section .swagger-ui-wrap a img { + border: none; +} +.swagger-section .swagger-ui-wrap article, +.swagger-section .swagger-ui-wrap aside, +.swagger-section .swagger-ui-wrap details, +.swagger-section .swagger-ui-wrap figcaption, +.swagger-section .swagger-ui-wrap figure, +.swagger-section .swagger-ui-wrap footer, +.swagger-section .swagger-ui-wrap header, +.swagger-section .swagger-ui-wrap hgroup, +.swagger-section .swagger-ui-wrap menu, +.swagger-section .swagger-ui-wrap nav, +.swagger-section .swagger-ui-wrap section, +.swagger-section .swagger-ui-wrap summary { + display: block; +} +.swagger-section .swagger-ui-wrap pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; +} +.swagger-section .swagger-ui-wrap pre code { + line-height: 1.6em; + background: none; +} +.swagger-section .swagger-ui-wrap .content > .content-type > div > label { + clear: both; + display: block; + color: #0F6AB4; + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap .content pre { + font-size: 12px; + margin-top: 5px; + padding: 5px; +} +.swagger-section .swagger-ui-wrap .icon-btn { + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .info_title { + padding-bottom: 10px; + font-weight: bold; + font-size: 25px; +} +.swagger-section .swagger-ui-wrap .footer { + margin-top: 20px; +} +.swagger-section .swagger-ui-wrap p.big, +.swagger-section .swagger-ui-wrap div.big p { + font-size: 1em; + margin-bottom: 10px; +} +.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input { + width: 500px !important; +} +.swagger-section .swagger-ui-wrap .info_license { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_tos { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .message-fail { + color: #cc0000; +} +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_description { + padding-bottom: 10px; + font-size: 15px; +} +.swagger-section .swagger-ui-wrap .markdown ol li, +.swagger-section .swagger-ui-wrap .markdown ul li { + padding: 3px 0px; + line-height: 1.4em; + color: #333333; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input { + display: block; + padding: 4px; + width: auto; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title { + font-size: 1.3em; +} +.swagger-section .swagger-ui-wrap table.fullwidth { + width: 100%; +} +.swagger-section .swagger-ui-wrap .model-signature { + font-family: "Droid Sans", sans-serif; + font-size: 1em; + line-height: 1.5em; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a { + text-decoration: none; + color: #AAA; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap .model-signature .propType { + color: #5555aa; +} +.swagger-section .swagger-ui-wrap .model-signature pre:hover { + background-color: #ffffdd; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + font-size: .85em; + line-height: 1.2em; + overflow: auto; + max-height: 200px; + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li { + float: left; + margin: 0 5px 5px 0; + padding: 2px 5px 2px 0; + border-right: 1px solid #ddd; +} +.swagger-section .swagger-ui-wrap .model-signature .propOpt { + color: #555; +} +.swagger-section .swagger-ui-wrap .model-signature .snippet small { + font-size: 0.75em; +} +.swagger-section .swagger-ui-wrap .model-signature .propOptKey { + font-style: italic; +} +.swagger-section .swagger-ui-wrap .model-signature .description .strong { + font-weight: bold; + color: #000; + font-size: .9em; +} +.swagger-section .swagger-ui-wrap .model-signature .description div { + font-size: 0.9em; + line-height: 1.5em; + margin-left: 1em; +} +.swagger-section .swagger-ui-wrap .model-signature .description .stronger { + font-weight: bold; + color: #000; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:first-child, +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:last-child { + display: inline; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:not(:first-child):before { + display: block; + content: ''; +} +.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown > p:only-child { + margin-right: -3px; +} +.swagger-section .swagger-ui-wrap .model-signature .propName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-container { + clear: both; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 300px; + height: 100px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap .markdown p code, +.swagger-section .swagger-ui-wrap .markdown li code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #f0f0f0; + color: black; + padding: 1px 3px; +} +.swagger-section .swagger-ui-wrap .required { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 300px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap h1 { + color: black; + font-size: 1.5em; + line-height: 1.3em; + padding: 10px 0 10px 0; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .heading_with_menu { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap .heading_with_menu ul { + display: block; + clear: none; + float: right; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + margin-top: 10px; +} +.swagger-section .swagger-ui-wrap h2 { + color: black; + font-size: 1.3em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap h2 span.sub { + font-size: 0.7em; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap h2 span.sub a { + color: #777777; +} +.swagger-section .swagger-ui-wrap span.weak { + color: #666666; +} +.swagger-section .swagger-ui-wrap .message-success { + color: #89BF04; +} +.swagger-section .swagger-ui-wrap caption, +.swagger-section .swagger-ui-wrap th, +.swagger-section .swagger-ui-wrap td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +.swagger-section .swagger-ui-wrap .code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea { + font-family: "Droid Sans", sans-serif; + height: 250px; + padding: 4px; + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select { + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label { + display: block; + float: left; + clear: none; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input { + display: block; + float: left; + clear: none; + margin: 0 5px 0 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label { + color: black; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label { + display: block; + clear: both; + width: auto; + padding: 0 0 3px; + color: #666666; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr { + padding-left: 3px; + color: #888888; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints { + margin-left: 0; + font-style: italic; + font-size: 0.9em; + margin: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap span.blank, +.swagger-section .swagger-ui-wrap span.empty { + color: #888888; + font-style: italic; +} +.swagger-section .swagger-ui-wrap .markdown h3 { + color: #547f00; +} +.swagger-section .swagger-ui-wrap .markdown h4 { + color: #666666; +} +.swagger-section .swagger-ui-wrap .markdown pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; + margin: 0 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown pre code { + line-height: 1.6em; +} +.swagger-section .swagger-ui-wrap div.gist { + margin: 20px 0 25px 0 !important; +} +.swagger-section .swagger-ui-wrap ul#resources { + font-family: "Droid Sans", sans-serif; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource { + border-bottom: 1px solid #dddddd; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a { + color: #555555; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading { + border: 1px solid transparent; + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 14px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; + color: #666666; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a { + color: #aaaaaa; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #999999; + padding-left: 0; + display: block; + clear: none; + float: left; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #999999; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0 0 10px; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 { + display: block; + clear: none; + float: left; + width: auto; + margin: 0; + padding: 0; + line-height: 1.1em; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path { + padding-left: 10px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a { + text-transform: uppercase; + text-decoration: none; + color: white; + display: inline-block; + width: 50px; + font-size: 0.7em; + text-align: center; + padding: 7px 0 4px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 6px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + border-top: none; + padding: 10px; + -moz-border-radius-bottomleft: 6px; + -webkit-border-bottom-left-radius: 6px; + -o-border-bottom-left-radius: 6px; + -ms-border-bottom-left-radius: 6px; + -khtml-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-right-radius: 6px; + -o-border-bottom-right-radius: 6px; + -ms-border-bottom-right-radius: 6px; + -khtml-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + margin: 0 0 20px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4 { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a { + padding: 4px 0 0 10px; + display: inline-block; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit { + display: block; + clear: none; + float: left; + padding: 6px 8px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber { + background-image: url('../images/throbber.gif'); + width: 128px; + height: 16px; + display: block; + clear: none; + float: right; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error { + outline: 2px solid black; + outline-color: #cc0000; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + padding: 10px; + font-size: 0.9em; + max-height: 400px; + overflow-y: auto; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { + background-color: #f9f2e9; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { + background-color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0e0ca; + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { + background-color: #faf5ee; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #ffd20f; + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { + background-color: #f5e8e8; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #e8c6c7; + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + background-color: #f7eded; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { + color: #c8787a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { + background-color: #e7f6ec; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { + background-color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3e8d1; + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { + background-color: #ebf7f0; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { + background-color: #FCE9E3; + border: 1px solid #F5D5C3; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { + background-color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0cecb; + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { + background-color: #faf0ef; + border: 1px solid #f0cecb; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + border-top: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap p#colophon { + margin: 0 15px 40px 15px; + padding: 10px 0; + font-size: 0.8em; + border-top: 1px solid #dddddd; + font-family: "Droid Sans", sans-serif; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap p#colophon a { + text-decoration: none; + color: #547f00; +} +.swagger-section .swagger-ui-wrap h3 { + color: black; + font-size: 1.1em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown ol, +.swagger-section .swagger-ui-wrap .markdown ul { + font-family: "Droid Sans", sans-serif; + margin: 5px 0 10px; + padding: 0 0 0 18px; + list-style-type: disc; +} +.swagger-section .swagger-ui-wrap form.form_box { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box label { + color: #0f6ab4 !important; +} +.swagger-section .swagger-ui-wrap form.form_box input[type=submit] { + display: block; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box p.weak { + font-size: 0.8em; +} +.swagger-section .swagger-ui-wrap form.form_box p { + font-size: 0.9em; + padding: 0 0 15px; + color: #7e7b6d; +} +.swagger-section .swagger-ui-wrap form.form_box p a { + color: #646257; +} +.swagger-section .swagger-ui-wrap form.form_box p strong { + color: black; +} +.swagger-section .swagger-ui-wrap .operation-status td.markdown > p:last-child { + padding-bottom: 0; +} +.swagger-section .title { + font-style: bold; +} +.swagger-section .secondary_form { + display: none; +} +.swagger-section .main_image { + display: block; + margin-left: auto; + margin-right: auto; +} +.swagger-section .oauth_body { + margin-left: 100px; + margin-right: 100px; +} +.swagger-section .oauth_submit { + text-align: center; +} +.swagger-section .api-popup-dialog { + z-index: 10000; + position: absolute; + width: 500px; + background: #FFF; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + color: #777; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog p.error-msg { + padding-left: 5px; + padding-bottom: 5px; +} +.swagger-section .api-popup-dialog button.api-popup-authbtn { + height: 30px; +} +.swagger-section .api-popup-dialog button.api-popup-cancel { + height: 30px; +} +.swagger-section .api-popup-scopes { + padding: 10px 20px; +} +.swagger-section .api-popup-scopes li { + padding: 5px 0; + line-height: 20px; +} +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} +.swagger-section .api-popup-scopes li input { + position: relative; + top: 2px; +} +.swagger-section .api-popup-actions { + padding-top: 10px; +} +#header { + display: none; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + max-height: none; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 100px; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 100px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + display: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints { + display: block !important; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + display: block !important; +} diff --git a/app/code/Magento/Swagger/view/frontend/web/css/reset.css b/app/code/Magento/Swagger/view/frontend/web/css/reset.css new file mode 100644 index 0000000000000..b2b078943c451 --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/css/reset.css @@ -0,0 +1,125 @@ +/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/app/code/Magento/Swagger/view/frontend/web/css/screen.css b/app/code/Magento/Swagger/view/frontend/web/css/screen.css new file mode 100644 index 0000000000000..436cc28edd312 --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/css/screen.css @@ -0,0 +1,1279 @@ +/* Original style from softwaremaniacs.org (c) Ivan Sagalaev */ +.swagger-section pre code { + display: block; + padding: 0.5em; + background: #F0F0F0; +} +.swagger-section pre code, +.swagger-section pre .subst, +.swagger-section pre .tag .title, +.swagger-section pre .lisp .title, +.swagger-section pre .clojure .built_in, +.swagger-section pre .nginx .title { + color: black; +} +.swagger-section pre .string, +.swagger-section pre .title, +.swagger-section pre .constant, +.swagger-section pre .parent, +.swagger-section pre .tag .value, +.swagger-section pre .rules .value, +.swagger-section pre .rules .value .number, +.swagger-section pre .preprocessor, +.swagger-section pre .ruby .symbol, +.swagger-section pre .ruby .symbol .string, +.swagger-section pre .aggregate, +.swagger-section pre .template_tag, +.swagger-section pre .django .variable, +.swagger-section pre .smalltalk .class, +.swagger-section pre .addition, +.swagger-section pre .flow, +.swagger-section pre .stream, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .apache .cbracket, +.swagger-section pre .tex .command, +.swagger-section pre .tex .special, +.swagger-section pre .erlang_repl .function_or_atom, +.swagger-section pre .markdown .header { + color: #800; +} +.swagger-section pre .comment, +.swagger-section pre .annotation, +.swagger-section pre .template_comment, +.swagger-section pre .diff .header, +.swagger-section pre .chunk, +.swagger-section pre .markdown .blockquote { + color: #888; +} +.swagger-section pre .number, +.swagger-section pre .date, +.swagger-section pre .regexp, +.swagger-section pre .literal, +.swagger-section pre .smalltalk .symbol, +.swagger-section pre .smalltalk .char, +.swagger-section pre .go .constant, +.swagger-section pre .change, +.swagger-section pre .markdown .bullet, +.swagger-section pre .markdown .link_url { + color: #080; +} +.swagger-section pre .label, +.swagger-section pre .javadoc, +.swagger-section pre .ruby .string, +.swagger-section pre .decorator, +.swagger-section pre .filter .argument, +.swagger-section pre .localvars, +.swagger-section pre .array, +.swagger-section pre .attr_selector, +.swagger-section pre .important, +.swagger-section pre .pseudo, +.swagger-section pre .pi, +.swagger-section pre .doctype, +.swagger-section pre .deletion, +.swagger-section pre .envvar, +.swagger-section pre .shebang, +.swagger-section pre .apache .sqbracket, +.swagger-section pre .nginx .built_in, +.swagger-section pre .tex .formula, +.swagger-section pre .erlang_repl .reserved, +.swagger-section pre .prompt, +.swagger-section pre .markdown .link_label, +.swagger-section pre .vhdl .attribute, +.swagger-section pre .clojure .attribute, +.swagger-section pre .coffeescript .property { + color: #8888ff; +} +.swagger-section pre .keyword, +.swagger-section pre .id, +.swagger-section pre .phpdoc, +.swagger-section pre .title, +.swagger-section pre .built_in, +.swagger-section pre .aggregate, +.swagger-section pre .css .tag, +.swagger-section pre .javadoctag, +.swagger-section pre .phpdoc, +.swagger-section pre .yardoctag, +.swagger-section pre .smalltalk .class, +.swagger-section pre .winutils, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .go .typename, +.swagger-section pre .tex .command, +.swagger-section pre .markdown .strong, +.swagger-section pre .request, +.swagger-section pre .status { + font-weight: bold; +} +.swagger-section pre .markdown .emphasis { + font-style: italic; +} +.swagger-section pre .nginx .built_in { + font-weight: normal; +} +.swagger-section pre .coffeescript .javascript, +.swagger-section pre .javascript .xml, +.swagger-section pre .tex .formula, +.swagger-section pre .xml .javascript, +.swagger-section pre .xml .vbscript, +.swagger-section pre .xml .css, +.swagger-section pre .xml .cdata { + opacity: 0.5; +} +.swagger-section .swagger-ui-wrap { + line-height: 1; + font-family: "Droid Sans", sans-serif; + max-width: 960px; + margin-left: auto; + margin-right: auto; +} +.swagger-section .swagger-ui-wrap b, +.swagger-section .swagger-ui-wrap strong { + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap q, +.swagger-section .swagger-ui-wrap blockquote { + quotes: none; +} +.swagger-section .swagger-ui-wrap p { + line-height: 1.4em; + padding: 0 0 10px; + color: #333333; +} +.swagger-section .swagger-ui-wrap q:before, +.swagger-section .swagger-ui-wrap q:after, +.swagger-section .swagger-ui-wrap blockquote:before, +.swagger-section .swagger-ui-wrap blockquote:after { + content: none; +} +.swagger-section .swagger-ui-wrap .heading_with_menu h1, +.swagger-section .swagger-ui-wrap .heading_with_menu h2, +.swagger-section .swagger-ui-wrap .heading_with_menu h3, +.swagger-section .swagger-ui-wrap .heading_with_menu h4, +.swagger-section .swagger-ui-wrap .heading_with_menu h5, +.swagger-section .swagger-ui-wrap .heading_with_menu h6 { + display: block; + clear: none; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 60%; +} +.swagger-section .swagger-ui-wrap table { + border-collapse: collapse; + border-spacing: 0; +} +.swagger-section .swagger-ui-wrap table thead tr th { + padding: 5px; + font-size: 0.9em; + color: #666666; + border-bottom: 1px solid #999999; +} +.swagger-section .swagger-ui-wrap table tbody tr:last-child td { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap table tbody tr.offset { + background-color: #f0f0f0; +} +.swagger-section .swagger-ui-wrap table tbody tr td { + padding: 6px; + font-size: 0.9em; + border-bottom: 1px solid #cccccc; + vertical-align: top; + line-height: 1.3em; +} +.swagger-section .swagger-ui-wrap ol { + margin: 0px 0 10px; + padding: 0 0 0 18px; + list-style-type: decimal; +} +.swagger-section .swagger-ui-wrap ol li { + padding: 5px 0px; + font-size: 0.9em; + color: #333333; +} +.swagger-section .swagger-ui-wrap ol, +.swagger-section .swagger-ui-wrap ul { + list-style: none; +} +.swagger-section .swagger-ui-wrap h1 a, +.swagger-section .swagger-ui-wrap h2 a, +.swagger-section .swagger-ui-wrap h3 a, +.swagger-section .swagger-ui-wrap h4 a, +.swagger-section .swagger-ui-wrap h5 a, +.swagger-section .swagger-ui-wrap h6 a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap h1 a:hover, +.swagger-section .swagger-ui-wrap h2 a:hover, +.swagger-section .swagger-ui-wrap h3 a:hover, +.swagger-section .swagger-ui-wrap h4 a:hover, +.swagger-section .swagger-ui-wrap h5 a:hover, +.swagger-section .swagger-ui-wrap h6 a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap h1 span.divider, +.swagger-section .swagger-ui-wrap h2 span.divider, +.swagger-section .swagger-ui-wrap h3 span.divider, +.swagger-section .swagger-ui-wrap h4 span.divider, +.swagger-section .swagger-ui-wrap h5 span.divider, +.swagger-section .swagger-ui-wrap h6 span.divider { + color: #aaaaaa; +} +.swagger-section .swagger-ui-wrap a { + color: #547f00; +} +.swagger-section .swagger-ui-wrap a img { + border: none; +} +.swagger-section .swagger-ui-wrap article, +.swagger-section .swagger-ui-wrap aside, +.swagger-section .swagger-ui-wrap details, +.swagger-section .swagger-ui-wrap figcaption, +.swagger-section .swagger-ui-wrap figure, +.swagger-section .swagger-ui-wrap footer, +.swagger-section .swagger-ui-wrap header, +.swagger-section .swagger-ui-wrap hgroup, +.swagger-section .swagger-ui-wrap menu, +.swagger-section .swagger-ui-wrap nav, +.swagger-section .swagger-ui-wrap section, +.swagger-section .swagger-ui-wrap summary { + display: block; +} +.swagger-section .swagger-ui-wrap pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; +} +.swagger-section .swagger-ui-wrap pre code { + line-height: 1.6em; + background: none; +} +.swagger-section .swagger-ui-wrap .content > .content-type > div > label { + clear: both; + display: block; + color: #0F6AB4; + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap .content pre { + font-size: 12px; + margin-top: 5px; + padding: 5px; +} +.swagger-section .swagger-ui-wrap .icon-btn { + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .info_title { + padding-bottom: 10px; + font-weight: bold; + font-size: 25px; +} +.swagger-section .swagger-ui-wrap .footer { + margin-top: 20px; +} +.swagger-section .swagger-ui-wrap p.big, +.swagger-section .swagger-ui-wrap div.big p { + font-size: 1em; + margin-bottom: 10px; +} +.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input { + width: 500px !important; +} +.swagger-section .swagger-ui-wrap .info_license { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_tos { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .message-fail { + color: #cc0000; +} +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_description { + padding-bottom: 10px; + font-size: 15px; +} +.swagger-section .swagger-ui-wrap .markdown ol li, +.swagger-section .swagger-ui-wrap .markdown ul li { + padding: 3px 0px; + line-height: 1.4em; + color: #333333; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input { + display: block; + padding: 4px; + width: auto; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title { + font-size: 1.3em; +} +.swagger-section .swagger-ui-wrap table.fullwidth { + width: 100%; +} +.swagger-section .swagger-ui-wrap .model-signature { + font-family: "Droid Sans", sans-serif; + font-size: 1em; + line-height: 1.5em; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a { + text-decoration: none; + color: #AAA; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap .model-signature .propType { + color: #5555aa; +} +.swagger-section .swagger-ui-wrap .model-signature pre:hover { + background-color: #ffffdd; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + font-size: .85em; + line-height: 1.2em; + overflow: auto; + max-height: 200px; + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li { + float: left; + margin: 0 5px 5px 0; + padding: 2px 5px 2px 0; + border-right: 1px solid #ddd; +} +.swagger-section .swagger-ui-wrap .model-signature .propOpt { + color: #555; +} +.swagger-section .swagger-ui-wrap .model-signature .snippet small { + font-size: 0.75em; +} +.swagger-section .swagger-ui-wrap .model-signature .propOptKey { + font-style: italic; +} +.swagger-section .swagger-ui-wrap .model-signature .description .strong { + font-weight: bold; + color: #000; + font-size: .9em; +} +.swagger-section .swagger-ui-wrap .model-signature .description div { + font-size: 0.9em; + line-height: 1.5em; + margin-left: 1em; +} +.swagger-section .swagger-ui-wrap .model-signature .description .stronger { + font-weight: bold; + color: #000; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:first-child, +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:last-child { + display: inline; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:not(:first-child):before { + display: block; + content: ''; +} +.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown > p:only-child { + margin-right: -3px; +} +.swagger-section .swagger-ui-wrap .model-signature .propName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-container { + clear: both; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 300px; + height: 100px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap .markdown p code, +.swagger-section .swagger-ui-wrap .markdown li code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #f0f0f0; + color: black; + padding: 1px 3px; +} +.swagger-section .swagger-ui-wrap .required { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 300px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap h1 { + color: black; + font-size: 1.5em; + line-height: 1.3em; + padding: 10px 0 10px 0; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .heading_with_menu { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap .heading_with_menu ul { + display: block; + clear: none; + float: right; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + margin-top: 10px; +} +.swagger-section .swagger-ui-wrap h2 { + color: black; + font-size: 1.3em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap h2 span.sub { + font-size: 0.7em; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap h2 span.sub a { + color: #777777; +} +.swagger-section .swagger-ui-wrap span.weak { + color: #666666; +} +.swagger-section .swagger-ui-wrap .message-success { + color: #89BF04; +} +.swagger-section .swagger-ui-wrap caption, +.swagger-section .swagger-ui-wrap th, +.swagger-section .swagger-ui-wrap td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +.swagger-section .swagger-ui-wrap .code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea { + font-family: "Droid Sans", sans-serif; + height: 250px; + padding: 4px; + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select { + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label { + display: block; + float: left; + clear: none; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input { + display: block; + float: left; + clear: none; + margin: 0 5px 0 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label { + color: black; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label { + display: block; + clear: both; + width: auto; + padding: 0 0 3px; + color: #666666; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr { + padding-left: 3px; + color: #888888; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints { + margin-left: 0; + font-style: italic; + font-size: 0.9em; + margin: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap span.blank, +.swagger-section .swagger-ui-wrap span.empty { + color: #888888; + font-style: italic; +} +.swagger-section .swagger-ui-wrap .markdown h3 { + color: #547f00; +} +.swagger-section .swagger-ui-wrap .markdown h4 { + color: #666666; +} +.swagger-section .swagger-ui-wrap .markdown pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; + margin: 0 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown pre code { + line-height: 1.6em; +} +.swagger-section .swagger-ui-wrap div.gist { + margin: 20px 0 25px 0 !important; +} +.swagger-section .swagger-ui-wrap ul#resources { + font-family: "Droid Sans", sans-serif; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource { + border-bottom: 1px solid #dddddd; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a { + color: #555555; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading { + border: 1px solid transparent; + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 14px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; + color: #666666; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a { + color: #aaaaaa; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #999999; + padding-left: 0; + display: block; + clear: none; + float: left; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #999999; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0 0 10px; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 { + display: block; + clear: none; + float: left; + width: auto; + margin: 0; + padding: 0; + line-height: 1.1em; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path { + padding-left: 10px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a { + text-transform: uppercase; + text-decoration: none; + color: white; + display: inline-block; + width: 50px; + font-size: 0.7em; + text-align: center; + padding: 7px 0 4px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 6px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + border-top: none; + padding: 10px; + -moz-border-radius-bottomleft: 6px; + -webkit-border-bottom-left-radius: 6px; + -o-border-bottom-left-radius: 6px; + -ms-border-bottom-left-radius: 6px; + -khtml-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-right-radius: 6px; + -o-border-bottom-right-radius: 6px; + -ms-border-bottom-right-radius: 6px; + -khtml-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + margin: 0 0 20px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4 { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a { + padding: 4px 0 0 10px; + display: inline-block; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit { + display: block; + clear: none; + float: left; + padding: 6px 8px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber { + background-image: url('../images/throbber.gif'); + width: 128px; + height: 16px; + display: block; + clear: none; + float: right; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error { + outline: 2px solid black; + outline-color: #cc0000; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + padding: 10px; + font-size: 0.9em; + max-height: 400px; + overflow-y: auto; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { + background-color: #f9f2e9; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { + background-color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0e0ca; + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { + background-color: #faf5ee; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #ffd20f; + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { + background-color: #f5e8e8; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #e8c6c7; + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + background-color: #f7eded; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { + color: #c8787a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { + background-color: #e7f6ec; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { + background-color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3e8d1; + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { + background-color: #ebf7f0; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { + background-color: #FCE9E3; + border: 1px solid #F5D5C3; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { + background-color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0cecb; + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { + background-color: #faf0ef; + border: 1px solid #f0cecb; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + border-top: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap p#colophon { + margin: 0 15px 40px 15px; + padding: 10px 0; + font-size: 0.8em; + border-top: 1px solid #dddddd; + font-family: "Droid Sans", sans-serif; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap p#colophon a { + text-decoration: none; + color: #547f00; +} +.swagger-section .swagger-ui-wrap h3 { + color: black; + font-size: 1.1em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown ol, +.swagger-section .swagger-ui-wrap .markdown ul { + font-family: "Droid Sans", sans-serif; + margin: 5px 0 10px; + padding: 0 0 0 18px; + list-style-type: disc; +} +.swagger-section .swagger-ui-wrap form.form_box { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box label { + color: #0f6ab4 !important; +} +.swagger-section .swagger-ui-wrap form.form_box input[type=submit] { + display: block; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box p.weak { + font-size: 0.8em; +} +.swagger-section .swagger-ui-wrap form.form_box p { + font-size: 0.9em; + padding: 0 0 15px; + color: #7e7b6d; +} +.swagger-section .swagger-ui-wrap form.form_box p a { + color: #646257; +} +.swagger-section .swagger-ui-wrap form.form_box p strong { + color: black; +} +.swagger-section .swagger-ui-wrap .operation-status td.markdown > p:last-child { + padding-bottom: 0; +} +.swagger-section .title { + font-style: bold; +} +.swagger-section .secondary_form { + display: none; +} +.swagger-section .main_image { + display: block; + margin-left: auto; + margin-right: auto; +} +.swagger-section .oauth_body { + margin-left: 100px; + margin-right: 100px; +} +.swagger-section .oauth_submit { + text-align: center; +} +.swagger-section .api-popup-dialog { + z-index: 10000; + position: absolute; + width: 500px; + background: #FFF; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + color: #777; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog p.error-msg { + padding-left: 5px; + padding-bottom: 5px; +} +.swagger-section .api-popup-dialog button.api-popup-authbtn { + height: 30px; +} +.swagger-section .api-popup-dialog button.api-popup-cancel { + height: 30px; +} +.swagger-section .api-popup-scopes { + padding: 10px 20px; +} +.swagger-section .api-popup-scopes li { + padding: 5px 0; + line-height: 20px; +} +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} +.swagger-section .api-popup-scopes li input { + position: relative; + top: 2px; +} +.swagger-section .api-popup-actions { + padding-top: 10px; +} +.swagger-section .access { + float: right; +} +.swagger-section .auth { + float: right; +} +.swagger-section .api-ic { + height: 18px; + vertical-align: middle; + display: inline-block; + background: url(../images/explorer_icons.png) no-repeat; +} +.swagger-section .api-ic .api_information_panel { + position: relative; + margin-top: 20px; + margin-left: -5px; + background: #FFF; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + max-width: 300px; + line-height: 30px; + color: black; + padding: 5px; +} +.swagger-section .api-ic .api_information_panel p .api-msg-enabled { + color: green; +} +.swagger-section .api-ic .api_information_panel p .api-msg-disabled { + color: red; +} +.swagger-section .api-ic:hover .api_information_panel { + position: absolute; + display: block; +} +.swagger-section .ic-info { + background-position: 0 0; + width: 18px; + margin-top: -6px; + margin-left: 4px; +} +.swagger-section .ic-warning { + background-position: -60px 0; + width: 18px; + margin-top: -6px; + margin-left: 4px; +} +.swagger-section .ic-error { + background-position: -30px 0; + width: 18px; + margin-top: -6px; + margin-left: 4px; +} +.swagger-section .ic-off { + background-position: -90px 0; + width: 58px; + margin-top: -4px; + cursor: pointer; +} +.swagger-section .ic-on { + background-position: -160px 0; + width: 58px; + margin-top: -4px; + cursor: pointer; +} +.swagger-section #header { + background-color: #89bf04; + padding: 14px; +} +.swagger-section #header a#logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo_small.png) no-repeat left center; + padding: 20px 0 20px 40px; + color: white; +} +.swagger-section #header form#api_selector { + display: block; + clear: none; + float: right; +} +.swagger-section #header form#api_selector .input { + display: block; + clear: none; + float: left; + margin: 0 10px 0 0; +} +.swagger-section #header form#api_selector .input input#input_apiKey { + width: 200px; +} +.swagger-section #header form#api_selector .input input#input_baseUrl { + width: 400px; +} +.swagger-section #header form#api_selector .input a#explore { + display: block; + text-decoration: none; + font-weight: bold; + padding: 6px 8px; + font-size: 0.9em; + color: white; + background-color: #547f00; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -o-border-radius: 4px; + -ms-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; +} +.swagger-section #header form#api_selector .input a#explore:hover { + background-color: #547f00; +} +.swagger-section #header form#api_selector .input input { + font-size: 0.9em; + padding: 3px; + margin: 0; +} +.swagger-section #content_message { + margin: 10px 15px; + font-style: italic; + color: #999999; +} +.swagger-section #message-bar { + min-height: 30px; + text-align: center; + padding-top: 10px; +} diff --git a/app/code/Magento/Swagger/view/frontend/web/css/style.css b/app/code/Magento/Swagger/view/frontend/web/css/style.css new file mode 100644 index 0000000000000..fc21a31db547c --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/css/style.css @@ -0,0 +1,250 @@ +.swagger-section #header a#logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo.png) no-repeat left center; + padding: 20px 0 20px 40px; +} +#text-head { + font-size: 80px; + font-family: 'Roboto', sans-serif; + color: #ffffff; + float: right; + margin-right: 20%; +} +.navbar-fixed-top .navbar-nav { + height: auto; +} +.navbar-fixed-top .navbar-brand { + height: auto; +} +.navbar-header { + height: auto; +} +.navbar-inverse { + background-color: #000; + border-color: #000; +} +#navbar-brand { + margin-left: 20%; +} +.navtext { + font-size: 10px; +} +.h1, +h1 { + font-size: 60px; +} +.navbar-default .navbar-header .navbar-brand { + color: #a2dfee; +} +/* tag titles */ +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #393939; + font-family: 'Arvo', serif; + font-size: 1.5em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #525252; + padding-left: 0px; + display: block; + clear: none; + float: left; + font-family: 'Arvo', serif; + font-weight: bold; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #0A0A0A; +} +.container1 { + width: 1500px; + margin: auto; + margin-top: 0; + background-image: url('../images/shield.png'); + background-repeat: no-repeat; + background-position: -40px -20px; + margin-bottom: 210px; +} +.container-inner { + width: 1200px; + margin: auto; + background-color: rgba(223, 227, 228, 0.75); + padding-bottom: 40px; + padding-top: 40px; + border-radius: 15px; +} +.header-content { + padding: 0; + width: 1000px; +} +.title1 { + font-size: 80px; + font-family: 'Vollkorn', serif; + color: #404040; + text-align: center; + padding-top: 40px; + padding-bottom: 100px; +} +#icon { + margin-top: -18px; +} +.subtext { + font-size: 25px; + font-style: italic; + color: #08b; + text-align: right; + padding-right: 250px; +} +.bg-primary { + background-color: #00468b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:focus { + color: #08b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:hover { + color: #08b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:focus:hover { + color: #08b; +} +.text-faded { + font-size: 25px; + font-family: 'Vollkorn', serif; +} +.section-heading { + font-family: 'Vollkorn', serif; + font-size: 45px; + padding-bottom: 10px; +} +hr { + border-color: #00468b; + padding-bottom: 10px; +} +.description { + margin-top: 20px; + padding-bottom: 200px; +} +.description li { + font-family: 'Vollkorn', serif; + font-size: 25px; + color: #525252; + margin-left: 28%; + padding-top: 5px; +} +.gap { + margin-top: 200px; +} +.troubleshootingtext { + color: rgba(255, 255, 255, 0.7); + padding-left: 30%; +} +.troubleshootingtext li { + list-style-type: circle; + font-size: 25px; + padding-bottom: 5px; +} +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} +.block.response_body.json:hover { + cursor: pointer; +} +.backdrop { + color: blue; +} +#myModal { + height: 100%; +} +.modal-backdrop { + bottom: 0; + position: fixed; +} +.curl { + padding: 10px; + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; + max-height: 400px; + margin-top: 5px; + overflow-y: auto; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + border-radius: 4px; +} +.curl_title { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; + font-family: 'Open Sans', 'Helvetica Neue', Arial, sans-serif; + font-weight: 500; + line-height: 1.1; +} +.footer { + display: none; +} +.swagger-section .swagger-ui-wrap h2 { + padding: 0; +} +h2 { + margin: 0; + margin-bottom: 5px; +} +.markdown p { + font-size: 15px; + font-family: 'Arvo', serif; +} +.swagger-section .swagger-ui-wrap .code { + font-size: 15px; + font-family: 'Arvo', serif; +} +.swagger-section .swagger-ui-wrap b { + font-family: 'Arvo', serif; +} +#signin:hover { + cursor: pointer; +} +.dropdown-menu { + padding: 15px; +} +.navbar-right .dropdown-menu { + left: 0; + right: auto; +} +#signinbutton { + width: 100%; + height: 32px; + font-size: 13px; + font-weight: bold; + color: #08b; +} +.navbar-default .nav > li .details { + color: #000000; + text-transform: none; + font-size: 15px; + font-weight: normal; + font-family: 'Open Sans', sans-serif; + font-style: italic; + line-height: 20px; + top: -2px; +} +.navbar-default .nav > li .details:hover { + color: black; +} +#signout { + width: 100%; + height: 32px; + font-size: 13px; + font-weight: bold; + color: #08b; +} diff --git a/app/code/Magento/Swagger/view/frontend/web/css/typography.css b/app/code/Magento/Swagger/view/frontend/web/css/typography.css new file mode 100644 index 0000000000000..27c3751ac2ebb --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/css/typography.css @@ -0,0 +1,26 @@ +/* droid-sans-regular - latin */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 400; + src: url('../fonts/droid-sans-v6-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Droid Sans'), local('DroidSans'), + url('../fonts/droid-sans-v6-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/droid-sans-v6-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/droid-sans-v6-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/droid-sans-v6-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/droid-sans-v6-latin-regular.svg#DroidSans') format('svg'); /* Legacy iOS */ +} +/* droid-sans-700 - latin */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 700; + src: url('../fonts/droid-sans-v6-latin-700.eot'); /* IE9 Compat Modes */ + src: local('Droid Sans Bold'), local('DroidSans-Bold'), + url('../fonts/droid-sans-v6-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/droid-sans-v6-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/droid-sans-v6-latin-700.woff') format('woff'), /* Modern Browsers */ + url('../fonts/droid-sans-v6-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/droid-sans-v6-latin-700.svg#DroidSans') format('svg'); /* Legacy iOS */ +} diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.eot b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.eot new file mode 100644 index 0000000000000000000000000000000000000000..d8524983ad8d296be95cb5b469efd1987d6e04e3 GIT binary patch literal 22922 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 b()wT*kWXAeMzX)G0;aHJLU2Us_FHkFnk)~p literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.svg b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.svg new file mode 100644 index 0000000000000..a54bbbbf258aa --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.ttf b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.ttf new file mode 100644 index 0000000000000000000000000000000000000000..15896c441fd59e5c2e9bdab90816661de06cdcba GIT binary patch literal 40513 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

N`?RC`@lwXbC3bfgCS&z9};Se$Q$7 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 literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.woff2 b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1e726a7cfce4130243a3de4bb2bd412000658896 GIT binary patch literal 11480 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 literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.eot b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..ac2698e85aee584b0f47c0cccff8a8b9b16a5c66 GIT binary patch literal 22008 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%0AA9nOF`EcNA#X$~6CRi6AAT-xXx{3Bx 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 M4w+BmWsNjR(0tp4%K!iX literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.svg b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.svg new file mode 100644 index 0000000000000..d9f2a214f9629 --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.ttf b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fb8cea662b2434571debae37fa6ba09fc5f24776 GIT binary patch literal 39069 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%0AhF2i0VuZL#GkvKsN76iB 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 literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.woff b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..abf19899f75a0e8ab8e2d41caeecd8d764d3f08c GIT binary patch literal 24868 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 X8CoUMY*lMRVpH6ur?CLJX!hLz`Fb1d literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.woff2 b/app/code/Magento/Swagger/view/frontend/web/fonts/droid-sans-v6-latin-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9f93f74c3bede4b96290650f7a21c98eb1e01351 GIT binary patch literal 11304 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 literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/images/favicon-32x32.png b/app/code/Magento/Swagger/view/frontend/web/images/favicon-32x32.png new file mode 100755 index 0000000000000000000000000000000000000000..32f319f89bd07e691de2ccaf21632bb9793a9cd9 GIT binary patch literal 1654 zcmV-+28sEJP)Z zYjBlU6^5U+_c^%{LI@BBNTw~6nu{hdI!rrEwGFgm#aci_3sGk}<7m?sf9eb^ z&gef46cL=-R%Vz2t>aV&tTwa+k{T7cTawZs4M`*flAN4x@8yqkX_Av0()aswzFB*( z_g(v2XYI9wX~KJNyap8@D?yj3`UN7k2td_e5i#!rt)NGYgj$R-e!9LVh4Vp9;GzxA zMK7v)oerFfUJTsuv(5*(Q~8(4BX%1_Ls=xV0tMmqzMUI4PvXOov* zN@+ngMR`jQiMjRax>fZ#BX;*hCo--8?_I7}_iH1eH6lVJdXsn0?&9dFMn390GigKx zvpz#@c|A3YzfF2L8&$=tJ7mOs!x(#QN&()xLa+W!YeGv@mDYd1!hz-=a(&=GlM;_b zPG%vitA9$x!Y2?Bybn%_m{rEu%M%KSMehG%O=wBrhS}Hj9gdybeM`h+QN3s*YnL|? zvgvUVc7-t}c@jwh@o&E0n$ViS4YT|3W1Q?bbX(*J+;!)d`PKvb6Cw_Y*hdmMVUhyW zZ8T!ns4DxK>OV1ZfPY>3J+HpK1yx1F)_HZC5;g(w-sLEI-iR$|x$s+l^XGNR&0(9# z+U1ShGrx|W{)=pX?Y>FLo_?g2xjCQaWXJ2g+O&meFp#vZ`{G`z$~NHDbpvJAgsz!b z^uFGREr>*Ka-jL?Q4VX$H&eA}1J?(yaQ5=yDWg5td6>SNom7^sV|jV~DBHp21|rcL z7_oCzwI0BD?~T9~fOpTln3C=D^Q!>ZbNFi<93yT#96a8@?!#XNptPWRl&yd8BaWWl z34kD5y!Xa<4JwQYEl^dOPB*4F%u0_Hvw`81zwm@e6sU}FPKxd5=|)r)V{EC{pvuH* zJ6!Jl2VH$<$8i_SQ&l%@0nSHJRgly=clG*tI(ymx5M-qRT?Ww6)jY1Vth8L5k8)$E zd)fkqhWl`Sm>KDF#NbSZjd4f1W4iLB@ygIB2Q(Evj zKI~~rAs@*lV&6Bw-ypSUBrp)UhBaZbGx8@q#<9o<&%&CtWIY&*`2|&ppREQs0#KB< zgo0U%##!zYYNsv0+Hfp4R8wsEISVP7vn=s?#2B$H-n(`Yp>|B|1{jR=0g#zCWqX%I zR@!U;hN9O~Y_;X}i3a5ZBlfs4#&|`42~e~6Npdm^M{Vf1dK`d_D_^Fr>iH?jAFkZS zH}BsU+uL<~lx=2a0X5~D0Z?>@F~%DJ5oz@5yVJwjtghZZYSYovJ2-LvC30t!u()K^ zlmg02Rxx|VJX$Zjl5)4yRc$9DJQJ_JTg3bVMs!5ZMK_7qUje-Q*G)8^+cPEEt)Q}O zJ?p-(7XYvB$&d~2f)O2&h~4AW9TE}NE^p+nc@KSJTfS+;@4SL}@UgYJ}w)Q)V=$7{=rRQ;RAgzi>VS}wfAf#wGK z2d~@`@yyISSY5T9%ChzGtaqnG%mc=liQDoKB63yzUJ+Xt8%%ES&Y7Jwo!-IKzH^fj z=jW7BTfT+b^39}&XT}GU;0+^o{j>&?k41Rn)ol`yZ6ims&fdS%-gS)L{`TapmX$u6 zyqTqx=2ufZ=iU*cneSC~&lw5r`oD)&=Y!n94L=*WXvefB)7Ws@5xC*4w>6xOb0Q(H zL4_bI75%KLUtq)*#v*lBL~MLK=dE~!3#Q}ufBOd*=m{K;N&o-=07*qoM6N<$g6kDD A00000 literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/images/favicon.ico b/app/code/Magento/Swagger/view/frontend/web/images/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..8b60bcf06a7685b9ea53983c125e7058906fbcbd GIT binary patch literal 5430 zcmcgwYiv|S6douFYJ&9 zoHH|LSE(UtsLIS#7_-&1VM>ivN@Zu;-zA{00&N^|8r`@w~u}3a1X>=27;pf_a{DPJMTR$JSvjrVZRL?J~Ga>i0GO0Y%B;(7M$}2m+kcrz@>Hae2Pk^@b^f8%H zL>`N;qJuC@Oe+t~7I z<(F|AfU$#EfN{kFKA+53u@A<+4YnEIf**{2=CuCE#{h4Wo9v-X#BN#D=ro%g~u zG`=OQBiQEDZgc6n2RYf*+oRWbKVZW9eJJuGNa8A-F{8(f+y@)q2tylad}QmVTBh{m zkpvl@O*Y<9#KzvA;3if`|g4qjlr75YyFqbGlV2Q--{B?*ERj@$;+A#v6A5% zKJZ-k(ti_bGM?eOj#f{ZHOKc6lK8&sk-j?4Kdjr4z{}bU>r#UnlQAQ!`bOZB;Ct>?+|WpbgrOY2zPu-B!V?-m447=gVK(*?-RQObKSO{281uhZ-RJZ_ax0d9HE}&gAII8uJO7-x&ULT3$-hG# zr#*GDR$v46R``GL&)??M=Z|+Z8{*GeE`I+!{6E}3tWV7S1MCU*9ccYQdsa7AC-|$l z32U8*#-^_c?O%nK{oI ze@n2sr7p*=%uQX9Dk-qo-r2V)7}P0ZWaab6B%)NcuSZfL*ZERjG4kd;J~ udLgV-)@7w`Z&hkIdqAlS_J#Nx!E}|RnRSkVm|Sa24|P&EF^Huxf&C8$As%)B literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/images/logo_small.png b/app/code/Magento/Swagger/view/frontend/web/images/logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..5496a65579ae903d4008f9d268fac422ef9d3679 GIT binary patch literal 770 zcmV+d1O5DoP)K11rQipnJ)eVnTSzHNF zN8ab&RhE5cC$$4FI-PZXx$pga@8yN)KS}L2Us~^y$(x-xioWbnFcV+~b9ig=!ft8Q z0RD+rpA8910Smyc0GviVUOPGiY6YM@-r6Nn8S&~cxHl27$l)-R$1(!Xx045RDy;_& zeXkG{;_#i9rz0B6149#Ddj=KM6MV^rTD%ylzGdCBX<^=^@I0X3SCR7OMbn}sUKdeF zKO-flaJa%@kJ27@Rod?J9=+Qx5|=PtG8n> zy~9rIu}+48M}FW5Bbqw3t#po?c?kmG!FX32W(dOjzTb+U@64MzHItoeB!M0Jcd}|E z>ekW`<~FjR_ZVVJkF|_htH&v!({Oad?xax?0K0sLwBY%nr46DpCmIIaa?@|Y&?n0q z@kJlMy`pE2HtEgASNd~xNzt$Kn7w#^Fy5oi`e$bUE*+f>Vk5z7=-2pj68afrqli$_ zvqe##5V?a)QU_-s9+s?mJYT5m`MQDRH4cYs^L1lCW;Dua5Ln9lG0BC@9DJQHA(}y&Z}$apb{kU zbezR}b^|O%6i+$BFsT3zqAe8wg9`vfiRp#{)z2bsJw`vBQL7Bt!IexM3$Hsf0tHK3 z+R=x{lR$K`s;7__?ASPW=3?*xgCpGaiadSEpoi0pw-_V#OXM8Ap{4qlG08x0ig9IY z3Ijqh(t1_=g#jocuqyJO=729e9OSiNDSrhR0Gc5G)(QGH?*IS*07*qoM6N<$f<~fU A82|tP literal 0 HcmV?d00001 diff --git a/app/code/Magento/Swagger/view/frontend/web/images/pet_store_api.png b/app/code/Magento/Swagger/view/frontend/web/images/pet_store_api.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f9cd4aeb35a108c4b2f1dddb59977d56c595d8 GIT binary patch literal 824 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 z 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. + * For example - + * + * If you wish to translate some new texsts you should do two things: + * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. + * 2. Mark that text it templates this way New Phrase or . + * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate. + * + */ +window.SwaggerTranslator = { + + _words:[], + + translate: function(sel) { + var $this = this; + sel = sel || '[data-sw-translate]'; + + $(sel).each(function() { + $(this).html($this._tryTranslate($(this).html())); + + $(this).val($this._tryTranslate($(this).val())); + $(this).attr('title', $this._tryTranslate($(this).attr('title'))); + }); + }, + + _tryTranslate: function(word) { + return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; + }, + + learn: function(wordsMap) { + this._words = wordsMap; + } +}; diff --git a/app/code/Magento/Swagger/view/frontend/web/js/lib/backbone-min.js b/app/code/Magento/Swagger/view/frontend/web/js/lib/backbone-min.js new file mode 100644 index 0000000000000..a3f544be6d9e8 --- /dev/null +++ b/app/code/Magento/Swagger/view/frontend/web/js/lib/backbone-min.js @@ -0,0 +1,15 @@ +// Backbone.js 1.1.2 + +(function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('