From 5d33eed7030f3ffbccbd7828af5f0165155059a0 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 14:53:30 +0200 Subject: [PATCH 1/9] Add support for PSR17 factories --- .travis.yml | 3 ++ composer.json | 3 +- src/MultipartStreamBuilder.php | 69 ++++++++++++++++++++++++++++++---- tests/FunctionTest.php | 46 +++++++++++++++++++++-- 4 files changed, 109 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f32e86..2ca6fa0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,9 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 + - 7.3 + - 7.4 - hhvm env: diff --git a/composer.json b/composer.json index bc193ef..25114ea 100644 --- a/composer.json +++ b/composer.json @@ -13,13 +13,14 @@ "require": { "php": "^5.5 || ^7.0", "psr/http-message": "^1.0", + "psr/http-factory": "^1.0", "php-http/message-factory": "^1.0.2", "php-http/discovery": "^1.0" }, "require-dev": { "phpunit/phpunit": "^4.8 || ^5.4", "php-http/message": "^1.5", - "zendframework/zend-diactoros": "^1.3.5" + "nyholm/psr7": "^1.0" }, "autoload": { "psr-4": { diff --git a/src/MultipartStreamBuilder.php b/src/MultipartStreamBuilder.php index 8622c00..19e53cd 100644 --- a/src/MultipartStreamBuilder.php +++ b/src/MultipartStreamBuilder.php @@ -2,8 +2,11 @@ namespace Http\Message\MultipartStream; +use Http\Discovery\Exception\NotFoundException; +use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\StreamFactoryDiscovery; -use Http\Message\StreamFactory; +use Http\Message\StreamFactory as HttplugStreamFactory; +use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\StreamInterface; /** @@ -16,7 +19,7 @@ class MultipartStreamBuilder { /** - * @var StreamFactory + * @var StreamFactory|StreamFactoryInterface */ private $streamFactory; @@ -36,11 +39,37 @@ class MultipartStreamBuilder private $data = []; /** - * @param StreamFactory|null $streamFactory + * @param StreamFactory|StreamFactoryInterface|null $streamFactory */ - public function __construct(StreamFactory $streamFactory = null) + public function __construct($streamFactory = null) { - $this->streamFactory = $streamFactory ?: StreamFactoryDiscovery::find(); + if ($streamFactory instanceof StreamFactoryInterface || $streamFactory instanceof HttplugStreamFactory) { + $this->streamFactory = $streamFactory; + + return; + } + + if (null !== $streamFactory) { + throw new \LogicException(sprintf( + 'First arguemnt to the constructor of "%s" must be of type "%s", "%s" or null. Got %s', + __CLASS__, + StreamFactoryInterface::class, + HttplugStreamFactory::class, + \is_object($streamFactory) ? \get_class($streamFactory) : \gettype($streamFactory) + )); + } + + // Try to find a stream factory. + try { + $this->streamFactory = Psr17FactoryDiscovery::findStreamFactory(); + } catch (NotFoundException $psr17Exception) { + try { + $this->streamFactory = StreamFactoryDiscovery::find(); + } catch (NotFoundException $httplugException) { + // we could not find any factory. + throw $psr17Exception; + } + } } /** @@ -58,7 +87,7 @@ public function __construct(StreamFactory $streamFactory = null) */ public function addResource($name, $resource, array $options = []) { - $stream = $this->streamFactory->createStream($resource); + $stream = $this->createStream($resource); // validate options['headers'] exists if (!isset($options['headers'])) { @@ -108,7 +137,7 @@ public function build() // Append end $streams .= "--{$this->getBoundary()}--\r\n"; - return $this->streamFactory->createStream($streams); + return $this->createStream($streams); } /** @@ -275,4 +304,30 @@ private function basename($path) return $filename; } + + /** + * @param string|resource|StreamInterface $resource + * @return StreamInterface + */ + private function createStream($resource) + { + if ($resource instanceof StreamInterface) { + return $resource; + } + + if ($this->streamFactory instanceof HttplugStreamFactory) { + return $this->streamFactory->createStream($resource); + } + + // Assert: We are using a PSR17 stream factory. + if (\is_string($resource)) { + return $this->streamFactory->createStream($resource); + } + + if (\is_resource($resource)) { + return $this->streamFactory->createStreamFromResource($resource); + } + + throw new \InvalidArgumentException(sprintf('First argument to "%s::createStream()" must be a string, resource or StreamInterface.', __CLASS__)); + } } diff --git a/tests/FunctionTest.php b/tests/FunctionTest.php index 10d16d4..a0b5da7 100644 --- a/tests/FunctionTest.php +++ b/tests/FunctionTest.php @@ -2,8 +2,12 @@ namespace tests\Http\Message\MultipartStream; +use Http\Message\MultipartStream\CustomMimetypeHelper; use Http\Message\MultipartStream\MultipartStreamBuilder; -use Zend\Diactoros\Stream; +use Nyholm\Psr7\Factory\HttplugFactory; +use Nyholm\Psr7\Factory\Psr17Factory; +use Nyholm\Psr7\Stream; +use Psr\Http\Message\StreamInterface; /** * @author Tobias Nyholm @@ -144,15 +148,49 @@ public function testReset() $this->assertNotEmpty($builder->getBoundary()); } + public function testThrowsExceptionIfNotStreamCompatible() + { + $builder = new MultipartStreamBuilder(); + $this->expectException(\LogicException::class); + $builder->addResource('foo', []); + } + + public function testThrowsExceptionInConstructor() + { + $this->expectException(\LogicException::class); + new MultipartStreamBuilder(new CustomMimetypeHelper()); + } + + /** + * @dataProvider getStreamFactories + */ + public function testSupportDifferentFactories($factory) + { + $resource = fopen(__DIR__.'/Resources/httplug.png', 'r'); + + $builder = new MultipartStreamBuilder($factory); + $builder->addResource('image', $resource); + + $multipartStream = (string) $builder->build(); + $this->assertTrue(false !== strpos($multipartStream, 'Content-Disposition: form-data; name="image"; filename="httplug.png"')); + $this->assertTrue(false !== strpos($multipartStream, 'Content-Type: image/png')); + } + + public function getStreamFactories() + { + yield 'Httplug Stream Factory' => [new HttplugFactory()]; + yield 'PSR-17 Stream Factory' => [new Psr17Factory()]; + yield 'Null Stream Factory' => [null]; + } + /** * @param string $body * - * @return Stream + * @return StreamInterface */ private function createStream($body) { - $stream = new Stream('php://memory', 'rw'); - $stream->write($body); + $stream = Stream::create($body); $stream->rewind(); return $stream; From 5ce837a344429ddebb31a1e0dab7554d75ebf4de Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 14:54:33 +0200 Subject: [PATCH 2/9] Added changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f0ee3d..ab36364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## UNRELEASED + +Added support for PSR-17 factories. + ## 1.0.0 - 2017-05-21 No changes from 0.2.0. From 22d74e5d42cdd07a60ca57971226fe604634f5f3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 14:56:02 +0200 Subject: [PATCH 3/9] cs --- src/MultipartStreamBuilder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MultipartStreamBuilder.php b/src/MultipartStreamBuilder.php index 19e53cd..4652210 100644 --- a/src/MultipartStreamBuilder.php +++ b/src/MultipartStreamBuilder.php @@ -48,7 +48,7 @@ public function __construct($streamFactory = null) return; } - + if (null !== $streamFactory) { throw new \LogicException(sprintf( 'First arguemnt to the constructor of "%s" must be of type "%s", "%s" or null. Got %s', @@ -307,6 +307,7 @@ private function basename($path) /** * @param string|resource|StreamInterface $resource + * * @return StreamInterface */ private function createStream($resource) From 7b4a47aa906e7f2e4224f3ce7ea9314e91803d1d Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 14:57:55 +0200 Subject: [PATCH 4/9] Fixes --- tests/FunctionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FunctionTest.php b/tests/FunctionTest.php index a0b5da7..18017d7 100644 --- a/tests/FunctionTest.php +++ b/tests/FunctionTest.php @@ -151,7 +151,7 @@ public function testReset() public function testThrowsExceptionIfNotStreamCompatible() { $builder = new MultipartStreamBuilder(); - $this->expectException(\LogicException::class); + $this->expectException(\InvalidArgumentException::class); $builder->addResource('foo', []); } From e78a95adc0545e8a92a06e16270b1eec6f963645 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 15:05:59 +0200 Subject: [PATCH 5/9] Drop older PHP versions that does not support psr/http-factory --- .travis.yml | 13 ++----------- CHANGELOG.md | 3 ++- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ca6fa0..999097e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: php - sudo: false cache: @@ -7,14 +6,8 @@ cache: - $HOME/.composer/cache/files php: - - 5.5 - - 5.6 - - 7.0 - - 7.1 - 7.2 - 7.3 - - 7.4 - - hhvm env: global: @@ -27,14 +20,12 @@ branches: matrix: fast_finish: true include: - - php: 5.5 + - php: 7.3 env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" COVERAGE=true TEST_COMMAND="composer test-ci" -before_install: - - travis_retry composer self-update install: - - travis_retry composer update ${COMPOSER_FLAGS} --prefer-source --no-interaction + - composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction script: - $TEST_COMMAND diff --git a/CHANGELOG.md b/CHANGELOG.md index ab36364..146f73a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## UNRELEASED -Added support for PSR-17 factories. +- Added support for PSR-17 factories. +- Dropped support for PHP < 7.2 ## 1.0.0 - 2017-05-21 From ae55285c40225c6752c146c548f8e660f5805e37 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 15:11:12 +0200 Subject: [PATCH 6/9] Updated phpunit --- .gitignore | 3 +-- composer.json | 2 +- phpunit.xml.dist | 2 +- tests/CustomMimetypeHelperTest.php | 3 ++- tests/FunctionTest.php | 7 ++++--- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index da734f1..0013978 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ .puli/ -build/ vendor/ composer.lock -phpspec.yml phpunit.xml +.phpunit.result.cache diff --git a/composer.json b/composer.json index 25114ea..3cc472b 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "php-http/discovery": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.4", + "phpunit/phpunit": "^8.2", "php-http/message": "^1.5", "nyholm/psr7": "^1.0" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1277304..8c0f5b8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,7 +5,7 @@ convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" - syntaxCheck="true"> +> ./tests diff --git a/tests/CustomMimetypeHelperTest.php b/tests/CustomMimetypeHelperTest.php index d8d1f10..185c35c 100644 --- a/tests/CustomMimetypeHelperTest.php +++ b/tests/CustomMimetypeHelperTest.php @@ -3,8 +3,9 @@ namespace tests\Http\Message\MultipartStream; use Http\Message\MultipartStream\CustomMimetypeHelper; +use PHPUnit\Framework\TestCase; -class CustomMimetypeHelperTest extends \PHPUnit_Framework_TestCase +class CustomMimetypeHelperTest extends TestCase { public function testGetMimetypeFromExtension() { diff --git a/tests/FunctionTest.php b/tests/FunctionTest.php index 18017d7..3d9c6ea 100644 --- a/tests/FunctionTest.php +++ b/tests/FunctionTest.php @@ -7,12 +7,13 @@ use Nyholm\Psr7\Factory\HttplugFactory; use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7\Stream; +use PHPUnit\Framework\TestCase; use Psr\Http\Message\StreamInterface; /** * @author Tobias Nyholm */ -class FunctionTest extends \PHPUnit_Framework_TestCase +class FunctionTest extends TestCase { public function testSupportStreams() { @@ -50,7 +51,7 @@ public function testSupportURIResources() $this->assertTrue(false !== strpos($multipartStream, 'Content-Type: image/png')); $urlContents = file_get_contents($url); - $this->assertContains($urlContents, $multipartStream); + $this->assertStringContainsString($urlContents, $multipartStream); } public function testResourceFilenameIsNotLocaleAware() @@ -143,7 +144,7 @@ public function testReset() $builder->reset(); $multipartStream = (string) $builder->build(); - $this->assertNotContains('foobar', $multipartStream, 'Stream should not have any data after reset()'); + $this->assertStringNotContainsString('foobar', $multipartStream, 'Stream should not have any data after reset()'); $this->assertNotEquals($boundary, $builder->getBoundary(), 'Stream should have a new boundary after reset()'); $this->assertNotEmpty($builder->getBoundary()); } From cadf4467091f3a0b22ac03446452c9251a246907 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 15:14:23 +0200 Subject: [PATCH 7/9] updated composer deps --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3cc472b..e4bb0ff 100644 --- a/composer.json +++ b/composer.json @@ -11,11 +11,11 @@ } ], "require": { - "php": "^5.5 || ^7.0", + "php": "^7.2", "psr/http-message": "^1.0", "psr/http-factory": "^1.0", "php-http/message-factory": "^1.0.2", - "php-http/discovery": "^1.0" + "php-http/discovery": "^1.7" }, "require-dev": { "phpunit/phpunit": "^8.2", From c27bb8124c46fb40d8aa95999a1e0297cea2ecc3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 15:30:25 +0200 Subject: [PATCH 8/9] Support PHP 7.1 --- .travis.yml | 1 + composer.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 999097e..cd3dbe9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ cache: - $HOME/.composer/cache/files php: + - 7.1 - 7.2 - 7.3 diff --git a/composer.json b/composer.json index e4bb0ff..4b28ddf 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.1", "psr/http-message": "^1.0", "psr/http-factory": "^1.0", "php-http/message-factory": "^1.0.2", From 2a66b56ec68755299bd99813c0bc01f9b1612f40 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Aug 2019 15:41:25 +0200 Subject: [PATCH 9/9] Allow PHPunit 7.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4b28ddf..329e906 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "php-http/discovery": "^1.7" }, "require-dev": { - "phpunit/phpunit": "^8.2", + "phpunit/phpunit": "^7.5 || ^8.3", "php-http/message": "^1.5", "nyholm/psr7": "^1.0" },