Skip to content

Commit

Permalink
Adding interface to supports PHP8.4
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Nov 14, 2024
1 parent 0269772 commit 464dee4
Show file tree
Hide file tree
Showing 10 changed files with 431 additions and 162 deletions.
95 changes: 95 additions & 0 deletions src/Hydrator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

/**
* League.Csv (https://csv.thephpleague.com)
*
* (c) Ignace Nyamagana Butera <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace League\Csv;

use Iterator;
use League\Csv\Serializer\DenormalizerFactory;
use League\Csv\Serializer\Factory;
use ReflectionException;

/**
* @template TClass of object
*/
final class Hydrator implements TabularDataHydrator
{
public function __construct(private readonly DenormalizerFactory $factory = new Factory())
{
}

/**
* Denormalizes data back into an object of a given class.
*
* @param class-string<TClass> $className
*
* @throws Serializer\DenormalizationFailed
* @throws ReflectionException
* @throws Serializer\TypeCastingFailed
*
* @return TClass
*/
public function hydrate(string $className, array $record): object
{
/** @var TClass $instance */
$instance = $this->factory
->newDenormalizer($className, array_keys($record))
->denormalize($record);

return $instance;
}

/**
* Denormalizes data back into an object of a given class.
*
* @param class-string<TClass> $className
* @param iterable<array> $records
*
* @throws Serializer\DenormalizationFailed
* @throws ReflectionException
* @throws Serializer\TypeCastingFailed
*
* @return Iterator<TClass>
*/
public function hydrateAll(string $className, iterable $records): Iterator
{
$iterator = MapIterator::toIterator($records);
$iterator->rewind();
if (!$iterator->valid()) {
return;
}

/** @var array $current */
$current = $iterator->current();
$key = $iterator->key();
$iterator->next();

$denormalizer = $this->factory->newDenormalizer($className, array_keys($current));

while ($iterator->valid()) {
/** @var TClass $instance */
$instance = $denormalizer->denormalize($current);

yield $key => $instance;

/** @var array $current */
$current = $iterator->current();
$key = $iterator->key();
$iterator->next();
}

/** @var TClass $instance */
$instance = $denormalizer->denormalize($current);

yield $key => $instance;
}
}
12 changes: 6 additions & 6 deletions src/JsonConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public function __call(string $name, array $arguments): self|bool
/**
* Returns the PHP json flag associated to its method suffix to ease method lookup.
*/
private static function methodToFlag(string $method, int $prefixSize): int
private static function methodToFlag(string $methodName, int $prefixSize): int
{
static $suffix2Flag;

Expand All @@ -252,8 +252,8 @@ private static function methodToFlag(string $method, int $prefixSize): int
}
}

return $suffix2Flag[substr($method, $prefixSize)]
?? throw new BadMethodCallException('The method "'.self::class.'::'.$method.'" does not exist.');
return $suffix2Flag[substr($methodName, $prefixSize)]
?? throw new BadMethodCallException('The method "'.self::class.'::'.$methodName.'" does not exist.');
}

/**
Expand Down Expand Up @@ -365,7 +365,7 @@ public function download(iterable $records, ?string $filename = null): int
HttpHeaders::forFileDownload($filename, 'application/json; charset=utf-8');
}

return $this->save($records, new SplFileObject('php://output', 'w'));
return $this->save($records, new SplFileObject('php://output', 'wb'));
}

/**
Expand Down Expand Up @@ -408,9 +408,9 @@ public function save(iterable $records, mixed $destination, $context = null): in
$stream = match (true) {
$destination instanceof Stream,
$destination instanceof SplFileObject => $destination,
$destination instanceof SplFileInfo => $destination->openFile(mode:'w', context: $context),
$destination instanceof SplFileInfo => $destination->openFile(mode:'wb', context: $context),
is_resource($destination) => Stream::createFromResource($destination),
is_string($destination) => Stream::createFromPath($destination, 'w', $context),
is_string($destination) => Stream::createFromPath($destination, 'wb', $context),
default => throw new TypeError('The destination path must be a filename, a stream or a SplFileInfo object.'),
};
$bytes = 0;
Expand Down
13 changes: 4 additions & 9 deletions src/Reader.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use Closure;
use Iterator;
use JsonSerializable;
use League\Csv\Serializer\Denormalizer;
use League\Csv\Serializer\MappingFailed;
use League\Csv\Serializer\TypeCastingFailed;
use SplFileObject;
Expand Down Expand Up @@ -484,18 +483,14 @@ public function getRecords(array $header = []): Iterator
* @throws MappingFailed
* @throws TypeCastingFailed
*
* @return iterator<T>
* @return Iterator<T>
*/
public function getRecordsAsObject(string $className, array $header = []): Iterator
{
/** @var array<string> $header */
$header = $this->prepareHeader($header);
/** @var Iterator<T> $records */
$records = (new Hydrator())->hydrateAll($className, $this->getRecords($header));

return Denormalizer::assignAll(
$className,
$this->combineHeader($this->prepareRecords(), $header),
$header
);
return $records;
}

/**
Expand Down
25 changes: 13 additions & 12 deletions src/ResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
use Generator;
use Iterator;
use JsonSerializable;
use League\Csv\Serializer\Denormalizer;
use League\Csv\Serializer\MappingFailed;
use League\Csv\Serializer\TypeCastingFailed;
use LimitIterator;
use ReflectionException;

use function array_filter;
use function array_flip;
Expand Down Expand Up @@ -316,24 +316,24 @@ public function getRecords(array $header = []): Iterator
}

/**
* @template T of object
* @param class-string<T> $className
* @template TClass of object
*
* @param class-string<TClass> $className
* @param array<string> $header
*
* @throws Exception
* @throws MappingFailed
* @throws ReflectionException
* @throws TypeCastingFailed
* @return iterator<T>
*
* @return Iterator<array-key, TClass>
*/
public function getRecordsAsObject(string $className, array $header = []): Iterator
{
$header = $this->prepareHeader($header);
/** @var Iterator<array-key, TClass> $data */
$data = (new Hydrator())->hydrateAll($className, $this->getRecords($header));

return Denormalizer::assignAll(
$className,
$this->combineHeader($header),
$header
);
return $data;
}

/**
Expand Down Expand Up @@ -424,8 +424,9 @@ public function nthAsObject(int $nth, string $className, array $header = []): ?o
return null;
}

$mapper = new Hydrator();
if ([] === $header || $this->header === $header) {
return Denormalizer::assign($className, $record);
return $mapper->hydrate($className, $record);
}

$row = array_values($record);
Expand All @@ -434,7 +435,7 @@ public function nthAsObject(int $nth, string $className, array $header = []): ?o
$record[$headerName] = $row[$offset] ?? null;
}

return Denormalizer::assign($className, $record);
return $mapper->hydrate($className, $record);
}

/**
Expand Down
Loading

0 comments on commit 464dee4

Please sign in to comment.