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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Bug #558: Fix `SoftDelete` with initiated custom date (@Tigrov)
- Enh #564: Clarify `$relations` parameter type in `JoinWith::__construct()` from `array<string|Closure>` to
`array<string|callable(ActiveQueryInterface):void>` (@vjik)
- Bug #567: Fix properties with hooks (@Tigrov)
Comment thread
Tigrov marked this conversation as resolved.
- Bug #562: Fix `ActiveRecordInterface::upsert()` to prioritize passed associative values during updates (@Tigrov)
- Bug #561: Fix `ActiveRecordInterface::upsert()` with `$updateProperties = false` (@Tigrov)
- Bug #550: Relation query should be created by related class, not primary model class (@batyrmastyr)
Expand Down
3 changes: 1 addition & 2 deletions src/ActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use function array_filter;
use function array_keys;
use function array_merge;
use function get_object_vars;
use function is_array;

use const ARRAY_FILTER_USE_KEY;
Expand Down Expand Up @@ -128,7 +127,7 @@ public function primaryKey(): array

protected function propertyValuesInternal(): array
{
return get_object_vars($this);
return ArArrayHelper::propertyValues($this);
}

protected function insertInternal(?array $properties = null): void
Expand Down
35 changes: 35 additions & 0 deletions src/Internal/ArArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,39 @@ public static function toArray(array|object $object): array

return get_object_vars($object);
}

/**
* Returns the available property values of an Active Record object.
*
* @param ActiveRecordInterface $model The ActiveRecord model instance.
*
* @psalm-return array<string, mixed>
Comment thread
Tigrov marked this conversation as resolved.
*
* @see https://www.php.net/manual/en/language.types.array.php#language.types.array.casting
*/
public static function propertyValues(ActiveRecordInterface $model): array
{
/** @psalm-var array<string, mixed> $data */
$data = (array) $model;
unset(
$data["\0Yiisoft\ActiveRecord\AbstractActiveRecord\0oldValues"],
$data["\0Yiisoft\ActiveRecord\AbstractActiveRecord\0related"],
$data["\0Yiisoft\ActiveRecord\AbstractActiveRecord\0relationsDependencies"],
);

$keys = array_map(self::clearPropertyName(...), array_keys($data));

return array_combine($keys, $data);
}

private static function clearPropertyName(string $propertyName): string
{
$pos = strrpos($propertyName, "\0");

if ($pos === false) {
return $propertyName;
}

return substr($propertyName, $pos + 1);
}
}
8 changes: 0 additions & 8 deletions src/Trait/PrivatePropertiesTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,17 @@

use Yiisoft\ActiveRecord\AbstractActiveRecord;

use function get_object_vars;

/**
* Trait to handle private properties in Active Record classes.
Comment thread
Tigrov marked this conversation as resolved.
*
* The trait required when using private properties inside the model class.
*
* @link https://github.com/yiisoft/active-record/blob/master/docs/create-model.md#private-properties
*
* @see AbstractActiveRecord::propertyValuesInternal()
* @see AbstractActiveRecord::populateProperty()
*/
trait PrivatePropertiesTrait
{
protected function propertyValuesInternal(): array
{
return get_object_vars($this);
}

protected function populateProperty(string $name, mixed $value): void
{
$this->$name = $value;
Expand Down
25 changes: 25 additions & 0 deletions tests/ActiveRecordTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Article;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\ArticleComment;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Cat;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Category;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CategoryAfterDelete;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerQuery;
Expand All @@ -28,6 +29,7 @@
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\DefaultValueOnInsertAr;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Dog;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Item;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\ItemWithPropertyHooks;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\NoExist;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\NullValues;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Order;
Expand Down Expand Up @@ -56,6 +58,8 @@
use function in_array;
use function count;

use const PHP_VERSION_ID;

abstract class ActiveRecordTest extends TestCase
{
public function testStoreNull(): void
Expand Down Expand Up @@ -1945,5 +1949,26 @@ public function testCreateQueryWithModelInstance(): void
$this->assertSame(Customer::class, $query->getModel()::class);
}

public function testRelationDefinedViaPropertyHook(): void
{
if (PHP_VERSION_ID < 80400) {
$this->markTestSkipped('Property hooks are not supported in PHP < 8.4');
}

$item = ItemWithPropertyHooks::query()->findByPk(1);
$itemCategory = $item->category;

$this->assertInstanceOf(Category::class, $itemCategory);
$this->assertSame(1, $itemCategory->getId());
$this->assertSame('Books', $itemCategory->getName());

$item->category = Category::query()->findByPk(2);
$itemCategory = $item->category;

$this->assertInstanceOf(Category::class, $itemCategory);
$this->assertSame(2, $itemCategory->getId());
$this->assertSame('Movies', $itemCategory->getName());
}

abstract protected function createFactory(): Factory;
}
15 changes: 15 additions & 0 deletions tests/Stubs/ActiveRecord/ItemWithPropertyHooks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord;

class ItemWithPropertyHooks extends Item
{
public Category $category {
get => $this->relation('category');
set {
$this->populateRelation('category', $value);
}
}
}
Loading