Encriptando datos al guardarlos en base de datos con Laravel 5

He tenido que preparar un proceso de pago y para ello teníamos que guardar el número de cuenta IBAN en base de datos. Lógicamente este dato es delicado por lo que mejor guardarlo encriptado. Para ello en la base de datos lo guardaremos como varchar(255).

Luego vamos a necesitar el uso de un trait, para ello crearemos el fichero app\Traits\Encryptable.php:

namespace Aplicacion\Traits;
use Crypt;
trait Encryptable
{
    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);
        if (in_array($key, $this->encryptable)) {
            $value = Crypt::decrypt($value);
        }
        return $value;
    }

    public function setAttribute($key, $value)
    {
        if (in_array($key, $this->encryptable)) {
            $value = Crypt::encrypt($value);
        }
        return parent::setAttribute($key, $value);
    }
}

Luego lo integramos en el modelo:

namespace Aplicacion;
use Illuminate\Database\Eloquent\Model;
use Aplicacion\Traits\Encryptable;

class Registro extends Model {
  use Encryptable;
  protected $table = 'registros';
  protected $fillable = ['razon_social', 'cif', 'email', 'iban'];
// indicamos los campos que van a guardarse encriptados
  protected $encryptable = ['iban'];
}

Ya podre usar el modelo como cualquier otro sin necesidad de preocuparnos por la encriptación

Definiendo modelo en Laravel 5

A parte de poder crearlo desde la consola con artisan:

$ php artisan make:model Modelo --migration

Luego tendremos que personalizarlo y para ello tenemos los siguientes parámetros obligatorios:

  protected $table = 'tabla_en_la_base_de_:datos';
  protected $fillable = ['campo1', 'campo2', 'campo3', 'campo4'];

Pero podremos definir unos cuantos más como por ejemplo para indicar que la tabla no va a usar los campos created_at y updated_at

public $timestamps = false;

O si la tabla no va a tener una clave primaria incremental:

public $incrementing = false;

También podemos indicar el nombre la clave primaría en el caso que no sea la que se usa por defecto (id), en este caso para una tabla con varios campos formando la clave primaria:

protected $primaryKey = ['campo_id1', ' campo_id2'];

En caso de querer ocultar algún campo cuando devolvemos la información por JSON de un modelo:

protected $hidden = ['campo_1', 'campo_2'];

En ocasiones querremos usar el campo created_at pero no necesitaremos updated_at, para ello podremos deshabilitarlo añadiendo la función:

public function setUpdatedAtAttribute($value)
{
}

O querremos usar un filtro específico sobre un modelo sin necesidad de hacer una consulta en la base de datos:

public function scopeEstado($query, $estado)
{
      return $query->where('estado', $estado);
}

Y podríamos usarlo de la siguiente forma:

$objeto->estado(‘activo’);

Esto sería lo mismo que aplicar un where pero se suele usar para no tener que meter llamadas a campos en el controlador:

$objeto->where(‘estado’, ‘activo’);

O si la consulta por la que se va a filtrar es algo más compleja (en este caso si filtramos por dos estados):

public function scopeInformes($query)
{
    return $query->where(function($query) {
       return $query->where('estado', 'En curso')
                    ->orWhere('estado', 'Finalizado');
    });
}

Trabajar con registros de un webform de Drupal 8

Cosas que se les ocurren a los clientes, una vez montado un formulario de contacto ahora me vienen con que lo quieren con validación del email por doble opt in. Hay módulos de Drupal ya pensados para ello pero la mayoría de los que he visto son para el registro de usuarios, no para un webform, por lo que al final me he puesto a montarlo a pelo. Básicamente es añadir un campo que llamo uuid con el código de validación y otro campo que indica si esta validado o no. Así cuando registramos al usuario en el formulario lo haría de esta forma:

$values = [
      'webform_id' => 'formulario_contacto',
      'in_draft' => FALSE,
      'uid' => '1',
      'langcode' => \Drupal::currentUser()->getPreferredLangcode(),
      'token' => 'pgmJREX2l4geg2RGFp0p78Qdfm1ksLxe6IlZ-mN9GZI',
      'uri' => '/webform/formulario_contacto/api',
      'remote_addr' => '',
      'data' => [
          'nombre'=>$form_state->getValue('nombre'),
          'apellidos'=>$form_state->getValue('apellidos'),
          'email'=>$form_state->getValue('email'),
          'validado'=>'No',
          'uuid'=>uniqid(explode('@', $form_state->getValue('email'))[0]),
      ],
    ];

Luego mandamos el email con el enlace a una página fija que creamos mediante el fichero routing.yml del modulo.


mi_modulo.contacto_validar:
  path: '/contactos/validar'
  defaults:
    _controller: '\Drupal\mi_modulo\ContactosController::validar'
    _title: 'Contactos'
  requirements:
    _permission: 'access content'

Y en el controlador ya podemos meter toda la lógica que queramos, por ejemplo comprobar si hay un registro con el uuid que llega por URL:


   $id = $request->query->get('id');
    $database = \Drupal::service('database');
    $select = $database->select('webform_submission_data', 'wsd')
                        ->fields('wsd', array('sid'))
                        ->condition('wsd.webform_id', 'formulario_contacto', '=')
                        ->condition('wsd.name', 'uuid', '=')
                        ->condition('wsd.value', $id, '=');
     $executed = $select->execute();
     $results = $executed->fetchAll(\PDO::FETCH_ASSOC);
     if (count($results) == 1) {
	// el identificador del registro 
       $sid = $results[0]['sid'];
    }

Luego si queremos recuperar los datos del registro:


$submission = \Drupal::entityTypeManager()->getStorage('webform_submission')->load($sid);
$data = $submission->getData();

O si directamente queremos actualizar el registro como validado:


$query = \Drupal::database()->merge('webform_submission_data');
       $query->key([
            'sid' => $sid,
            'name' => 'validado',
        ])->fields([
            'value' => 'Si',
        ]);
        $query->execute();