Skip to content

Commit

Permalink
Fixes #440
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgutierrez committed May 31, 2015
1 parent 2a674f1 commit 9e82c7b
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 109 deletions.
104 changes: 61 additions & 43 deletions phalcon/mvc/model.zep
Original file line number Diff line number Diff line change
Expand Up @@ -1777,15 +1777,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI

/**
* Executes internal hooks before save a record
*
* @param Phalcon\Mvc\Model\MetadataInterface metaData
* @param boolean exists
* @param string identityField
* @return boolean
*/
protected function _preSave(<MetadataInterface> metaData, boolean exists, var identityField) -> boolean
{
var notNull, columnMap, dataTypeNumeric, automaticAttributes, defaultValues, field, attributeField, value;
var notNull, columnMap, dataTypeNumeric, automaticAttributes, defaultValues,
field, attributeField, value, emptyStringValues;
boolean error, isNull;

/**
Expand Down Expand Up @@ -1852,6 +1848,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
let defaultValues = metaData->getDefaultValues(this);
}

/**
* Get string attributes that allow empty strings as defaults
*/
let emptyStringValues = metaData->getEmptyStringAttributes(this);

let error = false;
for field in notNull {

Expand Down Expand Up @@ -1881,15 +1882,22 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
*/
if typeof value != "object" {
if !isset dataTypeNumeric[field] {
if value === null || value === "" {
let isNull = true;
if isset emptyStringValues[field] {
if value === null {
let isNull = true;
}
} else {
if value === null || value === "" {
let isNull = true;
}
}
} else {
if !is_numeric(value) {
let isNull = true;
}
}
}

} else {
let isNull = true;
}
Expand Down Expand Up @@ -2026,7 +2034,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
table, identityField) -> boolean
{
var bindSkip, fields, values, bindTypes, attributes, bindDataTypes, automaticAttributes,
field, columnMap, value, attributeField, success, bindType, defaultValue, sequenceName;
field, columnMap, value, attributeField, success, bindType,
defaultValue, sequenceName, defaultValues;
boolean useExplicitIdentity;

let bindSkip = Column::BIND_SKIP;
Expand All @@ -2037,7 +2046,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI

let attributes = metaData->getAttributes(this),
bindDataTypes = metaData->getBindTypes(this),
automaticAttributes = metaData->getAutomaticCreateAttributes(this);
automaticAttributes = metaData->getAutomaticCreateAttributes(this),
defaultValues = metaData->getDefaultValues(this);

if globals_get("orm.column_renaming") {
let columnMap = metaData->getColumnMap(this);
Expand Down Expand Up @@ -2075,6 +2085,10 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
*/
if fetch value, this->{attributeField} {

if value === null && isset defaultValues[field] {
let value = defaultValues[field];
}

/**
* Every column must have a bind data type defined
*/
Expand All @@ -2084,7 +2098,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI

let values[] = value, bindTypes[] = bindType;
} else {
let values[] = null, bindTypes[] = bindSkip;

let bindTypes[] = bindSkip;

fetch value, defaultValues[field];
let values[] = value;
}
}
}
Expand Down Expand Up @@ -3160,9 +3178,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
* <code>
* echo $robot->readAttribute('name');
* </code>
*
* @param string attribute
* @return mixed
*/
public function readAttribute(string! attribute)
{
Expand All @@ -3176,14 +3191,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
/**
* Writes an attribute value by its name
*
* <code>
*<code>
* $robot->writeAttribute('name', 'Rosey');
* </code>
*
* @param string attribute
* @param mixed value
*</code>
*/
public function writeAttribute(string! attribute, value)
public function writeAttribute(string! attribute, var value)
{
let this->{attribute} = value;
}
Expand All @@ -3202,7 +3214,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
* {
* $this->skipAttributes(array('price'));
* }
*
*}
*</code>
*/
Expand Down Expand Up @@ -3234,7 +3245,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
* {
* $this->skipAttributesOnCreate(array('created_at'));
* }
*
*}
*</code>
*/
Expand Down Expand Up @@ -3264,7 +3274,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
* {
* $this->skipAttributesOnUpdate(array('modified_in'));
* }
*
*}
*</code>
*/
Expand All @@ -3280,6 +3289,35 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
this->getModelsMetaData()->setAutomaticUpdateAttributes(this, keysAttributes);
}

/**
* Sets a list of attributes that must be skipped from the
* generated UPDATE statement
*
*<code>
*<?php
*
*class Robots extends \Phalcon\Mvc\Model
*{
*
* public function initialize()
* {
* $this->allowEmptyStringValues(array('name'));
* }
*}
*</code>
*/
protected function allowEmptyStringValues(array! attributes) -> void
{
var keysAttributes, attribute;

let keysAttributes = [];
for attribute in attributes {
let keysAttributes[attribute] = null;
}

this->getModelsMetaData()->setEmptyStringAttributes(this, keysAttributes);
}

/**
* Setup a 1-1 relation between two models
*
Expand All @@ -3293,15 +3331,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
* {
* $this->hasOne('id', 'RobotsDescription', 'robots_id');
* }
*
*}
*</code>
*
* @param mixed fields
* @param string referenceModel
* @param mixed referencedFields
* @param array options
* @return Phalcon\Mvc\Model\Relation
*/
protected function hasOne(var fields, string! referenceModel, var referencedFields, options = null) -> <Relation>
{
Expand All @@ -3324,12 +3355,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
*
*}
*</code>
*
* @param mixed fields
* @param string referenceModel
* @param mixed referencedFields
* @param array options
* @return Phalcon\Mvc\Model\Relation
*/
protected function belongsTo(var fields, string! referenceModel, var referencedFields, options = null) -> <Relation>
{
Expand All @@ -3349,15 +3374,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
* {
* $this->hasMany('id', 'RobotsParts', 'robots_id');
* }
*
*}
*</code>
*
* @param mixed fields
* @param string referenceModel
* @param mixed referencedFields
* @param array options
* @return Phalcon\Mvc\Model\Relation
*/
protected function hasMany(var fields, string! referenceModel, var referencedFields, options = null) -> <Relation>
{
Expand Down
72 changes: 39 additions & 33 deletions phalcon/mvc/model/metadata.zep
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,14 @@ abstract class MetaData implements InjectionAwareInterface

const MODELS_DEFAULT_VALUES = 12;

const MODELS_EMPTY_STRING_VALUES = 13;

const MODELS_COLUMN_MAP = 0;

const MODELS_REVERSE_COLUMN_MAP = 1;

/**
* Initialize the metadata for certain table
*
* @param Phalcon\Mvc\ModelInterface model
* @param string|null key
* @param string|null table
* @param string|null schema
*/
protected final function _initialize(<ModelInterface> model, var key, var table, var schema)
{
Expand All @@ -105,7 +102,7 @@ abstract class MetaData implements InjectionAwareInterface
if !isset metaData[key] {

/**
* The meta-data is read from the adapter always
* The meta-data is read from the adapter always if not available in _metaData property
*/
let prefixKey = "meta-" . key,
data = this->{"read"}(prefixKey);
Expand All @@ -124,8 +121,7 @@ abstract class MetaData implements InjectionAwareInterface
} else {

/**
* Get the meta-data extraction strategy
* Get the meta-data
* Get the meta-data extraction strategy
*/
let dependencyInjector = this->_dependencyInjector,
strategy = this->getStrategy(),
Expand All @@ -142,7 +138,6 @@ abstract class MetaData implements InjectionAwareInterface
*/
this->{"write"}(prefixKey, modelMetadata);
}

}
}

Expand Down Expand Up @@ -235,9 +230,6 @@ abstract class MetaData implements InjectionAwareInterface
*<code>
* print_r($metaData->readMetaData(new Robots());
*</code>
*
* @param Phalcon\Mvc\ModelInterface model
* @return array
*/
public final function readMetaData(<ModelInterface> model)
{
Expand All @@ -263,10 +255,6 @@ abstract class MetaData implements InjectionAwareInterface
*<code>
* print_r($metaData->readMetaDataIndex(new Robots(), 0);
*</code>
*
* @param Phalcon\Mvc\ModelInterface model
* @param int index
* @return mixed
*/
public final function readMetaDataIndex(<ModelInterface> model, int index)
{
Expand Down Expand Up @@ -294,14 +282,10 @@ abstract class MetaData implements InjectionAwareInterface
*<code>
* print_r($metaData->writeColumnMapIndex(new Robots(), MetaData::MODELS_REVERSE_COLUMN_MAP, array('leName' => 'name')));
*</code>
*
* @param Phalcon\Mvc\ModelInterface model
* @param int index
* @param mixed data
*/
public final function writeMetaDataIndex(<ModelInterface> model, int index, var data) -> void
{
var source, schema, key;
var metaData, source, schema, key;

if typeof data != "array" && typeof data != "string" && typeof data != "boolean" {
throw new Exception("Invalid data for index");
Expand All @@ -319,7 +303,9 @@ abstract class MetaData implements InjectionAwareInterface
this->_initialize(model, key, source, schema);
}

let this->_metaData[key][index] = data;
let metaData = this->_metaData,
metaData[key][index] = data,
this->_metaData = metaData;
}

/**
Expand All @@ -328,9 +314,6 @@ abstract class MetaData implements InjectionAwareInterface
*<code>
* print_r($metaData->readColumnMap(new Robots()));
*</code>
*
* @param Phalcon\Mvc\ModelInterface model
* @return array
*/
public final function readColumnMap(<ModelInterface> model)
{
Expand Down Expand Up @@ -550,11 +533,8 @@ abstract class MetaData implements InjectionAwareInterface
*<code>
* $metaData->setAutomaticCreateAttributes(new Robots(), array('created_at' => true));
*</code>
*
* @param Phalcon\Mvc\ModelInterface model
* @param array attributes
*/
public function setAutomaticCreateAttributes(<ModelInterface> model, attributes) -> void
public function setAutomaticCreateAttributes(<ModelInterface> model, array attributes) -> void
{
this->writeMetaDataIndex(model, self::MODELS_AUTOMATIC_DEFAULT_INSERT, attributes);
}
Expand All @@ -565,15 +545,41 @@ abstract class MetaData implements InjectionAwareInterface
*<code>
* $metaData->setAutomaticUpdateAttributes(new Robots(), array('modified_at' => true));
*</code>
*
* @param Phalcon\Mvc\ModelInterface model
* @param array attributes
*/
public function setAutomaticUpdateAttributes(<ModelInterface> model, attributes) -> void
public function setAutomaticUpdateAttributes(<ModelInterface> model, array attributes) -> void
{
this->writeMetaDataIndex(model, self::MODELS_AUTOMATIC_DEFAULT_UPDATE, attributes);
}

/**
* Set the attributes that allow empty string values
*
*<code>
* $metaData->setEmptyStringAttributes(new Robots(), array('name' => true));
*</code>
*/
public function setEmptyStringAttributes(<ModelInterface> model, array attributes) -> void
{
this->writeMetaDataIndex(model, self::MODELS_EMPTY_STRING_VALUES, attributes);
}

/**
* Returns attributes allow empty strings
*
*<code>
* print_r($metaData->getEmptyStringAttributes(new Robots()));
*</code>
*/
public function getEmptyStringAttributes(<ModelInterface> model) -> array
{
var data;
let data = this->readMetaDataIndex(model, self::MODELS_EMPTY_STRING_VALUES);
if typeof data != "array" {
throw new Exception("The meta-data is invalid or is corrupt");
}
return data;
}

/**
* Returns attributes (which have default values) and their default values
*
Expand Down
Loading

0 comments on commit 9e82c7b

Please sign in to comment.