Skip to content

Commit

Permalink
Update Blameable for Phalcon 3.1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Jurigag committed May 23, 2017
1 parent 3f39a27 commit 9eef508
Show file tree
Hide file tree
Showing 12 changed files with 702 additions and 48 deletions.
158 changes: 116 additions & 42 deletions Library/Phalcon/Mvc/Model/Behavior/Blameable.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<?php

namespace Phalcon\Mvc\Model\Behavior;

use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Behavior;
use Phalcon\Mvc\Model\Behavior\Blameable\Audit;
use Phalcon\Mvc\Model\Behavior\Blameable\AuditDetail;
use Phalcon\Mvc\Model\Behavior\Blameable\AuditDetailInterface;
use Phalcon\Mvc\Model\Behavior\Blameable\AuditInterface;
use Phalcon\Mvc\Model\BehaviorInterface;
use Phalcon\Mvc\ModelInterface;

Expand All @@ -10,56 +16,104 @@
*/
class Blameable extends Behavior implements BehaviorInterface
{
/**
* @var array
*/
protected $snapshot;

/**
* @var array
*/
protected $changedFields;

/**
* @var string
*/
protected $auditClass = Audit::class;

/**
* @var string
*/
protected $auditDetailClass = AuditDetail::class;

/**
* @var callable
*/
protected $userCallback;

/**
* Blameable constructor.
* @param array|null $options
* @throws Exception
*/
public function __construct($options = null)
{
parent::__construct($options);
if (isset($options['auditClass'])) {
if (!in_array(AuditInterface::class, class_implements($options['auditClass']))) {
throw new Exception(
"Your class must implement Phalcon\\Mvc\\Model\\Behavior\\Blameable\\AuditInterface"
);
}
$this->auditClass = $options['auditClass'];
}

if (isset($options['auditDetailClass'])) {
if (!in_array(AuditDetailInterface::class, class_implements($options['auditDetailClass']))) {
throw new Exception(
"Your class must implement Phalcon\\Mvc\\Model\\Behavior\\Blameable\\AuditDetailInterface"
);
}
$this->auditDetailClass = $options['auditDetailClass'];
}

if (isset($options['userCallback'])) {
if (!is_callable($options['userCallback'])) {
throw new Exception("User callback must be callable!");
}
$this->userCallback = $options['userCallback'];
}
}

/**
* {@inheritdoc}
*
* @param string $eventType
* @param string $eventType
* @param \Phalcon\Mvc\ModelInterface $model
*/
public function notify($eventType, ModelInterface $model)
{
//Fires 'logAfterUpdate' if the event is 'afterCreate'
//Fires 'auditAfterCreate' if the event is 'afterCreate'
if ($eventType == 'afterCreate') {
return $this->auditAfterCreate($model);
}

//Fires 'logAfterUpdate' if the event is 'afterUpdate'
//Fires 'auditAfterUpdate' if the event is 'afterUpdate'
if ($eventType == 'afterUpdate') {
return $this->auditAfterUpdate($model);
}

// Fires 'collectData' if the event is 'beforeUpdate'
if ($eventType == 'beforeUpdate') {
return $this->collectData($model);
}
}

/**
* Creates an Audit isntance based on the current enviroment
*
* @param string $type
* @param string $type
* @param \Phalcon\Mvc\ModelInterface $model
* @return Audit
* @return AuditInterface
*/
public function createAudit($type, ModelInterface $model)
{
//Get the session service
$session = $model->getDI()->getSession();

//Get the request service
$request = $model->getDI()->getRequest();

$audit = new Audit();

//Get the username from session
$audit->user_name = $session->get('userName');

//The model who performed the action
$audit->model_name = get_class($model);

//The client IP address
$audit->ipaddress = $request->getClientAddress();

//Action is an update
$audit->type = $type;

//Current time
$audit->created_at = date('Y-m-d H:i:s');
$auditClass = $this->auditClass;
/** @var AuditInterface $audit */
$audit = new $auditClass();
$audit->setUserCallback($this->userCallback);
$audit->setModel($model);
$audit->setType($type);

return $audit;
}
Expand All @@ -72,17 +126,26 @@ public function createAudit($type, ModelInterface $model)
*/
public function auditAfterCreate(ModelInterface $model)
{
//Create a new audit
$audit = $this->createAudit('C', $model);
/** @var AuditInterface|ModelInterface $audit */
$audit = $this->createAudit('C', $model);
/** @var Model\MetaData $metaData */
$metaData = $model->getModelsMetaData();
$fields = $metaData->getAttributes($model);
$details = [];
$fields = $metaData->getAttributes($model);
$columnMap = $metaData->getColumnMap($model);
$details = [];
$auditDetailClass = $this->auditDetailClass;

foreach ($fields as $field) {
$auditDetail = new AuditDetail();
$auditDetail->field_name = $field;
$auditDetail->old_value = null;
$auditDetail->new_value = $model->readAttribute($field);
/** @var AuditDetailInterface $auditDetail */
$auditDetail = new $auditDetailClass();
$auditDetail->setOldValue(null);
if (empty($columnMap)) {
$auditDetail->setFieldName($field);
$auditDetail->setNewValue($model->readAttribute($field));
} else {
$auditDetail->setFieldName($columnMap[$field]);
$auditDetail->setNewValue($model->readAttribute($columnMap[$field]));
}

$details[] = $auditDetail;
}
Expand All @@ -100,24 +163,26 @@ public function auditAfterCreate(ModelInterface $model)
*/
public function auditAfterUpdate(ModelInterface $model)
{
$changedFields = $model->getChangedFields();
$changedFields = $this->changedFields;

if (count($changedFields) == 0) {
return null;
}

//Create a new audit
/** @var AuditInterface|ModelInterface $audit */
$audit = $this->createAudit('U', $model);

//Date the model had before modifications
$originalData = $model->getSnapshotData();
$originalData = $this->snapshot;
$auditDetailClass = $this->auditDetailClass;

$details = [];
foreach ($changedFields as $field) {
$auditDetail = new AuditDetail();
$auditDetail->field_name = $field;
$auditDetail->old_value = $originalData[$field];
$auditDetail->new_value = $model->readAttribute($field);
/** @var AuditDetailInterface $auditDetail */
$auditDetail = new $auditDetailClass();
$auditDetail->setFieldName($field);
$auditDetail->setOldValue($originalData[$field]);
$auditDetail->setNewValue($model->readAttribute($field));

$details[] = $auditDetail;
}
Expand All @@ -126,4 +191,13 @@ public function auditAfterUpdate(ModelInterface $model)

return $audit->save();
}

/**
* @param ModelInterface $model
*/
protected function collectData(ModelInterface $model)
{
$this->snapshot = $model->getSnapshotData();
$this->changedFields = $model->getChangedFields();
}
}
158 changes: 158 additions & 0 deletions Library/Phalcon/Mvc/Model/Behavior/Blameable/Audit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php

namespace Phalcon\Mvc\Model\Behavior\Blameable;

use Phalcon\Http\Request;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\ModelInterface;
use Phalcon\Session\Adapter;

/**
* Phalcon\Mvc\Model\Behavior\Blameable\Audit
*
* @package Phalcon\Mvc\Model\Behavior\Blameable
*/
class Audit extends Model implements AuditInterface
{
/**
* @var int
*/
public $id;

/**
* @var string
*/
public $user_name;

/**
* @var string
*/
public $model_name;

/**
* @var string
*/
public $ipaddress;

/**
* @var string
*/
public $type;

/**
* @var string
*/
public $created_at;

/**
* @var ModelInterface
*/
public $model;

/**
* @var array
*/
public $primary_key;

/**
* @var callable
*/
public $userCallback;

/**
* Sets relations between models
*/
public function initialize()
{
$this->hasMany('id', AuditDetail::class, 'audit_id', ['alias' => 'details']);
}

/**
* Executes code to set audits all needed data, like ipaddress, username, created_at etc
*/
public function beforeValidation()
{
if (empty($this->userCallback)) {
/** @var Adapter $session */
$session = $this->getDI()->get('session');

//Get the username from session
$this->user_name = $session->get('userName');
} else {
$userCallback = $this->userCallback;
$this->user_name = $userCallback($this->getDI());
}

//The model who performed the action
$this->model_name = get_class($this->model);

/** @var Request $request */
$request = $this->getDI()->get('request');

//The client IP address
$this->ipaddress = $request->getClientAddress();

//Current time
$this->created_at = date('Y-m-d H:i:s');

$primaryKeys = $this->getModelsMetaData()->getPrimaryKeyAttributes($this->model);

$columnMap = $this->getModelsMetaData()->getColumnMap($this->model);

$primaryValues = [];
if (!empty($columnMap)) {
foreach ($primaryKeys as $primaryKey) {
$primaryValues[] = $this->model->readAttribute($columnMap[$primaryKey]);
}
} else {
foreach ($primaryKeys as $primaryKey) {
$primaryValues[] = $this->model->readAttribute($primaryKey);
}
}

$this->primary_key = json_encode($primaryValues);
}

public function afterSave()
{
$this->primary_key = json_decode($this->primary_key, true);
}

public function afterFetch()
{
$this->primary_key = json_decode($this->primary_key, true);
}

/**
* @param ModelInterface $model
* @return $this
*/
public function setModel(ModelInterface $model)
{
$this->model = $model;

return $this;
}

/**
* @param string $type
* @return $this
*/
public function setType($type)
{
$this->type = $type;

return $this;
}

/**
* @param $userCallback
* @return $this
*/
public function setUserCallback($userCallback)
{
$this->userCallback = $userCallback;

return $this;
}
}
Loading

0 comments on commit 9eef508

Please sign in to comment.