Τετάρτη 11 Ιουλίου 2018

[Laravel Hack] venturecraft/revisionable to include details

As a backend development, you might have been asked to keep a history of changes. A very good library that does so in Laravel, with minimum configuration, is the venturecraft/revisionable. A limitation of this library is that it is limited to whatever is stored in the table that is related to each model. 

There are several situations that this is not enough. For instance, you might have a Model "PriceTable" that is related to many "ServiceTypePrice" where "ServiceTypePrice" is stored in a separate table and they have a One-to-Many relationship.

My simplest solution was to convert define the relationship in the model class using "hasMany" and also create a function that converts the data of hasMany into a readable string. So I override method preSave that Revisionable uses, in order to include the result of getDetails() as if it is was a actual attribute of the table "PriceTable".

It should be noted that I have decided this solution since I have pretty small number of entries in the table "ServieTypePrice" for each "PriceTable", otherwise I would select a more sophisticated solution that I have already though of but I might test and document in a future post!

preSave code included in my "PriceTable" Model class is the following:
 
use \Venturecraft\Revisionable\RevisionableTrait; 
public function preSave() {
        if (!isset($this->revisionEnabled) || $this->revisionEnabled) {
            // if there's no revisionEnabled. Or if there is, if it's true
            $this->originalData = $this->original;
            $this->updatedData = $this->attributes;

            /**
             * Append details
             */
            if ($this->originalData) {
                $originalModel = static::find($this->originalData["id"]);
                $this->originalData["details"] = $originalModel->getDetails();
            }
            $this->updatedData["details"] = $this->getDetails();

            // we can only safely compare basic items,
            // so for now we drop any object based items, like DateTime
            foreach ($this->updatedData as $key => $val) {
                if (gettype($val) == 'object' && !method_exists($val, '__toString')) {
                    unset($this->originalData[$key]);
                    unset($this->updatedData[$key]);
                    array_push($this->dontKeep, $key);
                }
            }
            // the below is ugly, for sure, but it's required so we can save the standard model
            // then use the keep / dontkeep values for later, in the isRevisionable method
            $this->dontKeep = isset($this->dontKeepRevisionOf) ?
                array_merge($this->dontKeepRevisionOf, $this->dontKeep) : $this->dontKeep;
            $this->doKeep = isset($this->keepRevisionOf) ?
                array_merge($this->keepRevisionOf, $this->doKeep) : $this->doKeep;
            unset($this->attributes['dontKeepRevisionOf']);
            unset($this->attributes['keepRevisionOf']);
            $this->dirtyData = $this->getDirty();
            /**
             * Check Details
             */
            if ($this->originalData == NULL || strcmp((string) $this->updatedData["details"], (string) $this->originalData["details"]) !== 0) {
                $this->dirtyData["details"] = $this->updatedData["details"];
            }
            $this->updating = $this->exists;
        }
    }

LinkWithin

Blog Widget by LinkWithin

Mobile edition