diff --git a/composer.json b/composer.json
index fad8c7e..9d94d68 100644
--- a/composer.json
+++ b/composer.json
@@ -38,7 +38,8 @@
"php": ">=8.1",
"cycle/database": "^2.11",
"cycle/orm": "^2.7",
- "psr/container": "^2.0"
+ "psr/container": "^2.0",
+ "yiisoft/injector": "^1.2"
},
"require-dev": {
"buggregator/trap": "^1.5",
diff --git a/composer.lock b/composer.lock
index e2e8662..bf490e6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "39a64bf69a855ddea1139bf99c075406",
+ "content-hash": "68d723ec5ccf2cd6e9ca2ec0b17ffca4",
"packages": [
{
"name": "brick/math",
@@ -4143,6 +4143,76 @@
}
],
"time": "2025-04-30T23:37:27+00:00"
+ },
+ {
+ "name": "yiisoft/injector",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/injector.git",
+ "reference": "0dc0127a7542341bdaabda7b85204e992938b83e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/injector/zipball/0dc0127a7542341bdaabda7b85204e992938b83e",
+ "reference": "0dc0127a7542341bdaabda7b85204e992938b83e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4|^8.0"
+ },
+ "require-dev": {
+ "maglnet/composer-require-checker": "^3.8|^4.2",
+ "phpbench/phpbench": "^1.1",
+ "phpunit/phpunit": "^9.5",
+ "psr/container": "^1.0|^2.0",
+ "rector/rector": "^0.18.12",
+ "roave/infection-static-analysis-plugin": "^1.16",
+ "spatie/phpunit-watcher": "^1.23",
+ "vimeo/psalm": "^4.30|^5.7",
+ "yiisoft/test-support": "^1.2"
+ },
+ "suggest": {
+ "psr/container": "For automatic resolving of dependencies"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Yiisoft\\Injector\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "PSR-11 compatible injector. Executes a callable and makes an instances by injecting dependencies from a given DI container.",
+ "homepage": "https://www.yiiframework.com/",
+ "keywords": [
+ "PSR-11",
+ "dependency injection",
+ "di",
+ "injector",
+ "reflection"
+ ],
+ "support": {
+ "chat": "https://t.me/yii3en",
+ "forum": "https://www.yiiframework.com/forum/",
+ "irc": "irc://irc.freenode.net/yii",
+ "issues": "https://github.com/yiisoft/injector/issues?state=open",
+ "source": "https://github.com/yiisoft/injector",
+ "wiki": "https://www.yiiframework.com/wiki/"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/yiisoft",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/yiisoft",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-12-20T09:39:03+00:00"
}
],
"packages-dev": [
@@ -11202,76 +11272,6 @@
}
],
"time": "2021-10-26T21:43:25+00:00"
- },
- {
- "name": "yiisoft/injector",
- "version": "1.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/yiisoft/injector.git",
- "reference": "0dc0127a7542341bdaabda7b85204e992938b83e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yiisoft/injector/zipball/0dc0127a7542341bdaabda7b85204e992938b83e",
- "reference": "0dc0127a7542341bdaabda7b85204e992938b83e",
- "shasum": ""
- },
- "require": {
- "php": "^7.4|^8.0"
- },
- "require-dev": {
- "maglnet/composer-require-checker": "^3.8|^4.2",
- "phpbench/phpbench": "^1.1",
- "phpunit/phpunit": "^9.5",
- "psr/container": "^1.0|^2.0",
- "rector/rector": "^0.18.12",
- "roave/infection-static-analysis-plugin": "^1.16",
- "spatie/phpunit-watcher": "^1.23",
- "vimeo/psalm": "^4.30|^5.7",
- "yiisoft/test-support": "^1.2"
- },
- "suggest": {
- "psr/container": "For automatic resolving of dependencies"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Yiisoft\\Injector\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "description": "PSR-11 compatible injector. Executes a callable and makes an instances by injecting dependencies from a given DI container.",
- "homepage": "https://www.yiiframework.com/",
- "keywords": [
- "PSR-11",
- "dependency injection",
- "di",
- "injector",
- "reflection"
- ],
- "support": {
- "chat": "https://t.me/yii3en",
- "forum": "https://www.yiiframework.com/forum/",
- "irc": "irc://irc.freenode.net/yii",
- "issues": "https://github.com/yiisoft/injector/issues?state=open",
- "source": "https://github.com/yiisoft/injector",
- "wiki": "https://www.yiiframework.com/wiki/"
- },
- "funding": [
- {
- "url": "https://github.com/yiisoft",
- "type": "github"
- },
- {
- "url": "https://opencollective.com/yiisoft",
- "type": "open_collective"
- }
- ],
- "time": "2023-12-20T09:39:03+00:00"
}
],
"aliases": [],
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 325ad1b..eb633d9 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -4,9 +4,9 @@
-
-
-
+
+ getSchema()->define(static::class, SchemaInterface::TABLE)]]>
+
@@ -19,8 +19,8 @@
-
+
-
+
diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php
index e65a2bc..e08fed7 100644
--- a/src/ActiveRecord.php
+++ b/src/ActiveRecord.php
@@ -12,6 +12,7 @@
use Cycle\ORM\Exception\RunnerException;
use Cycle\ORM\ORMInterface;
use Cycle\ORM\RepositoryInterface;
+use Cycle\ORM\SchemaInterface;
/**
* A base class for entities that are managed by the ORM.
@@ -19,6 +20,16 @@
*/
abstract class ActiveRecord
{
+ /**
+ * Get the table name associated with the entity.
+ *
+ * @return non-empty-string
+ */
+ final public static function tableName(): string
+ {
+ return static::getOrm()->getSchema()->define(static::class, SchemaInterface::TABLE);
+ }
+
/**
* Create a new entity instance with the given data.
* It is preferable to use this method instead of the constructor because
@@ -142,8 +153,14 @@ final public static function groupActions(
* will be used.
*
* @template TResult
- * @param callable(DatabaseInterface, EntityManagerInterface): TResult $callback Note that the provided
- * Entity Manager doesn't collect operations and executes them right away in the opened transaction.
+ * @param callable(): TResult $callback A function that may accept parameters of the following types in any order:
+ * - {@see DatabaseInterface}
+ * - {@see EntityManagerInterface}
+ * - {@see ORMInterface}
+ * - {@see SchemaInterface}
+ * @psalm-param callable(...): TResult $callback
+ * @note that the provided Entity Manager doesn't collect operations and executes them right away in the opened transaction.
+ *
* @return TResult
*
* @throws TransactionException
diff --git a/src/Internal/TransactionFacade.php b/src/Internal/TransactionFacade.php
index 4f61afa..854cbb8 100644
--- a/src/Internal/TransactionFacade.php
+++ b/src/Internal/TransactionFacade.php
@@ -12,6 +12,7 @@
use Cycle\ORM\Service\SourceProviderInterface;
use Cycle\ORM\Transaction\Runner;
use Cycle\ORM\Transaction\UnitOfWork;
+use Yiisoft\Injector\Injector;
/**
* @internal
@@ -65,8 +66,9 @@ public static function groupOrmActions(
/**
* @template TResult
- * @param callable(DatabaseInterface, EntityManagerInterface): TResult $callback
+ * @param callable(): TResult $callback
* @param class-string|null $entity If null, the default database will be used.
+ * @psalm-param callable(...): TResult $callback
* @return TResult
*
* @throws TransactionException
@@ -86,12 +88,13 @@ public static function transact(
return $dbal->transaction(static function (DatabaseInterface $db) use ($callback): mixed {
$previous = self::$em;
try {
+ $orm = Facade::getOrm();
self::$em = $em = new EntityManager(
- static fn(): UnitOfWork => new UnitOfWork(Facade::getOrm(), Runner::outerTransaction(strict: true)),
+ static fn(): UnitOfWork => new UnitOfWork($orm, Runner::outerTransaction(strict: true)),
autoExecute: true,
);
- return $callback($db, $em);
+ return (new Injector())->invoke($callback, [$db, $em, $orm, $orm->getHeap(), $orm->getSchema()]);
} finally {
self::$em = $previous;
}
diff --git a/src/Repository/ActiveRepository.php b/src/Repository/ActiveRepository.php
index a170ace..782680a 100644
--- a/src/Repository/ActiveRepository.php
+++ b/src/Repository/ActiveRepository.php
@@ -51,6 +51,8 @@ public function __construct(string $role)
*
* @note Limit of 1 will be added to the query.
*
+ * @param string|int|non-empty-list|non-empty-array|object $id
+ *
* @return TEntity|null
*/
public function findByPK(mixed $id): ?object
diff --git a/tests/src/Functional/ActiveRecordTest.php b/tests/src/Functional/ActiveRecordTest.php
index 0314909..d7450b0 100644
--- a/tests/src/Functional/ActiveRecordTest.php
+++ b/tests/src/Functional/ActiveRecordTest.php
@@ -12,6 +12,9 @@
use Cycle\Database\DatabaseInterface;
use Cycle\ORM\EntityManagerInterface;
use Cycle\ORM\Exception\RunnerException;
+use Cycle\ORM\Heap\HeapInterface;
+use Cycle\ORM\ORMInterface;
+use Cycle\ORM\SchemaInterface;
use Cycle\ORM\Select\Repository;
use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use PHPUnit\Framework\Attributes\Test;
@@ -283,9 +286,30 @@ public function it_runs_transaction_with_orm_actions(): void
self::assertSame($savedUserFour->name, $user4->name);
}
+ #[Test]
+ public function transact_method_resolves_parameters(): void
+ {
+ $ars = User::transact(static fn(
+ SchemaInterface $schema,
+ EntityManagerInterface $em,
+ ORMInterface $orm,
+ HeapInterface $heap,
+ DatabaseInterface $dbal,
+ ): array => \func_get_args());
+
+ self::assertIsArray($ars);
+ }
+
#[Test]
public function query_method_returns_ActiveQuery(): void
{
self::assertInstanceOf(ActiveQuery::class, Identity::query());
}
+
+ #[Test]
+ public function get_table_name(): void
+ {
+ self::assertSame('user', User::tableName());
+ self::assertSame('user_identity', Identity::tableName());
+ }
}