考虑到我有几个模型使用MySQL的位字段存储一些标志。 我知道通过以下方式很容易将其转换为bool:
$myBoolFlag = (ord($model->myFlag) == 1) ? true : false;
我正在寻找一些方法让它自动映射到布尔属性。
有人告诉我,有一种比为项目中的每个位字段创建setter和getter更好的方法。我敢打赌,Phalcon在数据库服务中有一些神奇的配置或类似的东西......
答案 0 :(得分:1)
我处理类似问题的方法是在每个模型中创建地图数组并使用它们。更具体地说:
<?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;
}
}
示例User
模型看起来像这样
<?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();
}
}
答案 1 :(得分:0)
我最终遵循Nikolao的方法并为我的模型实现了一个基类,它可以将位字段解析为更实用的值。但是,我设计它不会覆盖默认的映射行为。这样的事情:
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;
}
}
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();
}
}