From f4e245db7435babb3afcffb39e17ed518eabb61f Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Mon, 17 Oct 2016 15:09:51 +0200 Subject: [PATCH 1/2] Added AddPathPlugin --- CHANGELOG.md | 2 +- spec/Plugin/AddPathPluginSpec.php | 64 +++++++++++++++++++++++++++++++ src/Plugin/AddPathPlugin.php | 48 +++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 spec/Plugin/AddPathPluginSpec.php create mode 100644 src/Plugin/AddPathPlugin.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fe5a4c8..dc57193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - Fix Emulated Trait to use Http based promise which respect the HttpAsyncClient interface - Require Httplug 1.1 where we use HTTP specific promises. - RedirectPlugin: use the full URL instead of the URI to properly keep track of redirects - +- Add AddPathPlugin for API URLs with base path ## 1.2.1 - 2016-07-26 diff --git a/spec/Plugin/AddPathPluginSpec.php b/spec/Plugin/AddPathPluginSpec.php new file mode 100644 index 0000000..a7ec9b5 --- /dev/null +++ b/spec/Plugin/AddPathPluginSpec.php @@ -0,0 +1,64 @@ +beConstructedWith($uri); + } + + function it_is_initializable(UriInterface $uri) + { + $uri->getPath()->shouldBeCalled()->willReturn('/api'); + + $this->shouldHaveType('Http\Client\Common\Plugin\AddPathPlugin'); + } + + function it_is_a_plugin(UriInterface $uri) + { + $uri->getPath()->shouldBeCalled()->willReturn('/api'); + + $this->shouldImplement('Http\Client\Common\Plugin'); + } + + function it_adds_path( + RequestInterface $request, + UriInterface $host, + UriInterface $uri + ) { + $host->getPath()->shouldBeCalled()->willReturn('/api'); + + $request->getUri()->shouldBeCalled()->willReturn($uri); + $request->withUri($uri)->shouldBeCalled()->willReturn($request); + + $uri->withPath('/api/users')->shouldBeCalled()->willReturn($uri); + $uri->getPath()->shouldBeCalled()->willReturn('/users'); + + $this->beConstructedWith($host); + $this->handleRequest($request, function () {}, function () {}); + } + + function it_throws_exception_on_trailing_slash(UriInterface $host) + { + $host->getPath()->shouldBeCalled()->willReturn('/api/'); + + $this->beConstructedWith($host); + $this->shouldThrow('\LogicException')->duringInstantiation(); + } + + function it_throws_exception_on_empty_path(UriInterface $host) + { + $host->getPath()->shouldBeCalled()->willReturn(''); + + $this->beConstructedWith($host); + $this->shouldThrow('\LogicException')->duringInstantiation(); + } +} diff --git a/src/Plugin/AddPathPlugin.php b/src/Plugin/AddPathPlugin.php new file mode 100644 index 0000000..18fdf52 --- /dev/null +++ b/src/Plugin/AddPathPlugin.php @@ -0,0 +1,48 @@ + + */ +final class AddPathPlugin implements Plugin +{ + /** + * @var UriInterface + */ + private $uri; + + /** + * @param UriInterface $uri + */ + public function __construct(UriInterface $uri) + { + if ($uri->getPath() === '') { + throw new \LogicException('URI path cannot be empty'); + } + + if (substr($uri->getPath(), -1) === '/') { + throw new \LogicException('URI path cannot end with a slash.'); + } + + $this->uri = $uri; + } + + /** + * {@inheritdoc} + */ + public function handleRequest(RequestInterface $request, callable $next, callable $first) + { + $request = $request->withUri($request->getUri() + ->withPath($this->uri->getPath().$request->getUri()->getPath()) + ); + + return $next($request); + } +} From 2c2e86d5ec4dba742dc91684570cdff5fa75f97b Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Mon, 17 Oct 2016 15:20:16 +0200 Subject: [PATCH 2/2] Add BaseUriPlugin that combines AddHostPlugin and AddPathPlugin --- CHANGELOG.md | 1 + spec/Plugin/BaseUriPluginSpec.php | 102 ++++++++++++++++++++++++++++++ src/Plugin/BaseUriPlugin.php | 54 ++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 spec/Plugin/BaseUriPluginSpec.php create mode 100644 src/Plugin/BaseUriPlugin.php diff --git a/CHANGELOG.md b/CHANGELOG.md index dc57193..f1ff756 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Require Httplug 1.1 where we use HTTP specific promises. - RedirectPlugin: use the full URL instead of the URI to properly keep track of redirects - Add AddPathPlugin for API URLs with base path +- Add BaseUriPlugin that combines AddHostPlugin and AddPathPlugin ## 1.2.1 - 2016-07-26 diff --git a/spec/Plugin/BaseUriPluginSpec.php b/spec/Plugin/BaseUriPluginSpec.php new file mode 100644 index 0000000..2faf769 --- /dev/null +++ b/spec/Plugin/BaseUriPluginSpec.php @@ -0,0 +1,102 @@ +beConstructedWith($uri); + } + + function it_is_initializable(UriInterface $uri) + { + $uri->getHost()->shouldBeCalled()->willReturn('example.com'); + $uri->getPath()->shouldBeCalled()->willReturn('/api'); + + $this->shouldHaveType('Http\Client\Common\Plugin\BaseUriPlugin'); + } + + function it_is_a_plugin(UriInterface $uri) + { + $uri->getHost()->shouldBeCalled()->willReturn('example.com'); + $uri->getPath()->shouldBeCalled()->willReturn('/api'); + + $this->shouldImplement('Http\Client\Common\Plugin'); + } + + function it_adds_domain_and_path( + RequestInterface $request, + UriInterface $host, + UriInterface $uri + ) { + $host->getScheme()->shouldBeCalled()->willReturn('http://'); + $host->getHost()->shouldBeCalled()->willReturn('example.com'); + $host->getPort()->shouldBeCalled()->willReturn(8000); + $host->getPath()->shouldBeCalled()->willReturn('/api'); + + $request->getUri()->shouldBeCalled()->willReturn($uri); + $request->withUri($uri)->shouldBeCalled()->willReturn($request); + + $uri->withScheme('http://')->shouldBeCalled()->willReturn($uri); + $uri->withHost('example.com')->shouldBeCalled()->willReturn($uri); + $uri->withPort(8000)->shouldBeCalled()->willReturn($uri); + $uri->withPath('/api/users')->shouldBeCalled()->willReturn($uri); + $uri->getHost()->shouldBeCalled()->willReturn(''); + $uri->getPath()->shouldBeCalled()->willReturn('/users'); + + $this->beConstructedWith($host); + $this->handleRequest($request, function () {}, function () {}); + } + + function it_adds_domain( + RequestInterface $request, + UriInterface $host, + UriInterface $uri + ) { + $host->getScheme()->shouldBeCalled()->willReturn('http://'); + $host->getHost()->shouldBeCalled()->willReturn('example.com'); + $host->getPort()->shouldBeCalled()->willReturn(8000); + $host->getPath()->shouldBeCalled()->willReturn('/'); + + $request->getUri()->shouldBeCalled()->willReturn($uri); + $request->withUri($uri)->shouldBeCalled()->willReturn($request); + + $uri->withScheme('http://')->shouldBeCalled()->willReturn($uri); + $uri->withHost('example.com')->shouldBeCalled()->willReturn($uri); + $uri->withPort(8000)->shouldBeCalled()->willReturn($uri); + $uri->getHost()->shouldBeCalled()->willReturn(''); + + $this->beConstructedWith($host); + $this->handleRequest($request, function () {}, function () {}); + } + + function it_replaces_domain_and_adds_path( + RequestInterface $request, + UriInterface $host, + UriInterface $uri + ) { + $host->getScheme()->shouldBeCalled()->willReturn('http://'); + $host->getHost()->shouldBeCalled()->willReturn('example.com'); + $host->getPort()->shouldBeCalled()->willReturn(8000); + $host->getPath()->shouldBeCalled()->willReturn('/api'); + + $request->getUri()->shouldBeCalled()->willReturn($uri); + $request->withUri($uri)->shouldBeCalled()->willReturn($request); + + $uri->withScheme('http://')->shouldBeCalled()->willReturn($uri); + $uri->withHost('example.com')->shouldBeCalled()->willReturn($uri); + $uri->withPort(8000)->shouldBeCalled()->willReturn($uri); + $uri->withPath('/api/users')->shouldBeCalled()->willReturn($uri); + $uri->getPath()->shouldBeCalled()->willReturn('/users'); + + $this->beConstructedWith($host, ['replace' => true]); + $this->handleRequest($request, function () {}, function () {}); + } +} diff --git a/src/Plugin/BaseUriPlugin.php b/src/Plugin/BaseUriPlugin.php new file mode 100644 index 0000000..2c2a775 --- /dev/null +++ b/src/Plugin/BaseUriPlugin.php @@ -0,0 +1,54 @@ + + */ +final class BaseUriPlugin implements Plugin +{ + /** + * @var AddHostPlugin + */ + private $addHostPlugin; + + /** + * @var AddPathPlugin|null + */ + private $addPathPlugin = null; + + /** + * @param UriInterface $uri Has to contain a host name and cans have a path. + * @param array $hostConfig Config for AddHostPlugin. @see AddHostPlugin::configureOptions + */ + public function __construct(UriInterface $uri, array $hostConfig = []) + { + $this->addHostPlugin = new AddHostPlugin($uri, $hostConfig); + + if (rtrim($uri->getPath(), '/')) { + $this->addPathPlugin = new AddPathPlugin($uri); + } + } + + /** + * {@inheritdoc} + */ + public function handleRequest(RequestInterface $request, callable $next, callable $first) + { + $addHostNext = function (RequestInterface $request) use ($next, $first) { + return $this->addHostPlugin->handleRequest($request, $next, $first); + }; + + if ($this->addPathPlugin) { + return $this->addPathPlugin->handleRequest($request, $addHostNext, $first); + } + + return $addHostNext($request); + } +}