Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/changelogs/v4.7.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Release Date: Unreleased

## Bugs Fixed

- **Entity:** Fixed a bug where `Entity::toRawArray()` returned a `Time` instance for a date attribute that had been assigned a string value, while the same attribute was returned as a string when the entity was populated from the database. `toRawArray()` now returns the string representation of date attributes in both cases.
- **Security:** Fixed a bug where `Security::__construct()` threw a `TypeError` when the CSRF cookie was an array, causing an HTTP 500 response for affected requests.
- **Worker Mode:** Fixed a bug where every request that ended with an uncaught exception, including a `404 Page Not Found` without a 404 override, called `exit()` in the exception handler. This ended the worker script, so FrankenPHP booted a new one, and the worker loop skipped its cleanup after the request. The exception handler now returns to the worker loop.

Expand Down
20 changes: 17 additions & 3 deletions system/Entity/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,20 @@ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recu
*/
public function toRawArray(bool $onlyChanged = false, bool $recursive = false): array
{
// Date attributes that were assigned at runtime are mutated to
// Time instances when they are set (see __set()), while the same
// attributes hold plain strings when the entity is populated
// from the database (see injectRawData()). The raw value of a
// date attribute is its string representation, so normalize any
// Time instances back to strings to keep the output consistent.
$attributes = $this->attributes;

foreach ($attributes as $key => $value) {
if ($value instanceof Time && in_array($key, $this->dates, true)) {
$attributes[$key] = (string) $value;
}
}

$convert = static function ($value) use (&$convert, $recursive) {
if (! $recursive) {
return $value;
Expand Down Expand Up @@ -260,14 +274,14 @@ public function toRawArray(bool $onlyChanged = false, bool $recursive = false):
// When returning everything
if (! $onlyChanged) {
return $recursive
? array_map($convert, $this->attributes)
: $this->attributes;
? array_map($convert, $attributes)
: $attributes;
}

// When filtering by changed values only
$return = [];

foreach ($this->attributes as $key => $value) {
foreach ($attributes as $key => $value) {
// Special handling for arrays of entities in recursive mode
// Skip hasChanged() and do per-entity comparison directly
if ($recursive && is_array($value) && $this->containsOnlyEntities($value)) {
Expand Down
23 changes: 23 additions & 0 deletions tests/system/Entity/EntityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,29 @@ public function testSetArrayToPropertyNamedAttributes(): void
$this->assertSame($expected, $entity->toRawArray());
}

public function testToRawArrayReturnsStringForAssignedDateAttribute(): void
{
$entity = new class () extends Entity {
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
};

// Simulate an entity fetched from the database.
$entity->injectRawData([
'created_at' => '2023-12-07 04:00:48',
'updated_at' => '2023-12-07 04:00:48',
'deleted_at' => null,
]);

$entity->updated_at = '2023-12-12 12:12:12';

// The raw value must stay the assigned string, not a Time instance.
$this->assertSame('2023-12-12 12:12:12', $entity->toRawArray()['updated_at']);

// Retrieval still mutates the value into a Time instance.
$this->assertInstanceOf(Time::class, $entity->updated_at);
$this->assertSame('2023-12-12 12:12:12', $entity->updated_at->format('Y-m-d H:i:s'));
}

public function testSetGetAttributesMethod(): void
{
$entity = new class () extends Entity {
Expand Down