Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Active Record Laravel Package

yiisoft/active-record

Active Record ORM for PHP in the Yii3 ecosystem. Map database tables to classes, perform CRUD operations, define relationships, and build queries through a familiar object-oriented API on top of yiisoft/db. A lightweight choice for ActiveRecord-style persistence.

View on GitHub
Deep Wiki
Context7

Getting Started

yiisoft/active-record is a standalone ActiveRecord implementation, not an Eloquent replacement. Treat it as a query/relation layer you can wire into Laravel when you want Yii-style AR behavior or are integrating Yii-derived code.

Minimal setup:

  1. Install the package with yiisoft/db and the appropriate DB driver:
    composer require yiisoft/active-record yiisoft/db
    
  2. Register a Yiisoft\Db\Connection\ConnectionInterface singleton in a Laravel service provider.
  3. Configure the package’s AR factory/connection wiring. Release 1.1.0 adds default config for the yiisoft/config plugin, so if you already use yiisoft/config, start there; otherwise bind the connection manually in Laravel.
  4. Create your first record class by extending the package’s base ActiveRecord class, defining tableName() and a relation.

Where to look first:

  • ActiveRecord / AbstractActiveRecord for property mapping, dirty tracking, hooks, and get().
  • ActiveQuery for query construction.
  • JoinWith for relation joins and closure-based join constraints.
  • The yiisoft/db connection for transactions, logging, and command execution.

First practical use case: map an existing table to an AR class, define a hasMany relation, then query with find() and joinWith() in a read path. This gives you the package’s main value: relation-aware query building without adopting Eloquent.

Implementation Patterns

Model and relation definitions

  • Keep one AR class per table and define relations with hasOne() / hasMany().
  • In 1.1.0, relation queries are created by the related class rather than the primary model class (Bug #550). This is the correct behavior and makes relations predictable when related classes have custom query classes. If you previously relied on the primary model’s custom query leaking into relation queries, review those relations.

Relation joins

  • Use joinWith() with string relation names for simple joins.
  • For constrained joins, use closures. The $relations parameter is now explicitly typed as array<string|callable(ActiveQueryInterface):void>. Type-hint closures against ActiveQueryInterface, not a concrete ActiveQuery:
    ->joinWith([
        'customer' => function (ActiveQueryInterface $query) {
            $query->andWhere(['active' => true]);
        },
    ])
    

Upsert and sync workflows

  • Use upsert() for import/sync jobs where rows may already exist.
  • Release 1.1.0 fixes two important upsert behaviors:
    • $updateProperties = false now works as insert-only.
    • Associative values passed to upsert() are prioritized during updates.
  • Be explicit about which columns should be updated. Test conflict resolution against your unique indexes.

Soft delete

  • Use the package’s SoftDelete support for archival flows.
  • 1.1.0 fixes SoftDelete with an initiated custom date. If you set a custom deletion timestamp, re-test delete/restore paths.

Hooks

  • Keep beforeSave / afterSave-style hook logic small and deterministic.
  • 1.1.0 fixes properties with hooks. Re-test hooks that mutate properties, especially if they previously appeared to be skipped or caused recursion.

Performance-sensitive reads

  • ActiveRecord::get() was optimized in 1.1.0. Use it for primary-key lookups in hot paths, but benchmark against your own data and indexes.
  • Avoid N+1 relation loads; use joinWith() or batch queries where appropriate.

Laravel integration

  • Wrap AR usage behind repositories/services rather than calling it directly from controllers.
  • Inject the yiisoft/db connection into your service layer and use it for transactions.
  • If you use yiisoft/config, adopt the new default plugin config as a baseline and override only what you need.

Gotchas and Tips

  • Not Eloquent. Do not expect Eloquent casts, accessors, model events, or Laravel relationship APIs. The package has its own hooks, property tracking, and query API.
  • Relation query ownership changed. Bug #550 means relation queries now come from the related class. If a relation depended on the primary model’s custom query class, move that logic to the related class or adjust the relation definition.
  • Closure type in JoinWith. The signature is now array<string|callable(ActiveQueryInterface):void>. If you type-hinted a closure parameter as ActiveQuery, change it to ActiveQueryInterface to stay compatible.
  • upsert() edge cases. $updateProperties = false now inserts only, and associative values win during updates. Re-check sync jobs that pass both associative values and update-column lists.
  • Dirty tracking with empty strings. AbstractActiveRecord::markPropertyChanged() no longer checks for an empty string. If your code relied on empty-string changes being ignored, verify update statements and optimistic-locking behavior.
  • Soft delete with custom dates. Re-test custom deletion timestamps, especially if you initialize the date yourself before calling delete.
  • Hooks and property mutation. The hook/property fix in 1.1.0 may change behavior in models where hooks mutate tracked properties. Add regression tests around those hooks.
  • No breaking changes in 1.1.0. This is a minor release; update within ^1.1. Still run your relation, upsert, soft-delete, and hook tests because several behavior fixes can expose assumptions.
  • Debugging. Use the yiisoft/db logger to inspect SQL. When a relation or upsert behaves unexpectedly, log the generated command and compare it with the related class’s query configuration.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource