PHP code example of tuzelko / yii2-softdelete

1. Go to this page and download the library: Download tuzelko/yii2-softdelete library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

tuzelko / yii2-softdelete example snippets


// Unix timestamp (default)
$this->addColumn('{{%post}}', 'deleted_at', $this->integer()->null()->defaultValue(null));

// — or — boolean flag
$this->addColumn('{{%article}}', 'is_deleted', $this->boolean()->notNull()->defaultValue(false));

use tuzelko\yii\softdelete\SoftDeleteTrait;
use yii\db\ActiveRecord;

class Post extends ActiveRecord
{
    use SoftDeleteTrait;

    public static function tableName(): string
    {
        return 'post';
    }
}

class Article extends ActiveRecord
{
    use SoftDeleteTrait;

    public static function tableName(): string { return 'article'; }

    public static function softDeleteColumn(): string { return 'is_deleted'; }
    public static function softDeleteType(): int      { return self::TYPE_BOOL; }
}

$post = Post::findOne(1);

$post->softDelete();      // soft-delete — sets deleted_at, hides from default scope
$post->isSoftDeleted();   // true

$post->restore();         // clears deleted_at, record becomes visible again
$post->isSoftDeleted();   // false

$post->hardDelete();      // permanent hard-delete (fires standard Yii2 before/afterDelete events)

// Default — excludes soft-deleted records (no extra call needed)
Post::find()->all();

// Include soft-deleted records alongside active ones
Post::find()->withDeleted()->all();

// Only soft-deleted records
Post::find()->onlyDeleted()->all();

// Soft-delete all active records matching the condition
Post::softDeleteAll(['status' => 'spam']);

// Restore all soft-deleted records
Post::restoreAll();

// Restore specific records
Post::restoreAll(['id' => [3, 5, 7]]);

// Permanently delete all soft-deleted records
Post::hardDeleteAll(['is not', 'deleted_at', null]);

// updateAll() also skips soft-deleted records automatically
Post::updateAll(['status' => 'archived'], ['category_id' => 2]);

class Post extends ActiveRecord
{
    use SoftDeleteTrait;

    public static function tableName(): string { return 'post'; }

    // Always route delete() to hardDelete()
    public static function defaultDeleteMethod(): int
    {
        return self::DELETE_METHOD_HARD;
    }
}

class Post extends ActiveRecord
{
    use SoftDeleteTrait;

    public static function tableName(): string { return 'post'; }

    // Disable delete() entirely — callers must choose softDelete() or hardDelete() explicitly
    public static function defaultDeleteMethod(): int
    {
        return self::DELETE_METHOD_DISABLED;
    }
}

class User extends ActiveRecord
{
    // hasMany — only active (non-deleted) posts are returned
    public function getPosts(): SoftDeleteActiveQuery
    {
        return $this->hasMany(Post::class, ['user_id' => 'id']);
    }

    // To uery
    {
        return $this->hasOne(Post::class, ['user_id' => 'id'])
            ->orderBy(['created_at' => SORT_DESC]);
    }
}

class Post extends ActiveRecord
{
    use SoftDeleteTrait;

    public static function tableName(): string { return 'post'; }

    // Relation to a model that does NOT use soft-delete — works as usual
    public function getUser(): \yii\db\ActiveQuery
    {
        return $this->hasOne(User::class, ['id' => 'user_id']);
    }

    // Relation to another soft-delete model
    public function getComments(): SoftDeleteActiveQuery
    {
        return $this->hasMany(Comment::class, ['post_id' => 'id']);
    }
}

// Load users and only their active posts (soft-delete scope applied automatically)
$users = User::find()->with('posts')->all();

foreach ($users as $user) {
    foreach ($user->posts as $post) {
        // $post is never soft-deleted
    }
}

// Load users together with ALL their posts (including deleted)
$users = User::find()
    ->with(['posts' => fn($q) => $q->withDeleted()])
    ->all();

// Load users with only their deleted posts
$users = User::find()
    ->with(['posts' => fn($q) => $q->onlyDeleted()])
    ->all();

// LEFT JOIN (default) — all users appear; only active posts are joined
// Generated SQL: ... LEFT JOIN post ON user.id = post.user_id AND post.deleted_at IS NULL
//                    WHERE user.deleted_at IS NULL
$users = User::find()->joinWith('posts')->all();

// INNER JOIN — only users with at least one active post are returned
$users = User::find()->joinWith('posts', false, 'INNER JOIN')->all();

// Include deleted posts in the JOIN
$users = User::find()->joinWith(['posts' => fn($q) => $q->withDeleted()])->all();

// JOIN only with deleted posts (e.g. to find users with pending cleanup)
$users = User::find()
    ->joinWith(['posts' => fn($q) => $q->onlyDeleted()], false, 'INNER JOIN')
    ->all();

$post->on(Post::EVENT_BEFORE_SOFT_DELETE, function (\yii\base\ModelEvent $event) {
    if (!Yii::$app->user->can('deletePost')) {
        $event->isValid = false; // cancel the soft-delete
    }
});

// In your migration
$this->createIndex('idx_post_deleted_at', 'post', 'deleted_at');

// Boolean column — a partial index (supported by PostgreSQL and SQLite) is even more efficient
$this->createIndex('idx_article_is_deleted', 'article', 'is_deleted');

class Post extends ActiveRecord
{
    use SoftDeleteTrait;

    public static function tableName(): string { return 'post'; }

    public function afterSoftDelete(): void
    {
        Comment::softDeleteAll(['post_id' => $this->id]);
    }

    public function afterRestore(): void
    {
        Comment::restoreAll(['post_id' => $this->id]);
    }
}

// ✗ scope is added twice — the string is not inspected
Post::softDeleteAll("deleted_at IS NULL AND category_id = 5");

// ✓ wrap in an array so the column is detected
Post::softDeleteAll(['and', ['is', 'deleted_at', null], ['category_id' => 5]]);