Skip to content
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
895ae13
Add Events
Tigrov Jun 21, 2024
1a6d192
Apply fixes from StyleCI
StyleCIBot Jun 10, 2025
5b0bd2e
Apply Rector changes (CI)
Tigrov Jun 10, 2025
dfe978b
Fix psalm
Tigrov Jun 10, 2025
a8b557b
Merge branch 'master' into add-events
Tigrov Jun 12, 2025
00d8a5e
Merge branch 'master' into add-events
vjik Jun 20, 2025
325876c
Improve and add `SoftDelete`, `AfterUpsert`, `BeforeUpsert`
Tigrov Jun 28, 2025
295191c
Fix
Tigrov Jun 28, 2025
f08df59
Fix
Tigrov Jun 29, 2025
8109d02
Replace `ActiveRecordInterface` with `object` in `EventDispatcher::ad…
Tigrov Jun 29, 2025
e69c1bc
Replace with `EventDispatcherProvider`
Tigrov Jul 8, 2025
f93fd17
Replace with `AttributeHandlerProvider`
Tigrov Jul 8, 2025
7ba4059
Add doc [skip ci]
Tigrov Jul 10, 2025
7635f3e
Update doc [skip ci]
Tigrov Jul 10, 2025
8e2d33e
Improve `EventDispatcherProvider`
Tigrov Jul 10, 2025
5d129a3
Improve doc
Tigrov Jul 21, 2025
827447b
Merge branch 'master' into add-events
Tigrov Aug 3, 2025
935078c
Improve
Tigrov Aug 4, 2025
3f9e104
Merge branch 'master' into add-events
Tigrov Aug 4, 2025
d1bd615
Merge branch 'master' into add-events
Tigrov Aug 5, 2025
2256687
Merge branch 'master' into add-events
Tigrov Aug 5, 2025
8b73636
Apply fixes from StyleCI
StyleCIBot Aug 5, 2025
a01d9e1
Fix tests
Tigrov Aug 6, 2025
19bdf90
Fix composer-require-checker
Tigrov Aug 6, 2025
f1ec06d
Fix composer-require-checker
Tigrov Aug 6, 2025
7463fe5
Fix composer-require-checker
Tigrov Aug 6, 2025
e294a86
Merge branch 'master' into add-events
Tigrov Aug 6, 2025
863d710
Merge branch 'master' into add-events
vjik Aug 8, 2025
7975b89
Fix psalm
Tigrov Aug 8, 2025
7650a1e
Update doc
Tigrov Aug 9, 2025
f5c4484
Merge branch 'master' into add-events
Tigrov Aug 10, 2025
86598c6
Merge branch 'master' into add-events
Tigrov Sep 2, 2025
da0ceae
Merge branch 'master' into add-events
vjik Sep 8, 2025
3aadcdc
Cleanup (#453)
vjik Sep 8, 2025
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
5 changes: 5 additions & 0 deletions composer-require-checker.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
{
"symbol-whitelist": [
"Psr\\EventDispatcher\\EventDispatcherInterface",
"Psr\\EventDispatcher\\StoppableEventInterface",
"Psr\\Http\\Message\\ResponseInterface",
"Psr\\Http\\Message\\ServerRequestInterface",
"Psr\\Http\\Server\\MiddlewareInterface",
"Psr\\Http\\Server\\RequestHandlerInterface",
"Yiisoft\\Arrays\\ArrayableTrait",
"Yiisoft\\EventDispatcher\\Dispatcher\\Dispatcher",
"Yiisoft\\EventDispatcher\\Provider\\ListenerCollection",
"Yiisoft\\EventDispatcher\\Provider\\Provider",
"Yiisoft\\Factory\\Factory"
]
}
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"yiisoft/cache": "^3.0",
"yiisoft/db-sqlite": "dev-master",
"yiisoft/di": "^1.3",
"yiisoft/event-dispatcher": "^1.1",
"yiisoft/factory": "^1.3",
"yiisoft/middleware-dispatcher": "^5.2"
},
Expand All @@ -55,6 +56,7 @@
"yiisoft/db-mssql": "For MSSQL database support",
"yiisoft/db-oracle": "For Oracle database support",
"yiisoft/factory": "For factory support",
"yiisoft/event-dispatcher": "For events support",
"yiisoft/middleware-dispatcher": "For middleware support"
},
"autoload": {
Expand Down
2 changes: 1 addition & 1 deletion src/ActiveQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ public function findByPk(array|float|int|string $values): array|ActiveRecordInte
}
}

return $this->setWhere(array_combine($primaryKey, $values))->one();
return (clone $this)->andWhere(array_combine($primaryKey, $values))->one();
}

public function on(array|string|null $value): static
Expand Down
88 changes: 88 additions & 0 deletions src/Event/AbstractEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Psr\EventDispatcher\StoppableEventInterface;
use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Base class for events in Active Record models.
*/
abstract class AbstractEvent implements StoppableEventInterface
{
/** @var bool Whether the default action of the event should be prevented. */
private bool $isDefaultPrevented = false;
/** @var bool Whether the propagation of the event should be stopped. */
private bool $isPropagationStopped = false;
/** @var mixed The return value if the default action is prevented. */
private mixed $returnValue = null;

/**
* @param ActiveRecordInterface $model The target model associated with this event.
*/
public function __construct(private readonly ActiveRecordInterface $model)
{
}

/**
* @return ActiveRecordInterface The target model associated with this event.
*/
public function getModel(): ActiveRecordInterface
{
return $this->model;
}

/**
* Returns the value that will be returned by the method that triggered this event
* if the {@see isDefaultPrevented() default action is prevented}.
*/
public function getReturnValue(): mixed
{
return $this->returnValue;
}

/**
* Checks if the default action associated with this event has been prevented.
*/
public function isDefaultPrevented(): bool
{
return $this->isDefaultPrevented;
}

public function isPropagationStopped(): bool
{
return $this->isPropagationStopped;
}

/**
* Prevents the default action associated with this event from being executed.
*
* @see returnValue()
*/
public function preventDefault(): void
{
$this->isDefaultPrevented = true;
}

/**
* Sets the return value which will be returned by the method that triggered this event
* if the {@see isDefaultPrevented() default action is prevented}.
*
* @see preventDefault()
*/
public function returnValue(mixed $returnValue): void
{
$this->returnValue = $returnValue;
}

/**
* Stops the propagation of the event to further listeners.
* No further listeners will be notified after this method is called.
*/
public function stopPropagation(): void
{
$this->isPropagationStopped = true;
}
}
23 changes: 23 additions & 0 deletions src/Event/AfterCreateQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveQueryInterface;
use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the query has been created for the {@see ActiveRecordInterface} model.
*
* @see ActiveRecordInterface::query()
*/
final class AfterCreateQuery extends AbstractEvent
{
public function __construct(
ActiveRecordInterface $model,
public ActiveQueryInterface &$query,
) {
parent::__construct($model);
}
}
24 changes: 24 additions & 0 deletions src/Event/AfterDelete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the record has been deleted from the database.
*
* @see ActiveRecordInterface::delete()
*/
final class AfterDelete extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that was deleted.
* @param int $count Number of deleted rows.
*/
public function __construct(ActiveRecordInterface $model, public int &$count)
{
parent::__construct($model);
}
}
24 changes: 24 additions & 0 deletions src/Event/AfterInsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the record has been inserted into the database.
*
* @see ActiveRecordInterface::insert
*/
final class AfterInsert extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that has been inserted.
* @param bool $isSuccessful Whether the insert operation is successful.
*/
public function __construct(ActiveRecordInterface $model, public bool &$isSuccessful)
{
parent::__construct($model);
}
}
24 changes: 24 additions & 0 deletions src/Event/AfterPopulate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the model has been populated with data.
*
* @see ActiveRecordInterface::populate()
*/
final class AfterPopulate extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that has been populated.
* @param array $data The data used to populate the model.
*/
public function __construct(ActiveRecordInterface $model, public readonly array $data)
{
parent::__construct($model);
}
}
24 changes: 24 additions & 0 deletions src/Event/AfterSave.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the model has been saved to the database.
*
* @see ActiveRecordInterface::afterSave()
*/
final class AfterSave extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that was saved.
* @param bool $isSuccessful Whether the save operation was successful.
*/
public function __construct(ActiveRecordInterface $model, public bool &$isSuccessful)
{
parent::__construct($model);
}
}
24 changes: 24 additions & 0 deletions src/Event/AfterUpdate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the record has been updated in the database.
*
* @see ActiveRecordInterface::update()
*/
final class AfterUpdate extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that was updated.
* @param int $count The number of rows that were updated.
*/
public function __construct(ActiveRecordInterface $model, public int &$count)
{
parent::__construct($model);
}
}
24 changes: 24 additions & 0 deletions src/Event/AfterUpsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered after the model has been upserted (inserted or updated).
*
* @see ActiveRecordInterface::upsert()
*/
final class AfterUpsert extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that was upserted.
* @param bool $isSuccessful Whether the upsert operation was successful.
*/
public function __construct(ActiveRecordInterface $model, public bool &$isSuccessful)
{
parent::__construct($model);
}
}
21 changes: 21 additions & 0 deletions src/Event/BeforeCreateQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered before creating the query for the {@see ActiveRecordInterface} model.
*
* @see ActiveRecordInterface::query()
*/
final class BeforeCreateQuery extends AbstractEvent
{
public function __construct(
ActiveRecordInterface $model,
) {
parent::__construct($model);
}
}
14 changes: 14 additions & 0 deletions src/Event/BeforeDelete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

/**
* Event triggered before the record is deleted from the database.
*
* @see ActiveRecordInterface::delete()
*/
final class BeforeDelete extends AbstractEvent
{
}
25 changes: 25 additions & 0 deletions src/Event/BeforeInsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered before a new record is inserted into the database.
* It allows to modify properties that will be used for {@see ActiveRecordInterface::insert()} operation.
*
* @see ActiveRecordInterface::insert()
*/
final class BeforeInsert extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that is being inserted.
* @param array|null &$properties The properties that will be used for the insert operation.
*/
public function __construct(ActiveRecordInterface $model, public array|null &$properties)
{
parent::__construct($model);
}
}
25 changes: 25 additions & 0 deletions src/Event/BeforePopulate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Event;

use Yiisoft\ActiveRecord\ActiveRecordInterface;

/**
* Event triggered before the model is populated with data.
* It allows to modify the data that will be used for {@see ActiveRecordInterface::populateRecord()} operation.
*
* @see ActiveRecordInterface::populateRecord()
*/
final class BeforePopulate extends AbstractEvent
{
/**
* @param ActiveRecordInterface $model The model that will be populated.
* @param array &$data The data that will be used to populate the model.
*/
public function __construct(ActiveRecordInterface $model, public array &$data)
{
parent::__construct($model);
}
}
Loading
Loading