PHP code example of privacy-ci / laravel

1. Go to this page and download the library: Download privacy-ci/laravel 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/ */

    

privacy-ci / laravel example snippets


$this->ignore(FeatureFlag::class)->reason('internal flag, no subject link');

final class UserPrivacyPolicy extends PrivacyPolicy
{
    public function configure(): void
    {
        $this->subject(User::class);

        // ── users ───────────────────────────────────── subject root
        //    email                         0.99  email address
        //    password                      0.95  credential
        //    name                          0.65  possibly a personal name

        // $this->delete(User::class);
        // $this->anonymize(User::class, ['email' => '[email protected]', 'name' => 'Deleted user']);
        //   Masking keeps the row so foreign keys survive. Use placeholders,
        //   not null: identifying columns are usually NOT NULL.

        // ── comments ────────────────────────────────── linked by user_id
        //    author_ip                     0.99  IP address
        //    user_id                       1.00  comments.user_id -> users.id

        // $this->anonymize(Comment::class, ['author_ip' => null, 'user_id' => null]);
        // $this->delete(Comment::class);

        // ── subscribers ─────────────────────────────── no link to the subject
        //    email                         0.99  email address

        // No foreign key to the subject, a generated handler cannot look these
        // rows up. Supply the lookup yourself, or rule the table out:
        // $this->custom('subscribers', \App\Privacy\PurgeTheseRows::class);
        // $this->ignore('subscribers')->reason("");
    }
}

namespace App\Privacy;

use App\Models\{Comment, Order, User};
use PrivacyCI\Policy\PrivacyPolicy;

class UserPrivacyPolicy extends PrivacyPolicy
{
    public function configure(): void
    {
        $this->subject(User::class);

        $this->delete(User::class);
        $this->anonymize(Comment::class, ['user_id' => null, 'author_ip' => null]);
        $this->retain(Order::class)->reason('statutory accounting retention, 7y');

        $this->deleteRedis('profile:{id}');
        $this->deleteStorage('avatars/{id}.jpg', disk: 's3');
    }
}

'discovery' => [
    'model_paths' => [base_path('src/Domain/Models')],
],

'model_base_classes' => [
    \Acme\Support\Database\Entity::class,
],

final class DeleteUser implements SubjectDeleter
{
    public function delete(DeletionRequest $request): void
    {
        $subjectId = $request->subjectId;

        Storage::disk('s3')->delete("avatars/{$subjectId}.png");

        Redis::del("user:{$subjectId}");

        DB::table('sessions')
            ->where('user_id', $subjectId)
            ->update([
                'ip_address' => null,
                'user_id' => null,
            ]);

        // retained: statutory accounting retention, 7y

        \App\Models\User::query()->whereKey($subjectId)->delete();

        // TODO: these locations have no policy and are therefore untouched.
        //   - recommendation_events.user_id
    }
}

// $this->delete(User::class);
// $this->anonymize(User::class, ['email' => '[email protected]', 'name' => 'Deleted user']);

$this->anonymize(User::class, [
    'name' => 'Deleted user',
    'email' => '[email protected]',
    'password' => '',
]);

use PrivacyCI\Lifecycle\Laravel\RequestsDeletion;

class User extends Authenticatable
{
    use RequestsDeletion;
}

$user->requestDeletion(via: 'account settings');  // suspended now, erased in 14 days
$user->deletionPending();                         // true
$user->isSuspendedForDeletion();                  // true
$user->daysUntilDeletion();                       // 14
$user->reactivate();                              // "actually, keep my account"

use PrivacyCI\Lifecycle\{DeletionRequest, SubjectSuspender, SubjectDeleter};

class SuspendUser implements SubjectSuspender
{
    public function suspend(DeletionRequest $request): void
    {
        // set status to pending_delete, revoke sessions and tokens, hide the
        // profile, unsubscribe from sends, drop from search and analytics.
        // Nothing here deletes, every change must be undoable below.
    }

    public function reactivate(DeletionRequest $request): void
    {
        // put it all back
    }
}

class DeleteUser implements SubjectDeleter
{
    public function delete(DeletionRequest $request): void
    {
        // your existing DeleteUserJob, unchanged
    }
}

use Illuminate\Support\Facades\Mail;
use PrivacyCI\Mail\DeletionScheduledMail;

public function suspend(DeletionRequest $request): void
{
    $user = User::findOrFail($request->subjectId);

    $user->update(['status' => 'pending_delete']);
    $user->tokens()->delete();
    // ...hide the profile, unsubscribe, drop from indexes

    Mail::to($user)->send(new DeletionScheduledMail($request));
}

if ($user->deletionPending()) {
    return view('auth.reactivate', ['days' => $user->daysUntilDeletion()]);
}

use PrivacyCI\Lifecycle\{DeletionRequest, SubjectNotifier};
use PrivacyCI\Mail\DeletionReminderMail;

class NotifySubject implements SubjectNotifier
{
    public function remind(DeletionRequest $request, int $daysRemaining): void
    {
        $user = User::findOrFail($request->subjectId);

        Mail::to($user)->send(new DeletionReminderMail($request, $daysRemaining));
    }
}

Cache::put("user:{$user->id}", $payload);
Storage::disk('s3')->put("avatars/{$user->id}.jpg", $file);
Redis::set('profile:' . $user->id, $json);

DB::statement("CREATE TABLE `legacy_members` (
  `member_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `state` enum('Active','Suspended','Pending Close') NOT NULL,
  PRIMARY KEY (`member_id`),
  CONSTRAINT `fk` FOREIGN KEY (`owner_id`) REFERENCES `legacy_members` (`member_id`)
) ENGINE=InnoDB;");

'subjects' => ['user' => 'legacy_members.member_id'],

Event::listen(DeletionRequested::class, LogPrivacyEvents::class);
Event::listen(DeletionCompleted::class, LogPrivacyEvents::class);
bash
composer vendor:publish --tag=privacy-config
php artisan privacy:discover
bash
php artisan vendor:publish --tag=privacy-migrations
php artisan migrate
php artisan privacy:forget 1 --force          # suspends, 14-day countdown
php artisan privacy:forget 1 --cancel         # reactivates
php artisan privacy:process-deletions --dry-run
bash
php artisan privacy:baseline   # once, when adopting: forgive existing debt
php artisan privacy:check      # in CI: fail only on what is new
bash
php artisan privacy:verify 42
bash
php artisan privacy:make-handler
bash
php artisan vendor:publish --tag=privacy-views
bash
php artisan privacy:forget 123              # suspend now, erase in 14 days
php artisan privacy:forget 123 --cancel     # reactivate and call it off
php artisan privacy:process-deletions --dry-run

  user:{user.id}         inferred   0.80   UNCLASSIFIED
  avatars/{user.id}.jpg  inferred   0.80   UNCLASSIFIED