-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
325 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
parameters: | ||
ignoreErrors: | ||
- '#expects .*, PHPUnit_Framework_MockObject_MockObject given#' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Exception; | ||
|
||
/** | ||
* Exception represents error in the program logic. | ||
*/ | ||
class LogicException extends AbstractMatejException | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\RequestBuilder; | ||
|
||
use Lmc\Matej\Exception\LogicException; | ||
use Lmc\Matej\Http\RequestManager; | ||
use Lmc\Matej\Model\Request; | ||
use Lmc\Matej\Model\Response; | ||
|
||
/** | ||
* Request builders provides methods for simple and type-safe assembly of request to specific Matej endpoint. | ||
* | ||
* If `RequestManager` is injected to the builder via `setRequestManager()`, the request could be executed right from | ||
* the builder using `send()` method. | ||
*/ | ||
abstract class AbstractRequestBuilder | ||
{ | ||
/** @var RequestManager */ | ||
protected $requestManager; | ||
|
||
/** | ||
* Use Commands and other settings which were passed to this builder object to build instance of | ||
* Lmc\Matej\Model\Request. | ||
*/ | ||
abstract public function build(): Request; | ||
|
||
/** | ||
* If instance of RequestManager is injected to this builder object, you can build and send the request directly | ||
* via send() method of the builder itself. | ||
*/ | ||
public function setRequestManager(RequestManager $requestManager): self | ||
{ | ||
$this->requestManager = $requestManager; | ||
|
||
return $this; | ||
} | ||
|
||
public function send(): Response | ||
{ | ||
$this->assertRequestManagerIsAvailable(); | ||
|
||
return $this->requestManager->sendRequest($this->build()); | ||
} | ||
|
||
private function assertRequestManagerIsAvailable(): void | ||
{ | ||
if ($this->requestManager === null) { | ||
throw new LogicException( | ||
'Instance of RequestManager must be set to request builder via setRequestManager() before' | ||
. ' calling send()' | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\RequestBuilder; | ||
|
||
use Fig\Http\Message\RequestMethodInterface; | ||
use Lmc\Matej\Exception\LogicException; | ||
use Lmc\Matej\Model\Command\ItemPropertySetup; | ||
use Lmc\Matej\Model\Request; | ||
|
||
class ItemPropertiesSetupRequestBuilder extends AbstractRequestBuilder | ||
{ | ||
protected const ENDPOINT_PATH = '/item-properties'; | ||
|
||
/** @var ItemPropertySetup[] */ | ||
protected $commands = []; | ||
/** @var bool */ | ||
protected $willDelete = false; | ||
|
||
public function addProperty(ItemPropertySetup $itemPropertySetup): self | ||
{ | ||
$this->commands[] = $itemPropertySetup; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param ItemPropertySetup[] $itemPropertiesSetup | ||
* @return self | ||
*/ | ||
public function addProperties(array $itemPropertiesSetup): self | ||
{ | ||
foreach ($itemPropertiesSetup as $itemPropertySetup) { | ||
$this->addProperty($itemPropertySetup); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* Mark the request as "deleting" - item properties added to this request will be IRREVERSIBLY removed from | ||
* all items in the database and the item property will from now be rejected by Matej. | ||
*/ | ||
public function requestWillDelete(): self | ||
{ | ||
$this->willDelete = true; | ||
|
||
return $this; | ||
} | ||
|
||
public function build(): Request | ||
{ | ||
if (empty($this->commands)) { | ||
throw new LogicException( | ||
'At least one ItemPropertySetup command must be added to the builder before sending the request' | ||
); | ||
} | ||
|
||
$method = $this->willDelete ? RequestMethodInterface::METHOD_DELETE : RequestMethodInterface::METHOD_PUT; | ||
|
||
return new Request(self::ENDPOINT_PATH, $method, $this->commands); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\RequestBuilder; | ||
|
||
use Lmc\Matej\Http\RequestManager; | ||
|
||
/** | ||
* Factory to create concrete RequestBuilder which helps you to create request for each Matej API | ||
*/ | ||
class RequestBuilderFactory | ||
{ | ||
/** @var RequestManager */ | ||
private $requestManager; | ||
|
||
public function __construct(RequestManager $requestManager) | ||
{ | ||
$this->requestManager = $requestManager; | ||
} | ||
|
||
public function itemPropertiesSetup(): ItemPropertiesSetupRequestBuilder | ||
{ | ||
return $this->createConfiguredBuilder(ItemPropertiesSetupRequestBuilder::class); | ||
} | ||
|
||
// TODO: builders for other endpoints | ||
|
||
/** | ||
* @param string $builderClass | ||
* @param array ...$args | ||
* @return mixed | ||
*/ | ||
private function createConfiguredBuilder(string $builderClass, ...$args) | ||
{ | ||
/** @var AbstractRequestBuilder $requestBuilder */ | ||
$requestBuilder = new $builderClass(...$args); | ||
|
||
$requestBuilder->setRequestManager($this->requestManager); | ||
|
||
return $requestBuilder; | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
tests/RequestBuilder/ItemPropertiesSetupRequestBuilderTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\RequestBuilder; | ||
|
||
use Fig\Http\Message\RequestMethodInterface; | ||
use Lmc\Matej\Exception\LogicException; | ||
use Lmc\Matej\Http\RequestManager; | ||
use Lmc\Matej\Model\Command\ItemPropertySetup; | ||
use Lmc\Matej\Model\Request; | ||
use Lmc\Matej\Model\Response; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class ItemPropertiesSetupRequestBuilderTest extends TestCase | ||
{ | ||
/** @test */ | ||
public function shouldThrowExceptionWhenBuildingEmptyCommands(): void | ||
{ | ||
$builder = new ItemPropertiesSetupRequestBuilder(); | ||
|
||
$this->expectException(LogicException::class); | ||
$this->expectExceptionMessage('At least one ItemPropertySetup command must be added to the builder'); | ||
$builder->build(); | ||
} | ||
|
||
/** | ||
* @test | ||
* @dataProvider provideBuilderVariants | ||
*/ | ||
public function shouldBuildRequestWithCommands(bool $shouldDelete, string $expectedMethod): void | ||
{ | ||
$builder = new ItemPropertiesSetupRequestBuilder(); | ||
|
||
$command1 = ItemPropertySetup::timestamp('property1'); | ||
$command2 = ItemPropertySetup::string('property2'); | ||
$command3 = ItemPropertySetup::string('property3'); | ||
|
||
$builder->addProperty($command1); | ||
$builder->addProperties([$command2, $command3]); | ||
|
||
if ($shouldDelete) { | ||
$builder->requestWillDelete(); | ||
} | ||
|
||
$request = $builder->build(); | ||
|
||
$this->assertInstanceOf(Request::class, $request); | ||
$this->assertSame($expectedMethod, $request->getMethod()); | ||
$this->assertSame('/item-properties', $request->getPath()); | ||
$this->assertContainsOnlyInstancesOf(ItemPropertySetup::class, $request->getData()); | ||
$this->assertSame($command1, $request->getData()[0]); | ||
$this->assertSame($command2, $request->getData()[1]); | ||
$this->assertSame($command3, $request->getData()[2]); | ||
} | ||
|
||
/** | ||
* @return array[] | ||
*/ | ||
public function provideBuilderVariants(): array | ||
{ | ||
return [ | ||
'builder to create item properties' => [false, RequestMethodInterface::METHOD_PUT], | ||
'builder to delete item properties' => [true, RequestMethodInterface::METHOD_DELETE], | ||
]; | ||
} | ||
|
||
/** @test */ | ||
public function shouldThrowExceptionWhenSendingCommandsWithoutRequestManager(): void | ||
{ | ||
$builder = new ItemPropertiesSetupRequestBuilder(); | ||
|
||
$builder->addProperty(ItemPropertySetup::timestamp('property1')); | ||
|
||
$this->expectException(LogicException::class); | ||
$this->expectExceptionMessage('Instance of RequestManager must be set to request builder'); | ||
$builder->send(); | ||
} | ||
|
||
/** @test */ | ||
public function shouldSendRequestViaRequestManager(): void | ||
{ | ||
$requestManagerMock = $this->createMock(RequestManager::class); | ||
$requestManagerMock->expects($this->once()) | ||
->method('sendRequest') | ||
->with($this->isInstanceOf(Request::class)) | ||
->willReturn(new Response(0, 0, 0, 0)); | ||
|
||
$builder = new ItemPropertiesSetupRequestBuilder(); | ||
$builder->setRequestManager($requestManagerMock); | ||
|
||
$builder->addProperty(ItemPropertySetup::timestamp('property1')); | ||
|
||
$builder->send(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\RequestBuilder; | ||
|
||
use Lmc\Matej\Http\RequestManager; | ||
use Lmc\Matej\Model\Command\ItemPropertySetup; | ||
use Lmc\Matej\Model\Request; | ||
use Lmc\Matej\Model\Response; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* @covers \Lmc\Matej\RequestBuilder\RequestBuilderFactory | ||
*/ | ||
class RequestBuilderFactoryTest extends TestCase | ||
{ | ||
/** | ||
* @test | ||
* @dataProvider provideBuilderMethods | ||
*/ | ||
public function shouldInstantiateBuilderToBuildAndSendRequest( | ||
string $factoryMethod, | ||
string $expectedBuilderClass, | ||
\Closure $minimalBuilderInit | ||
): void { | ||
$requestManagerMock = $this->createMock(RequestManager::class); | ||
$requestManagerMock->expects($this->once()) | ||
->method('sendRequest') | ||
->with($this->isInstanceOf(Request::class)) | ||
->willReturn(new Response(0, 0, 0, 0)); | ||
|
||
$factory = new RequestBuilderFactory($requestManagerMock); | ||
|
||
/** @var AbstractRequestBuilder $builder */ | ||
$builder = $factory->$factoryMethod(); | ||
|
||
// Builders may require some minimal setup to be able to execute the build() method | ||
$minimalBuilderInit($builder); | ||
|
||
$this->assertInstanceOf($expectedBuilderClass, $builder); | ||
$this->assertInstanceOf(Request::class, $builder->build()); | ||
|
||
// Make sure the builder has been properly configured and it can execute send() via RequestManager mock: | ||
$this->assertInstanceOf(Response::class, $builder->send()); | ||
} | ||
|
||
/** | ||
* @return array[] | ||
*/ | ||
public function provideBuilderMethods(): array | ||
{ | ||
$itemPropertiesSetupInit = function (ItemPropertiesSetupRequestBuilder $builder): void { | ||
$builder->addProperty(ItemPropertySetup::timestamp('valid_from')); | ||
}; | ||
|
||
return [ | ||
['itemPropertiesSetup', ItemPropertiesSetupRequestBuilder::class, $itemPropertiesSetupInit], | ||
]; | ||
} | ||
} |