diff --git a/src/Action/ActionUtilTrait.php b/src/Action/ActionUtilTrait.php deleted file mode 100644 index c515270e2ec..00000000000 --- a/src/Action/ActionUtilTrait.php +++ /dev/null @@ -1,80 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ApiPlatform\Core\Action; - -use ApiPlatform\Core\Api\ItemDataProviderInterface; -use ApiPlatform\Core\Exception\RuntimeException; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; - -/** - * Checks if the request is properly configured. - * - * @author Kévin Dunglas - */ -trait ActionUtilTrait -{ - /** - * Gets an item using the data provider. Throws a 404 error if not found. - * - * @param ItemDataProviderInterface $itemDataProvider - * @param string $resourceClass - * @param string $operationName - * @param string|int $id - * - * @throws NotFoundHttpException - * - * @return object - */ - private function getItem(ItemDataProviderInterface $itemDataProvider, string $resourceClass, string $operationName, $id) - { - $data = $itemDataProvider->getItem($resourceClass, $id, $operationName, true); - if (!$data) { - throw new NotFoundHttpException('Not Found'); - } - - return $data; - } - - /** - * Extract resource class, operation name and format request attributes. Throws an exception if the request does not contain required - * attributes. - * - * @param Request $request - * - * @throws RuntimeException - * - * @return array - */ - private function extractAttributes(Request $request) - { - $resourceClass = $request->attributes->get('_resource_class'); - - if (!$resourceClass) { - throw new RuntimeException('The request attribute "_resource_class" must be defined.'); - } - - $collectionOperation = $request->attributes->get('_collection_operation_name'); - $itemOperation = $request->attributes->get('_item_operation_name'); - - if (!$itemOperation && !$collectionOperation) { - throw new RuntimeException('One of the request attribute "_item_operation_name" or "_collection_operation_name" must be defined.'); - } - - $format = $request->attributes->get('_api_format'); - if (!$format) { - throw new RuntimeException('The request attribute "_api_format" must be defined.'); - } - - return [$resourceClass, $collectionOperation, $itemOperation, $format]; - } -} diff --git a/src/Action/PutItemAction.php b/src/Action/PutItemAction.php deleted file mode 100644 index d572ab1f6d2..00000000000 --- a/src/Action/PutItemAction.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace ApiPlatform\Core\Action; - -use ApiPlatform\Core\Api\ItemDataProviderInterface; -use ApiPlatform\Core\Exception\RuntimeException; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\Serializer\SerializerInterface; - -/** - * Updates a resource. - * - * @author Kévin Dunglas - */ -final class PutItemAction -{ - use ActionUtilTrait; - - private $itemDataProvider; - private $serializer; - - public function __construct(ItemDataProviderInterface $itemDataProvider, SerializerInterface $serializer) - { - $this->itemDataProvider = $itemDataProvider; - $this->serializer = $serializer; - } - - /** - * Create a new item. - * - * @param Request $request - * @param string|int $id - * - * @throws NotFoundHttpException - * @throws RuntimeException - * - * @return mixed - */ - public function __invoke(Request $request, $id) - { - list($resourceClass, , $operationName, $format) = $this->extractAttributes($request); - $data = $this->getItem($this->itemDataProvider, $resourceClass, $operationName, $id); - - $context = ['object_to_populate' => $data, 'resource_class' => $resourceClass, 'item_operation_name' => $operationName]; - - return $this->serializer->deserialize($request->getContent(), $resourceClass, $format, $context); - } -} diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index 8d50156964f..301a47fa059 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -60,26 +60,38 @@ - + - + + + + + + + + + + - + + - - + + + - - + + + - + diff --git a/src/Exception/NotFoundHttpException.php b/src/Exception/NotFoundHttpException.php new file mode 100644 index 00000000000..96bfd673dec --- /dev/null +++ b/src/Exception/NotFoundHttpException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Exception; + +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException as SymfonyNotFoundHttpException; + +/** + * @author Théo FIDRY + */ +class NotFoundHttpException extends SymfonyNotFoundHttpException implements ExceptionInterface +{ + +} diff --git a/src/Action/GetCollectionAction.php b/src/Http/Action/GetCollectionAction.php similarity index 63% rename from src/Action/GetCollectionAction.php rename to src/Http/Action/GetCollectionAction.php index 51a531cddd4..fb8f3378737 100644 --- a/src/Action/GetCollectionAction.php +++ b/src/Http/Action/GetCollectionAction.php @@ -14,6 +14,7 @@ use ApiPlatform\Core\Api\CollectionDataProviderInterface; use ApiPlatform\Core\Api\PaginatorInterface; use ApiPlatform\Core\Exception\RuntimeException; +use ApiPlatform\Core\Http\RequestAttributesExtractorInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -23,13 +24,20 @@ */ final class GetCollectionAction { - use ActionUtilTrait; - + /** + * @var CollectionDataProviderInterface + */ private $collectionDataProvider; - public function __construct(CollectionDataProviderInterface $collectionDataProvider) + /** + * @var RequestAttributesExtractorInterface + */ + private $attributesExtractor; + + public function __construct(CollectionDataProviderInterface $collectionDataProvider, RequestAttributesExtractorInterface $attributesExtractor) { $this->collectionDataProvider = $collectionDataProvider; + $this->attributesExtractor = $attributesExtractor; } /** @@ -43,8 +51,11 @@ public function __construct(CollectionDataProviderInterface $collectionDataProvi */ public function __invoke(Request $request) { - list($resourceClass, $operationName) = $this->extractAttributes($request); + $attributesBag = $this->attributesExtractor->extract($request); - return $this->collectionDataProvider->getCollection($resourceClass, $operationName); + return $this->collectionDataProvider->getCollection( + $attributesBag->getResourceClass(), + $attributesBag->getCollectionOperationName() + ); } } diff --git a/src/Action/GetItemAction.php b/src/Http/Action/GetItemAction.php similarity index 56% rename from src/Action/GetItemAction.php rename to src/Http/Action/GetItemAction.php index c9616ddde50..d80e6ba0924 100644 --- a/src/Action/GetItemAction.php +++ b/src/Http/Action/GetItemAction.php @@ -9,10 +9,12 @@ * file that was distributed with this source code. */ -namespace ApiPlatform\Core\Action; +namespace ApiPlatform\Core\Http\Action; use ApiPlatform\Core\Api\ItemDataProviderInterface; use ApiPlatform\Core\Exception\RuntimeException; +use ApiPlatform\Core\Http\ItemDataProvider; +use ApiPlatform\Core\Http\RequestAttributesExtractorInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -23,13 +25,20 @@ */ final class GetItemAction { - use ActionUtilTrait; - + /** + * @var ItemDataProvider + */ private $itemDataProvider; - public function __construct(ItemDataProviderInterface $itemDataProvider) + /** + * @var RequestAttributesExtractorInterface + */ + private $attributesExtractor; + + public function __construct(ItemDataProviderInterface $itemDataProvider, RequestAttributesExtractorInterface $attributesExtractor) { - $this->itemDataProvider = $itemDataProvider; + $this->itemDataProvider = new ItemDataProvider($itemDataProvider); + $this->attributesExtractor = $attributesExtractor; } /** @@ -45,8 +54,13 @@ public function __construct(ItemDataProviderInterface $itemDataProvider) */ public function __invoke(Request $request, $id) { - list($resourceClass, , $operationName) = $this->extractAttributes($request); + $attributesBag = $this->attributesExtractor->extract($request); - return $this->getItem($this->itemDataProvider, $resourceClass, $operationName, $id); + return $this->itemDataProvider->getItem( + $this->itemDataProvider, + $attributesBag->getResourceClass(), + $attributesBag->getItemOperationName(), + $id + ); } } diff --git a/src/Action/PostCollectionAction.php b/src/Http/Action/PostCollectionAction.php similarity index 50% rename from src/Action/PostCollectionAction.php rename to src/Http/Action/PostCollectionAction.php index 3d461546263..d3dff25b6dd 100644 --- a/src/Action/PostCollectionAction.php +++ b/src/Http/Action/PostCollectionAction.php @@ -12,6 +12,7 @@ namespace ApiPlatform\Core\Action; use ApiPlatform\Core\Exception\RuntimeException; +use ApiPlatform\Core\Http\RequestAttributesExtractorInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Serializer\SerializerInterface; @@ -22,13 +23,20 @@ */ final class PostCollectionAction { - use ActionUtilTrait; - + /** + * @var SerializerInterface + */ private $serializer; - public function __construct(SerializerInterface $serializer) + /** + * @var RequestAttributesExtractorInterface + */ + private $attributesExtractor; + + public function __construct(SerializerInterface $serializer, RequestAttributesExtractorInterface $attributesExtractor) { $this->serializer = $serializer; + $this->attributesExtractor = $attributesExtractor; } /** @@ -42,9 +50,17 @@ public function __construct(SerializerInterface $serializer) */ public function __invoke(Request $request) { - list($resourceClass, $operationName, , $format) = $this->extractAttributes($request); - $context = ['resource_class' => $resourceClass, 'collection_operation_name' => $operationName]; + $attributesBag = $this->attributesExtractor->extract($request); + $context = [ + 'resource_class' => $attributesBag->getResourceClass(), + 'collection_operation_name' => $attributesBag->getCollectionOperationName() + ]; - return $this->serializer->deserialize($request->getContent(), $resourceClass, $format, $context); + return $this->serializer->deserialize( + $request->getContent(), + $attributesBag->getResourceClass(), + $attributesBag->getFormat(), + $context + ); } } diff --git a/src/Http/Action/PutItemAction.php b/src/Http/Action/PutItemAction.php new file mode 100644 index 00000000000..a30f7de1e8d --- /dev/null +++ b/src/Http/Action/PutItemAction.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Action; + +use ApiPlatform\Core\Api\ItemDataProviderInterface; +use ApiPlatform\Core\Exception\RuntimeException; +use ApiPlatform\Core\Http\ItemDataProvider; +use ApiPlatform\Core\Http\RequestAttributesExtractorInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Serializer\SerializerInterface; + +/** + * Updates a resource. + * + * @author Kévin Dunglas + */ +final class PutItemAction +{ + /** + * @var ItemDataProvider + */ + private $itemDataProvider; + private $serializer; + private $attributesExtractor; + + public function __construct(ItemDataProviderInterface $itemDataProvider, SerializerInterface $serializer, RequestAttributesExtractorInterface $attributesExtractor) + { + $this->itemDataProvider = new ItemDataProvider($itemDataProvider); + $this->serializer = $serializer; + $this->attributesExtractor = $attributesExtractor; + } + + /** + * Create a new item. + * + * @param Request $request + * @param string|int $id + * + * @throws NotFoundHttpException + * @throws RuntimeException + * + * @return mixed + */ + public function __invoke(Request $request, $id) + { + $attributesBag = $this->attributesExtractor->extract($request); + $data = $this->itemDataProvider->getItem( + $this->itemDataProvider, + $attributesBag->getResourceClass(), + $attributesBag->getItemOperationName(), + $id + ); + $context = [ + 'object_to_populate' => $data, + 'resource_class' => $attributesBag->getResourceClass(), + 'item_operation_name' => $attributesBag->getItemOperationName() + ]; + + return $this->serializer->deserialize( + $request->getContent(), + $attributesBag->getResourceClass(), + $attributesBag->getFormat(), + $context + ); + } +} diff --git a/src/Http/AttributesBag.php b/src/Http/AttributesBag.php new file mode 100644 index 00000000000..6485cbcfb5c --- /dev/null +++ b/src/Http/AttributesBag.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Http; + +/** + * @author Théo FIDRY + */ +final class AttributesBag +{ + /** + * @var string|null + */ + private $collectionOperationName; + + /** + * @var string|null + */ + private $itemOperationName; + + /** + * @var string + */ + private $format; + + /** + * @var string + */ + private $resourceClass; + + /** + * @param string $resourceClass Resource FQCN + * @param string|null $collectionOperationName Example: 'get', 'post', etc. + * @param string|null $itemOperationName Example: 'get', 'post', etc. + * @param string $format Example: 'jsonld' + */ + public function __construct( + string $resourceClass, + string $collectionOperationName = null, + string $itemOperationName = null, + string $format + ) { + $this->resourceClass = $resourceClass; + $this->collectionOperationName = $collectionOperationName; + $this->itemOperationName = $itemOperationName; + $this->format = $format; + } + + /** + * @return string|null Is null if is an item operation + * + * @example + * 'get', 'post', etc. + */ + public function getCollectionOperationName() + { + return $this->collectionOperationName; + } + + /** + * @return string|null Is null if is a collection operation + * + * @example + * 'get', 'post', etc. + */ + public function getItemOperationName() + { + return $this->itemOperationName; + } + + /** + * @return string + * + * @example + * 'jsonld' + */ + public function getFormat() + { + return $this->format; + } + + /** + * @return string Resource FQCN + */ + public function getResourceClass() + { + return $this->resourceClass; + } +} diff --git a/src/Http/ItemDataProvider.php b/src/Http/ItemDataProvider.php new file mode 100644 index 00000000000..77a8a9f8ade --- /dev/null +++ b/src/Http/ItemDataProvider.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Http; + +use ApiPlatform\Core\Api\ItemDataProviderInterface; +use ApiPlatform\Core\Exception\ExceptionInterface; +use ApiPlatform\Core\Exception\InvalidArgumentException; +use ApiPlatform\Core\Exception\NotFoundHttpException; +use ApiPlatform\Core\Exception\ResourceClassNotSupportedException; + +/** + * @author Théo FIDRY + */ +final class ItemDataProvider implements ItemDataProviderInterface +{ + /** + * @var ItemDataProviderInterface + */ + private $decoratedProvider; + + public function __construct(ItemDataProviderInterface $decoratedProvider) + { + $this->decoratedProvider = $decoratedProvider; + } + + /** + * {@inheritdoc} + * + * @throws ResourceClassNotSupportedException + * @throws NotFoundHttpException + * @throws ExceptionInterface + */ + public function getItem(string $resourceClass, $id, string $operationName = null, bool $fetchData = false) + { + $data = $this->decoratedProvider->getItem($resourceClass, $id, $operationName, true); + if (null !== $data) { + return $data; + } + + throw new NotFoundHttpException('Not Found'); + } +} diff --git a/src/Http/RequestAttributesExtractor.php b/src/Http/RequestAttributesExtractor.php new file mode 100644 index 00000000000..c397c137f69 --- /dev/null +++ b/src/Http/RequestAttributesExtractor.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Http; + +use ApiPlatform\Core\Exception\RuntimeException; +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Théo FIDRY + */ +final class RequestAttributesExtractor implements RequestAttributesExtractorInterface +{ + /** + * {@inheritdoc} + */ + public function extract(Request $request) + { + $resourceClass = $this->retrieveAttribute($request, '_resource_class'); + + try { + $collectionOperation = $this->retrieveAttribute($request, '_collection_operation_name'); + $itemOperation = null; + } catch (RuntimeException $exception) { + try { + $collectionOperation = null; + $itemOperation = $this->retrieveAttribute($request, '_item_operation_name'); + } catch (RuntimeException $exception) { + throw new RuntimeException('One of the request attribute "_item_operation_name" or "_collection_operation_name" must be defined.'); + } + } + + $format = $this->retrieveAttribute($request, '_api_format'); + + return new AttributesBag($resourceClass, $collectionOperation, $itemOperation, $format); + } + + /** + * @param Request $request + * @param string $attributeName + * + * @throws RuntimeException + * + * @return string + */ + private function retrieveAttribute(Request $request, string $attributeName) + { + $attribute = $request->attributes->get('_resource_class'); + + if (null === $attribute) { + throw new RuntimeException(sprintf('The request attribute "%s" must be defined.', $attributeName)); + } + + if (!is_string($attribute)) { + throw new RuntimeException(sprintf('The request attribute "%s" must be a string.', $attributeName)); + } + + return $attribute; + } +} diff --git a/src/Http/RequestAttributesExtractorInterface.php b/src/Http/RequestAttributesExtractorInterface.php new file mode 100644 index 00000000000..dca79ed3d06 --- /dev/null +++ b/src/Http/RequestAttributesExtractorInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Http; + +use ApiPlatform\Core\Exception\RuntimeException; +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Théo FIDRY + */ +interface RequestAttributesExtractorInterface +{ + /** + * Extract resource class, operation name and format request attributes. Throws an exception if the request does + * not contain required attributes. + * + * @param Request $request + * + * @throws RuntimeException + * + * @return AttributesBag + */ + public function extract(Request $request); +} diff --git a/tests/Http/AttributesBagTest.php b/tests/Http/AttributesBagTest.php new file mode 100644 index 00000000000..00cb3c29e5c --- /dev/null +++ b/tests/Http/AttributesBagTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Tests\Http; + +use ApiPlatform\Core\Http\AttributesBag; + +/** + * @covers ApiPlatform\Core\Http\AttributesBag + * + * @author Théo FIDRY + */ +class AttributesBagTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideArguments + */ + public function testConstruct($resourceClass, $collectionOperationName, $itemOperationName, $format) + { + $bag = new AttributesBag($resourceClass, $collectionOperationName, $itemOperationName, $format); + + $this->assertEquals($resourceClass, $bag->getResourceClass()); + $this->assertEquals($collectionOperationName, $bag->getCollectionOperationName()); + $this->assertEquals($itemOperationName, $bag->getItemOperationName()); + $this->assertEquals($format, $bag->getFormat()); + } + + public function provideArguments() + { + yield [ + 'App\Entity\Dummy', + 'get', + 'post', + 'jsonld', + ]; + + yield [ + 'App\Entity\Dummy', + 'delete', + null, + 'xml', + ]; + + yield [ + 'App\Entity\Dummy', + null, + 'put', + 'json', + ]; + } +} diff --git a/tests/Http/ItemDataProviderTest.php b/tests/Http/ItemDataProviderTest.php new file mode 100644 index 00000000000..c9e5bf37cea --- /dev/null +++ b/tests/Http/ItemDataProviderTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Tests\Http; + +use ApiPlatform\Core\Api\ItemDataProviderInterface; +use ApiPlatform\Core\Http\ItemDataProvider; + +/** + * @covers ApiPlatform\Core\Http\ItemDataProvider + * + * @author Théo FIDRY + */ +class ItemDataProviderTest extends \PHPUnit_Framework_TestCase +{ + public function testDecoratesProvider() + { + $resourceClass = 'App\Entity\Dummy'; + $id = 200; + $operationName = 'get'; + $fetchData = true; + $expectedItem = new \stdClass(); + + $decoratedProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + $decoratedProviderProphecy->getItem($resourceClass, $id, $operationName, $fetchData)->shouldBeCalledTimes(1); + $decoratedProviderProphecy->getItem($resourceClass, $id, $operationName, $fetchData)->willReturn($expectedItem); + /* @var ItemDataProviderInterface $decoratedProvider */ + $decoratedProvider = $decoratedProviderProphecy->reveal(); + + $provider = new ItemDataProvider($decoratedProvider); + $actualItem = $provider->getItem($resourceClass, $id, $operationName, $fetchData); + + $this->assertSame($expectedItem, $actualItem); + } + + /** + * @expectedException \ApiPlatform\Core\Exception\NotFoundHttpException + */ + public function testThrowExceptionWhenItemNotFound() + { + $resourceClass = 'App\Entity\Dummy'; + $id = 200; + $operationName = 'get'; + $fetchData = true; + + $decoratedProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + $decoratedProviderProphecy->getItem($resourceClass, $id, $operationName, $fetchData)->willReturn(null); + /* @var ItemDataProviderInterface $decoratedProvider */ + $decoratedProvider = $decoratedProviderProphecy->reveal(); + + $provider = new ItemDataProvider($decoratedProvider); + $provider->getItem($resourceClass, $id, $operationName, $fetchData); + } +} diff --git a/tests/Http/RequestAttributesExtractorTest.php b/tests/Http/RequestAttributesExtractorTest.php new file mode 100644 index 00000000000..0c96ca523a8 --- /dev/null +++ b/tests/Http/RequestAttributesExtractorTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Tests\Http; + +use ApiPlatform\Core\Http\RequestAttributesExtractor; +use Symfony\Component\HttpFoundation\ParameterBag; +use Symfony\Component\HttpFoundation\Request; + +/** + * @covers ApiPlatform\Core\Http\RequestAttributesExtractor + * + * @author Théo FIDRY + */ +class RequestAttributesExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var RequestAttributesExtractor + */ + private $extractor; + + public function setUp() + { + $this->extractor = new RequestAttributesExtractor(); + } + + /** + * @dataProvider provideValidRequest + */ + public function testExtractFromValidRequest($request, $expected) + { + $actual = $this->extractor->extract($request); + $this->assertEquals($expected, $actual); + } + + /** + * @dataProvider provideInvalidRequest + * @expectedException \ApiPlatform\Core\Exception\RuntimeException + */ + public function testExtractFromInvalidRequest($request) + { + $this->extractor->extract($request); + } + + public function provideValidRequest() + { + $resourceClass = 'App\Entity\Dummy'; + $collectionOperationName = 'get'; + $itemOperationName = null; + $format = 'jsonld'; + + $parameterBagProphecy = $this->prophesize(ParameterBag::class); + $parameterBagProphecy->get('_resource_class')->shouldBeCalledTimes(1); + $parameterBagProphecy->get('_resource_class')->willReturn($resourceClass); + $parameterBagProphecy->get('_collection_operation_name')->shouldBeCalledTimes(1); + $parameterBagProphecy->get('_collection_operation_name')->willReturn($collectionOperationName); + $parameterBagProphecy->get('_item_operation_name')->shouldBeCalledTimes(1); + $parameterBagProphecy->get('_item_operation_name')->willReturn($itemOperationName); + $parameterBagProphecy->get('_api_format')->shouldBeCalledTimes(1); + $parameterBagProphecy->get('_api_format')->willReturn($format); + /* @var ParameterBag $parameterBag */ + $parameterBag = $parameterBagProphecy->reveal(); + + $requestProphecy = $this->prophesize(Request::class); + $requestProphecy->initialize(Argument::cetera()) + } + + public function provideInvalidRequest() + { + //TODO + } +}