Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,22 @@ $doubles = $collection->map(function ($value) {
});
```

### Map Into
The `mapInto()` method allows you to take any collection and in one call create
a new collection of a given type, run a callable across the data, and have it
immediately collected into the new collection.

Here's an example where we have created new collections that are restricted to
allowing only integers to be collected in the first, and strings in the second:
```php
$ints = new IntegerCollection([1, 2, 3, 4, 5]);
$strings = $ints->mapInto(function (int $item): string {
return (string)($item*10);
}, StringCollection::class);
```
We now have a `StringCollection` which contains a string representation of
every value from the original `$ints` collection, multiplied by 10.

### Each
Sometimes we need to iterate over values, but we don't want to make any
changes. That is where `each()` is different to `map()`. Otherwise, the
Expand Down
40 changes: 32 additions & 8 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,45 @@ private function checkType($value, ?string $type)
/**
* Copy entries into a new collection
*
* @param string $collection The collection type to copy into
* @param string $type The collection type to copy into
* @return self
* @throws TypeError
*/
public function into(string $collection): Collection
public function into(string $type): Collection
{
if (!class_exists($collection)) {
throw new TypeError(sprintf('Unknown class name "%s"', $collection));
return self::newCollectionOfType($type, $this->getArrayCopy());
}

/**
* Map collection into a new collection of a given type
*
* @param callable $callable
* @param string $type
* @return Collection
*/
public function mapInto(callable $callable, string $type): self
{
return self::newCollectionOfType($type, array_map($callable, $this->getArrayCopy()));
}

/**
* Get a new collection of a given type
*
* @param string $type The collection type that you want an instance of
* @param array $items The items that you want to collect immediately (defaults to nothing)
* @return self
*/
public static function newCollectionOfType(string $type, $items = []): Collection
{
if (!class_exists($type)) {
throw new TypeError(sprintf('Unknown class name "%s"', $type));
}
if (!is_subclass_of($collection, Collection::class) &&
Collection::class !== $collection
if (!is_subclass_of($type, Collection::class) &&
Collection::class !== $type
) {
throw new TypeError(sprintf('Class "%s" is not a Collection type', $collection));
throw new TypeError(sprintf('Class "%s" is not a Collection type', $type));
}
return new $collection($this->getArrayCopy());
return new $type($items);
}

/**
Expand Down
40 changes: 40 additions & 0 deletions tests/CollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,46 @@ public function failToCollectIntoANonExitingType()
$collection->into('my arbitrary type');
}

/**
* @test
*/
public function mapInto()
{
$stringCollection = new class extends Collection
{
protected $valueType = 'string';
};

$intCollection = new class([1,2,3,4,5]) extends Collection
{
protected $valueType = 'integer';
};

$finalCollection = $intCollection->mapInto(function (int $int): string {
return (string) ($int * 10);
}, get_class($stringCollection));

$finalCollection->each(function ($value, $key) use ($intCollection) {
$this->assertSame((string) ($intCollection[$key] * 10), $value);
});
}

/**
* @test
* @expectedException \TypeError
*/
public function mapIntoThrows()
{
$intCollection = new class([1,2,3,4,5]) extends Collection
{
protected $valueType = 'integer';
};

$intCollection->mapInto(function (int $int): string {
return (string) ($int * 10);
}, get_class($intCollection));
}

/**
* @dataProvider collectibles
* @param $data
Expand Down