Skip to content

Commit

Permalink
[10.x] Throw exception when trying to initiate Collection using `We…
Browse files Browse the repository at this point in the history
…akMap`

fixes #49089

Signed-off-by: Mior Muhammad Zaki <[email protected]>
  • Loading branch information
crynobone committed Nov 23, 2023
1 parent 2967d89 commit 1ef2123
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/Illuminate/Collections/Traits/EnumeratesValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Enumerable;
use Illuminate\Support\HigherOrderCollectionProxy;
use InvalidArgumentException;
use JsonSerializable;
use Symfony\Component\VarDumper\VarDumper;
use Traversable;
use UnexpectedValueException;
use UnitEnum;
use WeakMap;

/**
* @template TKey of array-key
Expand Down Expand Up @@ -1019,6 +1021,7 @@ protected function getArrayableItems($items)
}

return match (true) {
$items instanceof WeakMap => throw new InvalidArgumentException('Unable to resolve array from instance of WeakMap.'),
$items instanceof Enumerable => $items->all(),
$items instanceof Arrayable => $items->toArray(),
$items instanceof Traversable => iterator_to_array($items),
Expand Down
46 changes: 40 additions & 6 deletions tests/Integration/Events/ShouldDispatchAfterCommitEventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,32 @@
namespace Illuminate\Tests\Integration\Events;

use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Mockery as m;
use Orchestra\Testbench\Attributes\WithMigration;
use Orchestra\Testbench\TestCase;

#[WithMigration('queue')]
class ShouldDispatchAfterCommitEventTest extends TestCase
{
protected function tearDown(): void
use DatabaseMigrations;

protected function setUp(): void
{
TransactionUnawareTestEvent::$ran = false;
ShouldDispatchAfterCommitTestEvent::$ran = false;
AnotherShouldDispatchAfterCommitTestEvent::$ran = false;

m::close();
parent::setUp();
}

protected function defineEnvironment($app)
{
$app['config']->set([
'database.default' => 'testing',
'queue.default' => 'database',
]);
}

public function testEventIsDispatchedIfThereIsNoTransaction()
Expand Down Expand Up @@ -112,6 +124,11 @@ public function testItOnlyDispatchesNestedTransactionsEventsAfterTheRootTransact
Event::listen(AnotherShouldDispatchAfterCommitTestEvent::class, AnotherShouldDispatchAfterCommitListener::class);

DB::transaction(function () {
DB::afterCommit(function () {
// The main difference with this test is that we dispatch an event on the parent transaction
// at the end. This is important due to how the DatabaseTransactionsManager works.
Event::dispatch(new AnotherShouldDispatchAfterCommitTestEvent);
});
DB::transaction(function () {
Event::dispatch(new ShouldDispatchAfterCommitTestEvent);
});
Expand All @@ -120,16 +137,33 @@ public function testItOnlyDispatchesNestedTransactionsEventsAfterTheRootTransact
// The event dispatched on the child transaction should not have been dispatched.
$this->assertFalse(ShouldDispatchAfterCommitTestEvent::$ran);

// The main difference with this test is that we dispatch an event on the parent transaction
// at the end. This is important due to how the DatabaseTransactionsManager works.
Event::dispatch(new AnotherShouldDispatchAfterCommitTestEvent);

$this->assertFalse(ShouldDispatchAfterCommitTestEvent::$ran);
$this->assertFalse(AnotherShouldDispatchAfterCommitTestEvent::$ran);
});

// Now that the parent transaction has been committed, the event
// on the child transaction should also have been dispatched.
$this->assertTrue(ShouldDispatchAfterCommitTestEvent::$ran);
$this->assertTrue(AnotherShouldDispatchAfterCommitTestEvent::$ran);
}

public function testItOnlyDispatchesEventsAfterTheRootTransactionIsCommitted()
{
Event::listen(ShouldDispatchAfterCommitTestEvent::class, ShouldDispatchAfterCommitListener::class);

DB::transaction(function () {
DB::transaction(function () {});

DB::afterCommit(
fn () => Event::dispatch(new ShouldDispatchAfterCommitTestEvent)
);

$this->assertFalse(ShouldDispatchAfterCommitTestEvent::$ran);
});

$this->assertTrue(ShouldDispatchAfterCommitTestEvent::$ran);
}
}

class TransactionUnawareTestEvent
Expand Down
18 changes: 17 additions & 1 deletion tests/Support/SupportCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
use IteratorAggregate;
use JsonSerializable;
use Mockery as m;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use stdClass;
use Symfony\Component\VarDumper\VarDumper;
use Traversable;
use UnexpectedValueException;
use stdClass;
use WeakMap;

include_once 'Enums.php';

Expand Down Expand Up @@ -2957,6 +2959,20 @@ public function testConstructMethodFromObject($collection)
$this->assertEquals(['foo' => 'bar'], $data->all());
}

#[DataProvider('collectionClassProvider')]
public function testConstructMethodFromWeakMap($collection)
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Unable to resolve array from instance of WeakMap.');

$map = new WeakMap();
$object = new stdClass;
$object->foo = 'bar';
$map[$object] = 3;

$data = new $collection($map);
}

public function testSplice()
{
$data = new Collection(['foo', 'baz']);
Expand Down

0 comments on commit 1ef2123

Please sign in to comment.