Laravel 4 Beta Update: Soft Deletes und deren Verwendung

06. Mai 2013 Web-Entwicklung von Eric Kubenka

Laravel 4 befindet sich immer noch im Entwicklungsstatus und so kommen wöchentlich neue Funktionen dazu. Mit dem Updaten mittels Composer und dem Ausprobieren der neuen Funktionen kann man sich seine Zeit genüsslich vertreiben.

Seit dem jüngsten Update des Ende Mai erscheinenden Frameworks wurde nun das Feature Soft Delete für Models umgesetzt. Mit Soft Delete ist es nun nicht mehr nötig Einträge komplett aus der Datenbank zu löschen, sondern es wird lediglich ein Eintrag deleted_at in der Tabelle des Models hinzugefügt. Dadurch können Einträge beliebig gelöscht und mittels Restore-Funktion auch wiederhergestellt werden.

Ich möchte kurz an einem ausführlichen Beispiel erläutern wie die neuen Funktionen verwendet werden können.

 

Datenbanktabelle anlegen und neue Spalte deleted_at hinzufügen

Zu Beginn ist es notwendig die Datenbank-Verbindung in der app/config/database.php-Datei anzupassen. Anschließend ist mittels Artisan eine neue Migration anzulegen. Folgend habe ich folgende simple Tabelle für das bereits bestehende Model Users angelegt.

php artisan migrate:make adduser
<?php

use Illuminate\Database\Migrations\Migration;

class Adduser extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		/**
		 * Users-Tabelle: id, name, email, confirmed, 
		 */
		Schema::create('users', function($table)
		{
			$table->increments('id');
			$table->string('username', 255);
			$table->timestamps();
			$table->timestamp('deleted_at')->default(null)->nullable();
		});
	}

Im User-Model muss das Property softDelete gesetzt werden um die entsprechenden Methoden nutzen zu können.
<?php

class User extends Eloquent {

	/**
	 * The database table used by the model.
	 *
	 * @var string
	 */
	protected $table = 'users';

	protected $softDelete = true;

}

 

Basis-Routen definieren

Für die einfach gehaltene User-Tabelle habe ich Routen für die Events Create, Soft-Delete und Force-Delete angelegt. Zusätzlich existiert noch eine weitere Route zur Ausgabe aller aktiven Elemente.

/**
* Create new user
*/
Route::get('/user/add', function(){
	$usr = new User;
	$usr->username = 'Test';
	$usr->deleted_at = null;
	$usr->save();

	return "user added";
});

/**
* Delete specified user softly
*/
Route::get('/user/delete/{id}', function($id){

	$usr = User::find($id);
	if(isset($usr))
	{
		$usr->delete();
		return 'User '.$usr->username.' with id '.$usr->id.' deleted, softly';
	}
});

/**
* Delete specified user hard
*/
Route::get('/user/forcedelete/{id}', function($id){

	$usr = User::find($id);
	if(isset($usr))
	{
		$usr->forceDelete();
		return 'User '.$usr->username.' with id '.$usr->id.' deleted';
	}
});

Ich habe mir mittels der Add-Route ein paar Testnutzer angelegt welche ich für die folgenden Beispiele der neuen Methoden verwende.

 

Neue Soft-Delete-Methoden anwenden

Um beispielsweise nur aktive Benutzer anzuzeigen, reicht die bereits bekannte Abfrage User::all() aus. Sollen zusätzlich auch die bereits gelöschten Anwender angezeigt werden so erfüllt die neue Methode User::withTrashed() diese Anforderung.

Das Pendant dazu ist die Methode User::trashed() welche ausschließlich bereits gelöschte Einträge als Ergebnis liefert.

Neben der bereits bekannten Methode delete() existiert nun auch die Methode forceDelete(). Der Unterschied der beiden Methoden liegt bei Verwendung eines Soft-Delete-Models darin, dass bei delete() lediglich der Wert deleted_at in der Datenbank gesetzt wird. Die Methode forceDelete() hingegen löscht den Eintrag komplett aus der Datenbank.

Durch diese neuen Features und der Funktion weich gelöschte Einträge wiederherstellen zu können ergeben sich folgende Routen um die neuen Methoden jeweils kurz testen zu können.

/**
* Restore specified user 
*/
Route::get('/user/restore/{id}', function($id){


	$usr = User::trashed()->where('id', '=', $id)->first();

	if(isset($usr))
	{
		$usr->restore();
		return $usr->username.' with id '.$usr->id.' restored';
	}
});


/**
* Display all non-trashed users
*/
Route::get('/user', function(){

	$user = User::all();

	if(isset($user))
	{
		foreach ($user as $usr) {
			echo $usr->username.' with id: '.$usr->id.' - deleted_at: '.$usr->deleted_at.'<br>';
		}
		return;
	}
});

/**
* Display all users incl. trashed
*/
Route::get('/user/all', function(){

	$user = User::withTrashed()->get();

	if(isset($user))
	{
		foreach ($user as $usr) {
			echo $usr->username.' with id: '.$usr->id.' - deleted_at: '.$usr->deleted_at.'<br>';
		}
		return;
	}
});

/**
* Display trashed users only
*/
Route::get('/user/trashed', function(){

	$user = User::trashed()->get();

	if(isset($user))
	{
		foreach ($user as $usr) {
			echo $usr->username.' with id: '.$usr->id.' - deleted_at: '.$usr->deleted_at.'<br>';
		}
		return;
	}
});

Folgend möchte ich noch jeweils kurz die Ausgaben für die gegebenen Routen präsentieren und so verdeutlichen wie sich das Ganze im Ergebnis letztendlich wiederspiegelt. Damit das ganze an dieser Stelle nicht in einem Bilderhagel ausartet, stelle ich es mittels Code-Highlighter dar. Ich hoffe der Faden geht nicht verloren.

<?php

// 1. After hit route /user/add some times the route /user will display the following
> Test with id: 1 - deleted_at: 
> Test with id: 2 - deleted_at: 
> Test with id: 3 - deleted_at: 
> Test with id: 4 - deleted_at: 
> Test with id: 5 - deleted_at: 
> Test with id: 6 - deleted_at: 

// 2. Hit route /user/delete/2 to delete the user 2 softly
> User Test with id 2 deleted, softly

// 3. Hit route /user again to see if the user 2 isn't displayed
// because User::all() doesn't display the trashed users
> Test with id: 1 - deleted_at: 
> Test with id: 3 - deleted_at: 
> Test with id: 4 - deleted_at: 
> Test with id: 5 - deleted_at: 
> Test with id: 6 - deleted_at: 

// 4. Hit route /user/trashed to display all trashed users 
> Test with id: 2 - deleted_at: 2013-05-06 14:07:43

// 5. Hit route /user/all to display trashed and active users
> Test with id: 1 - deleted_at: 
> Test with id: 2 - deleted_at: 2013-05-06 14:07:43
> Test with id: 3 - deleted_at: 
> Test with id: 4 - deleted_at: 
> Test with id: 5 - deleted_at: 
> Test with id: 6 - deleted_at: 

// 6. Hit route /user/forceDelete/1 to delete the user 1 permantly
> User Test with id 1 deleted

// 7. Hit route /user/restore/2 to restore the softly deleted user
> Test with id 2 restored

// 8. Hit route /user/all to display all trashed and active users
// User 1 doesn't appear because it was deleted permantly
> Test with id: 2 - deleted_at: 
> Test with id: 3 - deleted_at: 
> Test with id: 4 - deleted_at: 
> Test with id: 5 - deleted_at: 
> Test with id: 6 - deleted_at:


Damit ist die kleine Einführung in das neue Feature bereits abgeschlossen. Und nun wünsche ich viel Spaß beim Ausprobieren und Umstellen Eurer Models. Der Source-Code zu den oben genannten Beispielen steht via GitHub zur Verfügung.

Zurück