Skip to content

Commit

Permalink
Initial work on making export of objects customizable
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianbergmann committed Mar 29, 2024
1 parent 92f21fd commit 794322c
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/ObjectExporter.php
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/exporter.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;

interface ObjectExporter
{
public function handles(object $object): bool;

public function export(object $object): string;
}
51 changes: 51 additions & 0 deletions src/ObjectExporterChain.php
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/exporter.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;

final class ObjectExporterChain implements ObjectExporter
{
/**
* @psalm-var non-empty-list<ObjectExporter>
*/
private array $exporter;

/**
* @psalm-param non-empty-list<ObjectExporter> $exporter
*/
public function __construct(array $exporter)
{
$this->exporter = $exporter;
}

public function handles(object $object): bool
{
foreach ($this->exporter as $exporter) {
if ($exporter->handles($object)) {
return true;
}
}

return false;
}

/**
* @throws ObjectNotSupportedException
*/
public function export(object $object): string
{
foreach ($this->exporter as $exporter) {
if ($exporter->handles($object)) {
return $exporter->export($object);
}
}

throw new ObjectNotSupportedException;
}
}
16 changes: 16 additions & 0 deletions src/exception/Exception.php
@@ -0,0 +1,16 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/exporter.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;

use Throwable;

interface Exception extends Throwable
{
}
16 changes: 16 additions & 0 deletions src/exception/ObjectNotSupportedException.php
@@ -0,0 +1,16 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/exporter.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;

use RuntimeException;

final class ObjectNotSupportedException extends RuntimeException implements Exception
{
}
62 changes: 62 additions & 0 deletions tests/ObjectExporterChainTest.php
@@ -0,0 +1,62 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/exporter.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\TestCase;
use stdClass;

#[CoversClass(ObjectExporterChain::class)]
#[Small]
final class ObjectExporterChainTest extends TestCase
{
public function testCanBeQueriedWhetherChainedExporterHandlesAnObject(): void
{
$firstExporter = $this->createStub(ObjectExporter::class);
$firstExporter->method('handles')->willReturn(false);

$secondExporter = $this->createStub(ObjectExporter::class);
$secondExporter->method('handles')->willReturn(true);

$chain = new ObjectExporterChain([$firstExporter]);
$this->assertFalse($chain->handles(new stdClass));

$chain = new ObjectExporterChain([$firstExporter, $secondExporter]);
$this->assertTrue($chain->handles(new stdClass));
}

public function testDelegatesExportingToFirstExporterThatHandlesAnObject(): void
{
$firstExporter = $this->createStub(ObjectExporter::class);
$firstExporter->method('handles')->willReturn(false);
$firstExporter->method('export')->willThrowException(new ObjectNotSupportedException);

$secondExporter = $this->createStub(ObjectExporter::class);
$secondExporter->method('handles')->willReturn(true);
$secondExporter->method('export')->willReturn('string');

$chain = new ObjectExporterChain([$firstExporter, $secondExporter]);

$this->assertSame('string', $chain->export(new stdClass));
}

public function testCannotExportObjectWhenNoExporterHandlesIt(): void
{
$firstExporter = $this->createStub(ObjectExporter::class);
$firstExporter->method('handles')->willReturn(false);

$chain = new ObjectExporterChain([$firstExporter]);

$this->expectException(ObjectNotSupportedException::class);

$this->assertSame('string', $chain->export(new stdClass));
}
}

0 comments on commit 794322c

Please sign in to comment.