Reputation: 6276
I'm trying to develop a small application in Laravel 5.5
where I've made an abstract model
which is extending Laravel eloquent model
something like this:
<?php
use Illuminate\Database\Eloquent\Model;
class AbstractModel extends Model
{
}
Now just for general convention I'm setting a database connection for this model:
<?php
use Illuminate\Database\Eloquent\Model;
class AbstractModel extends Model
{
/**
* Defining connection for database
*
* @var string
**/
protected $connection='mysql';
}
And I created my own model which extends this abstract class
:
<?php
use Illuminate\Database\Eloquent\SoftDeletes;
class Posts extends AbstractModel
{
use SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'unique_id', 'title', 'contents'
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'id'
];
}
By defining this by default we come to know that it will have a database connection of mysql, similarly fillable
are defined for mass assignment. In similar way I want to make one encrypt
variable which will encrypt
and decrypt
the data from the database so for this I added accessor
and mutator
to my encrypt variable
inside my model:
<?php
use Illuminate\Database\Eloquent\SoftDeletes;
class Posts extends AbstractModel
{
use SoftDeletes;
/**
* The attributes that will have encryption.
*
* @var array
*/
protected $encryption = ['unique_id', 'title', 'contents'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'unique_id', 'title', 'contents'
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'id'
];
}
and configured it back in my abstract model
:
<?php
use Illuminate\Database\Eloquent\Model;
class AbstractModel extends Model
{
/**
* Defining connection for database
*
* @var string
**/
protected $connection='mysql';
/**
* Defining encryption
*
* @var array
**/
protected $encryption = [];
public function setAttributes()
{
foreach ($this->encryption as $attributes)
{
$this->attributes[$attributes] = Crypt::encryptString($this->attributes[$attributes]);
}
}
public function getAttributes()
{
foreach ($this->encryption as $attributes)
{
$this->attributes[$attributes] = Crypt::decryptString($this->attributes[$attributes]);
}
}
}
I think my approach is wrong as there is no encryption or decryption done on these attributes, I can see the data sent to create rows is stored in database without any encryption and in same way retrieved also.
More over I would like to have a use case where I'm encrypting these fields also their attribute accessor or mutator is called inside their own model for example:
<?php
use Illuminate\Database\Eloquent\SoftDeletes;
class Posts extends AbstractModel
{
use SoftDeletes;
/**
* The attributes that will have encryption.
*
* @var array
*/
protected $encryption = ['unique_id', 'title', 'contents'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'unique_id', 'title', 'contents'
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'id'
];
public function setTitleAttributes($value)
{
return ucfirst($value);
}
public function getTitleAttributes($value)
{
return ucfirst($value)
}
}
Any feedback comments are welcome. Thanks.
Upvotes: 0
Views: 1764
Reputation: 4674
First, the Eloquent model has setAttribute()
& getAttribute()
methods not setAttributes()
and getAttributes()
.
Secondly, for this kind of situation. I'd rather use the Eloquent's event. Because the setAttribute()
or getAttribute()
methods will only be fired when you access the attribute dynamically like: $post->title
.
You can encrypt the attributes on saving
event. And decrypt it back using retrieved
event.
<?php
namespace App;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Database\Eloquent\Model;
abstract class AbstractModel extends Model
{
protected $connection = 'mysql';
protected $encryption = [];
protected static function boot()
{
parent::boot();
// When being retrieved, decrypt the attributes.
static::retrieved(function ($instance) {
foreach ($instance->encryption as $encryptedKey) {
$instance->attributes[$encryptedKey] = Crypt::decryptString($instance->attributes[$encryptedKey]);
}
});
// When saving (could be create or update) the modal, encrypt the attributes.
static::saving(function ($instance) {
foreach ($instance->encryption as $encryptedKey) {
$instance->attributes[$encryptedKey] = Crypt::encryptString($instance->attributes[$encryptedKey]);
}
});
// Once it's saved, decrypt it back so it's still readble.
static::saved(function ($instance) {
foreach ($instance->encryption as $encryptedKey) {
$instance->attributes[$encryptedKey] = Crypt::decryptString($instance->attributes[$encryptedKey]);
}
});
}
}
When you decided to use this approach, don't override both the setAttribute()
& getAttribute()
methods. Since it will most likely to double encrypt/decrypt the attributes.
Also, it supposed to be setTitleAttribute()
and getTitleAttribute()
—in singular form. And on the setTitleAttribute()
you should mutate the title
attribute; not returning the intended value. I don't see the purpose of capitalizing the title
either since it will be encrypted anyway.
<?php
namespace App;
class Post extends Model
{
protected $encryption = ['unique_id', 'title', 'contents'];
protected $fillable = ['unique_id', 'title', 'contents'];
// Expected to mutate the title attribute.
public function setTitleAttribute($value)
{
$this->attributes['title'] = ucfirst($value);
}
public function getTitleAttribute($value)
{
return ucfirst($value);
}
}
Hope this gives you some ideas.
Upvotes: 2