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
2 changes: 2 additions & 0 deletions src/event/illuminate/CallQueuedListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Illuminate\Events;

use AllowDynamicProperties;
use DateInterval;
use DateTimeInterface;
use Hyperf\Context\ApplicationContext;
Expand All @@ -13,6 +14,7 @@
use Hypervel\Queue\InteractsWithQueue;
use Throwable;

#[AllowDynamicProperties]
class CallQueuedListener implements ShouldQueue
{
use InteractsWithQueue;
Expand Down
2 changes: 2 additions & 0 deletions src/event/src/CallQueuedListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Hypervel\Event;

use AllowDynamicProperties;
use DateInterval;
use DateTimeInterface;
use Hyperf\Context\ApplicationContext;
Expand All @@ -13,6 +14,7 @@
use Hypervel\Queue\InteractsWithQueue;
use Throwable;

#[AllowDynamicProperties]
class CallQueuedListener implements ShouldQueue
{
use InteractsWithQueue;
Expand Down
19 changes: 18 additions & 1 deletion src/queue/src/CallQueuedClosure.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class CallQueuedClosure implements ShouldQueue
*/
public array $failureCallbacks = [];

/**
* The name assigned to the job.
*/
public ?string $name = null;

/**
* Indicate if the job should be deleted when models are missing.
*/
Expand Down Expand Up @@ -91,6 +96,18 @@ public function displayName(): string
{
$reflection = new ReflectionFunction($this->closure->getClosure());

return 'Closure (' . basename($reflection->getFileName()) . ':' . $reflection->getStartLine() . ')';
$prefix = is_null($this->name) ? '' : "{$this->name} - ";

return $prefix . 'Closure (' . basename($reflection->getFileName()) . ':' . $reflection->getStartLine() . ')';
}

/**
* Assign a name to the job.
*/
public function name(string $name): static
{
$this->name = $name;

return $this;
}
}
58 changes: 58 additions & 0 deletions tests/Event/CallQueuedListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Hypervel\Tests\Event;

use Hypervel\Event\CallQueuedListener as HypervelCallQueuedListener;
use Hypervel\Tests\TestCase;
use Illuminate\Events\CallQueuedListener as IlluminateCallQueuedListener;

/**
* @internal
* @coversNothing
*/
class CallQueuedListenerTest extends TestCase
{
public function testHypervelListenerToleratesUnknownPropertiesOnUnserialization()
{
$this->assertListenerToleratesUnknownProperties(
HypervelCallQueuedListener::class
);
}

public function testIlluminateListenerToleratesUnknownPropertiesOnUnserialization()
{
$this->assertListenerToleratesUnknownProperties(
IlluminateCallQueuedListener::class
);
}

/**
* Simulates cross-version deserialization: a job payload serialized by a
* newer Laravel/Hypervel version (which adds extra properties to
* CallQueuedListener) is unserialized by an older version that does not
* declare those properties. Without #[AllowDynamicProperties], PHP 8.2+
* raises an error on the dynamic property assignment during unserialize().
*/
private function assertListenerToleratesUnknownProperties(string $class): void
{
$listener = new $class('App\Listeners\OrderShipped', 'handle', []);
$serialized = serialize($listener);

// Inject a synthetic property absent from the current class definition.
$extra = 's:18:"newPropertyFromV11";s:5:"value";';
$serialized = preg_replace_callback(
'/^(O:\d+:"[^"]+":)(\d+):/',
fn ($m) => $m[1] . ((int) $m[2] + 1) . ':',
$serialized
);
$serialized = substr($serialized, 0, -1) . $extra . '}';

$result = unserialize($serialized);

$this->assertInstanceOf($class, $result);
$this->assertSame('App\Listeners\OrderShipped', $result->class);
$this->assertSame('value', $result->newPropertyFromV11);
}
}
Loading