Pregunta

Consider that I got several models that store some flags using MySQL's bit field. I know that it can easily be converted into bool by doing the follow:

$myBoolFlag = (ord($model->myFlag) == 1) ? true : false;

I'm looking for some way to make it map to a boolean property automatically.

Please someone tell me that there is an better way than creating setters and getters for every bit field in my project. I bet that Phalcon has some magic configuration in the DB service or something like this...

¿Fue útil?

Solución 2

I've ended up by following the Nikolao's approach and implemented a base class for my models that can parse bit fields into more practical values. However, I designed it to not override the default mapping behavior. Something like that:

abstract class BaseModel extends Phalcon\Mvc\Model
{
    public function explicitDataTypes()
    {
        //TODO: Suport relational data
        $numargs = func_num_args();

        if($numargs)
        {
            foreach (func_get_args() as $arg)
            {
                if(isset($this->$arg)) $this->$arg = $this->explicitDataType($arg)
            }
        }
        else
        {
            foreach (get_object_vars($this) as $key => $value)
            {
                if($key[0] != '_') $this->$key = $this->explicitDataType($key)
            }
        }
    }

    public function explicitDataType($propertyName)
    {
        $value = $this->$propertyName;

        if(is_numeric($value))
        {   
            $locale = localeconv();
            $separatorCount = substr_count($value, $locale['decimal_point']);

            if($separatorCount == 0) $value = (int)$value;
            elseif($separatorCount == 1) $value = (float)$value;
        }
        elseif(strlen($value) == 1 && ord($value) <= 1) $value = ord($value) == 1;

        return $value;
    }
}

Examples

class User extends BaseModel
{
    protected $password;

    public function afterFetch()
    {
        //Explicit data type for specific fields (e.g. var_dump($user->activated); //bool(true))
        $this->explicitDataTypes('activated', 'deleted');
    }
}

class Location extends BaseModel
{
    public function afterFetch()
    {
        //Explicit data type for specific all fields (e.g. var_dump($location->distance); //float(12.3)
        $this->explicitDataTypes();
    }
}

Otros consejos

The way I have dealt with a similar issue is to create map arrays in each model and work with those. More specifically:

<?php
/**
 * Model.php
 *
 * Model
 *
 * @author      Nikos Dimopoulos <nikos@niden.net>
 * @since       2012-12-12
 * @category    Library
 *
 */

namespace NDN;

use \Phalcon\DI\FactoryDefault as PhDi;
use \Phalcon\Mvc\Model as PhModel;

class Model extends PhModel
{
    private $meta = [];

    /**
     * Some init stuff
     */
    public function initialize()
    {

        // Disable literals
        $this->setup(['phqlLiterals' => false]);
    }

    /**
     * Universal method caller. This checks the available methods based on
     * the fields in the meta array and returns the relevant results
     *
     * @author  Nikos Dimopoulos <nikos@niden.net>
     * @since   2015-02-15
     *
     * @param   string      $function
     * @param   array|null  $arguments
     *
     * @return  mixed|void
     * @throws  \Exception
     */
    public function __call($function, $arguments = null)
    {
        // $function is something like getId, setId, getName etc.
        $metaFunction = substr($function, 3);
        $field        = $this->getMetaFunctionToField($metaFunction);

        if ($field) {

            $prefix    = substr($function, 0, 3);
            $fieldName = $field['field'];

            switch ($prefix) {
                case 'get':

                    /**
                     * Data manipulation here if needed
                     */
                    $value = $this->getField($fieldName);
                    $value = $this->metaFieldValidate($field, $value);

                    return $value;
                    break;

                case 'set':

                    /**
                     * Data manipulation here
                     */
                    $value = $this->metaFieldValidate($field, $arguments);

                    $this->setField($field, $value);
                    break;
            }

        } else {
            throw new \Exception('Function does not exist');
        }
    }

    /**
     * -------------------------------------------------------------------------
     * PROTECTED METHODS
     * -------------------------------------------------------------------------
     */

    /**
     * Gets a field from the model with the correct prefix
     *
     * @param $name
     *
     * @return mixed
     */
    protected function getField($name)
    {
        return $this->$name;

    }

    /**
     * Sets a field in the model
     *
     * @author  Nikos Dimopoulos <nikos@niden.net>
     * @since   2014-02-15
     *
     * @param   string  $field
     * @param   mixed   $value
     */
    protected function setField($field, $value)
    {
        $this->$field = $value;
    }

    /**
     * Returns the DI container
     *
     * @author  Nikos Dimopoulos <nikos@niden.net>
     * @since   2014-02-22
     *
     * @return  mixed
     */
    public function getDI()
    {
        return PhDi::getDefault();
    }

    /**
     * Accesses the internal array map to provide the field name from a function
     *
     * @author  Nikos Dimopoulos <nikos@niden.net>
     * @since   2014-02-27
     *
     * @param   string  $prefix     The prefix of the table
     * @param   string  $function   The aliased function
     *
     * @return  string  The field name (i.e. tnt_id)
     *          bool    False if not found
     */
    public function getMetaFunctionToField($function)
    {
        if (array_key_exists($function, $this->meta)) {
            return $this->meta[$function];
        }

        return false;
    }

    /**
     * Validates a setter value based on each field's type
     *
     * @author  Nikos Dimopoulos <nikos@niden.net>
     * @since   2014-02-17
     *
     * @param   string  $field  The field to check
     * @param   mixed   $value  The value of the field
     *
     * @return bool|int|string
     */
    protected function metaFieldValidate($field, $value)
    {
        // Find the validator
        $validator = $field['validator'];

        switch ($validator)
        {
            case 'int':
                $return = intval($value);
                break;
            case 'bit':
                $return = (ord($value) == 1) ? true : false;
                break;
            case 'bool':
                $return = (bool) $value;
                break;
            case 'decimal':
                $return = (float) $value;
                break;
            case 'string':
                $return = (string) $value;
                break;
            case 'datetime':
                /**
                 * @todo check datetime validator
                 */
                $return = (string) $value;
                break;
            default:
                $return = $value;
                break;
        }

        return $return;
    }

}

A sample User model looks like this

<?php
/**
 * User.php
 *
 * User
 *
 * @author      Nikos Dimopoulos <nikos@niden.net>
 * @since       2014-03-08
 * @category    Models
 *
 */

namespace NDN;

use \NDN\Model as NDNModel;

class Model extends NDNModel
{
    public function initialize()
    {
        /**
         * This is where I will set the field map
         * 
         * The key of the array is the function name without 
         * the prefix. So for instance if you want getName()
         * to return the user.name you use Name as the key
         */
        $this->data = [
            'Id' => [
                'field'     => 'user_id',
                'validator' => 'int',
            ],
            'Name' => [
                'field'     => 'user_name',
                'validator' => 'int',
            ],
            'IsMarried' => [
                'field'     => 'user_is_married',
                'validator' => 'bit',
            ]
        ];

        parent::initialize();
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top