Skip to content

Commit 9e82c7b

Browse files
Fixes #440
1 parent 2a674f1 commit 9e82c7b

File tree

4 files changed

+125
-109
lines changed

4 files changed

+125
-109
lines changed

phalcon/mvc/model.zep

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,15 +1777,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
17771777

17781778
/**
17791779
* Executes internal hooks before save a record
1780-
*
1781-
* @param Phalcon\Mvc\Model\MetadataInterface metaData
1782-
* @param boolean exists
1783-
* @param string identityField
1784-
* @return boolean
17851780
*/
17861781
protected function _preSave(<MetadataInterface> metaData, boolean exists, var identityField) -> boolean
17871782
{
1788-
var notNull, columnMap, dataTypeNumeric, automaticAttributes, defaultValues, field, attributeField, value;
1783+
var notNull, columnMap, dataTypeNumeric, automaticAttributes, defaultValues,
1784+
field, attributeField, value, emptyStringValues;
17891785
boolean error, isNull;
17901786

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

1851+
/**
1852+
* Get string attributes that allow empty strings as defaults
1853+
*/
1854+
let emptyStringValues = metaData->getEmptyStringAttributes(this);
1855+
18551856
let error = false;
18561857
for field in notNull {
18571858

@@ -1881,15 +1882,22 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
18811882
*/
18821883
if typeof value != "object" {
18831884
if !isset dataTypeNumeric[field] {
1884-
if value === null || value === "" {
1885-
let isNull = true;
1885+
if isset emptyStringValues[field] {
1886+
if value === null {
1887+
let isNull = true;
1888+
}
1889+
} else {
1890+
if value === null || value === "" {
1891+
let isNull = true;
1892+
}
18861893
}
18871894
} else {
18881895
if !is_numeric(value) {
18891896
let isNull = true;
18901897
}
18911898
}
18921899
}
1900+
18931901
} else {
18941902
let isNull = true;
18951903
}
@@ -2026,7 +2034,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
20262034
table, identityField) -> boolean
20272035
{
20282036
var bindSkip, fields, values, bindTypes, attributes, bindDataTypes, automaticAttributes,
2029-
field, columnMap, value, attributeField, success, bindType, defaultValue, sequenceName;
2037+
field, columnMap, value, attributeField, success, bindType,
2038+
defaultValue, sequenceName, defaultValues;
20302039
boolean useExplicitIdentity;
20312040

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

20382047
let attributes = metaData->getAttributes(this),
20392048
bindDataTypes = metaData->getBindTypes(this),
2040-
automaticAttributes = metaData->getAutomaticCreateAttributes(this);
2049+
automaticAttributes = metaData->getAutomaticCreateAttributes(this),
2050+
defaultValues = metaData->getDefaultValues(this);
20412051

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

2088+
if value === null && isset defaultValues[field] {
2089+
let value = defaultValues[field];
2090+
}
2091+
20782092
/**
20792093
* Every column must have a bind data type defined
20802094
*/
@@ -2084,7 +2098,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
20842098

20852099
let values[] = value, bindTypes[] = bindType;
20862100
} else {
2087-
let values[] = null, bindTypes[] = bindSkip;
2101+
2102+
let bindTypes[] = bindSkip;
2103+
2104+
fetch value, defaultValues[field];
2105+
let values[] = value;
20882106
}
20892107
}
20902108
}
@@ -3160,9 +3178,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
31603178
* <code>
31613179
* echo $robot->readAttribute('name');
31623180
* </code>
3163-
*
3164-
* @param string attribute
3165-
* @return mixed
31663181
*/
31673182
public function readAttribute(string! attribute)
31683183
{
@@ -3176,14 +3191,11 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
31763191
/**
31773192
* Writes an attribute value by its name
31783193
*
3179-
* <code>
3194+
*<code>
31803195
* $robot->writeAttribute('name', 'Rosey');
3181-
* </code>
3182-
*
3183-
* @param string attribute
3184-
* @param mixed value
3196+
*</code>
31853197
*/
3186-
public function writeAttribute(string! attribute, value)
3198+
public function writeAttribute(string! attribute, var value)
31873199
{
31883200
let this->{attribute} = value;
31893201
}
@@ -3202,7 +3214,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
32023214
* {
32033215
* $this->skipAttributes(array('price'));
32043216
* }
3205-
*
32063217
*}
32073218
*</code>
32083219
*/
@@ -3234,7 +3245,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
32343245
* {
32353246
* $this->skipAttributesOnCreate(array('created_at'));
32363247
* }
3237-
*
32383248
*}
32393249
*</code>
32403250
*/
@@ -3264,7 +3274,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
32643274
* {
32653275
* $this->skipAttributesOnUpdate(array('modified_in'));
32663276
* }
3267-
*
32683277
*}
32693278
*</code>
32703279
*/
@@ -3280,6 +3289,35 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
32803289
this->getModelsMetaData()->setAutomaticUpdateAttributes(this, keysAttributes);
32813290
}
32823291

3292+
/**
3293+
* Sets a list of attributes that must be skipped from the
3294+
* generated UPDATE statement
3295+
*
3296+
*<code>
3297+
*<?php
3298+
*
3299+
*class Robots extends \Phalcon\Mvc\Model
3300+
*{
3301+
*
3302+
* public function initialize()
3303+
* {
3304+
* $this->allowEmptyStringValues(array('name'));
3305+
* }
3306+
*}
3307+
*</code>
3308+
*/
3309+
protected function allowEmptyStringValues(array! attributes) -> void
3310+
{
3311+
var keysAttributes, attribute;
3312+
3313+
let keysAttributes = [];
3314+
for attribute in attributes {
3315+
let keysAttributes[attribute] = null;
3316+
}
3317+
3318+
this->getModelsMetaData()->setEmptyStringAttributes(this, keysAttributes);
3319+
}
3320+
32833321
/**
32843322
* Setup a 1-1 relation between two models
32853323
*
@@ -3293,15 +3331,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
32933331
* {
32943332
* $this->hasOne('id', 'RobotsDescription', 'robots_id');
32953333
* }
3296-
*
32973334
*}
32983335
*</code>
3299-
*
3300-
* @param mixed fields
3301-
* @param string referenceModel
3302-
* @param mixed referencedFields
3303-
* @param array options
3304-
* @return Phalcon\Mvc\Model\Relation
33053336
*/
33063337
protected function hasOne(var fields, string! referenceModel, var referencedFields, options = null) -> <Relation>
33073338
{
@@ -3324,12 +3355,6 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
33243355
*
33253356
*}
33263357
*</code>
3327-
*
3328-
* @param mixed fields
3329-
* @param string referenceModel
3330-
* @param mixed referencedFields
3331-
* @param array options
3332-
* @return Phalcon\Mvc\Model\Relation
33333358
*/
33343359
protected function belongsTo(var fields, string! referenceModel, var referencedFields, options = null) -> <Relation>
33353360
{
@@ -3349,15 +3374,8 @@ abstract class Model implements ModelInterface, ResultInterface, InjectionAwareI
33493374
* {
33503375
* $this->hasMany('id', 'RobotsParts', 'robots_id');
33513376
* }
3352-
*
33533377
*}
33543378
*</code>
3355-
*
3356-
* @param mixed fields
3357-
* @param string referenceModel
3358-
* @param mixed referencedFields
3359-
* @param array options
3360-
* @return Phalcon\Mvc\Model\Relation
33613379
*/
33623380
protected function hasMany(var fields, string! referenceModel, var referencedFields, options = null) -> <Relation>
33633381
{

phalcon/mvc/model/metadata.zep

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,14 @@ abstract class MetaData implements InjectionAwareInterface
7979

8080
const MODELS_DEFAULT_VALUES = 12;
8181

82+
const MODELS_EMPTY_STRING_VALUES = 13;
83+
8284
const MODELS_COLUMN_MAP = 0;
8385

8486
const MODELS_REVERSE_COLUMN_MAP = 1;
8587

8688
/**
8789
* Initialize the metadata for certain table
88-
*
89-
* @param Phalcon\Mvc\ModelInterface model
90-
* @param string|null key
91-
* @param string|null table
92-
* @param string|null schema
9390
*/
9491
protected final function _initialize(<ModelInterface> model, var key, var table, var schema)
9592
{
@@ -105,7 +102,7 @@ abstract class MetaData implements InjectionAwareInterface
105102
if !isset metaData[key] {
106103

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

126123
/**
127-
* Get the meta-data extraction strategy
128-
* Get the meta-data
124+
* Get the meta-data extraction strategy
129125
*/
130126
let dependencyInjector = this->_dependencyInjector,
131127
strategy = this->getStrategy(),
@@ -142,7 +138,6 @@ abstract class MetaData implements InjectionAwareInterface
142138
*/
143139
this->{"write"}(prefixKey, modelMetadata);
144140
}
145-
146141
}
147142
}
148143

@@ -235,9 +230,6 @@ abstract class MetaData implements InjectionAwareInterface
235230
*<code>
236231
* print_r($metaData->readMetaData(new Robots());
237232
*</code>
238-
*
239-
* @param Phalcon\Mvc\ModelInterface model
240-
* @return array
241233
*/
242234
public final function readMetaData(<ModelInterface> model)
243235
{
@@ -263,10 +255,6 @@ abstract class MetaData implements InjectionAwareInterface
263255
*<code>
264256
* print_r($metaData->readMetaDataIndex(new Robots(), 0);
265257
*</code>
266-
*
267-
* @param Phalcon\Mvc\ModelInterface model
268-
* @param int index
269-
* @return mixed
270258
*/
271259
public final function readMetaDataIndex(<ModelInterface> model, int index)
272260
{
@@ -294,14 +282,10 @@ abstract class MetaData implements InjectionAwareInterface
294282
*<code>
295283
* print_r($metaData->writeColumnMapIndex(new Robots(), MetaData::MODELS_REVERSE_COLUMN_MAP, array('leName' => 'name')));
296284
*</code>
297-
*
298-
* @param Phalcon\Mvc\ModelInterface model
299-
* @param int index
300-
* @param mixed data
301285
*/
302286
public final function writeMetaDataIndex(<ModelInterface> model, int index, var data) -> void
303287
{
304-
var source, schema, key;
288+
var metaData, source, schema, key;
305289

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

322-
let this->_metaData[key][index] = data;
306+
let metaData = this->_metaData,
307+
metaData[key][index] = data,
308+
this->_metaData = metaData;
323309
}
324310

325311
/**
@@ -328,9 +314,6 @@ abstract class MetaData implements InjectionAwareInterface
328314
*<code>
329315
* print_r($metaData->readColumnMap(new Robots()));
330316
*</code>
331-
*
332-
* @param Phalcon\Mvc\ModelInterface model
333-
* @return array
334317
*/
335318
public final function readColumnMap(<ModelInterface> model)
336319
{
@@ -550,11 +533,8 @@ abstract class MetaData implements InjectionAwareInterface
550533
*<code>
551534
* $metaData->setAutomaticCreateAttributes(new Robots(), array('created_at' => true));
552535
*</code>
553-
*
554-
* @param Phalcon\Mvc\ModelInterface model
555-
* @param array attributes
556536
*/
557-
public function setAutomaticCreateAttributes(<ModelInterface> model, attributes) -> void
537+
public function setAutomaticCreateAttributes(<ModelInterface> model, array attributes) -> void
558538
{
559539
this->writeMetaDataIndex(model, self::MODELS_AUTOMATIC_DEFAULT_INSERT, attributes);
560540
}
@@ -565,15 +545,41 @@ abstract class MetaData implements InjectionAwareInterface
565545
*<code>
566546
* $metaData->setAutomaticUpdateAttributes(new Robots(), array('modified_at' => true));
567547
*</code>
568-
*
569-
* @param Phalcon\Mvc\ModelInterface model
570-
* @param array attributes
571548
*/
572-
public function setAutomaticUpdateAttributes(<ModelInterface> model, attributes) -> void
549+
public function setAutomaticUpdateAttributes(<ModelInterface> model, array attributes) -> void
573550
{
574551
this->writeMetaDataIndex(model, self::MODELS_AUTOMATIC_DEFAULT_UPDATE, attributes);
575552
}
576553

554+
/**
555+
* Set the attributes that allow empty string values
556+
*
557+
*<code>
558+
* $metaData->setEmptyStringAttributes(new Robots(), array('name' => true));
559+
*</code>
560+
*/
561+
public function setEmptyStringAttributes(<ModelInterface> model, array attributes) -> void
562+
{
563+
this->writeMetaDataIndex(model, self::MODELS_EMPTY_STRING_VALUES, attributes);
564+
}
565+
566+
/**
567+
* Returns attributes allow empty strings
568+
*
569+
*<code>
570+
* print_r($metaData->getEmptyStringAttributes(new Robots()));
571+
*</code>
572+
*/
573+
public function getEmptyStringAttributes(<ModelInterface> model) -> array
574+
{
575+
var data;
576+
let data = this->readMetaDataIndex(model, self::MODELS_EMPTY_STRING_VALUES);
577+
if typeof data != "array" {
578+
throw new Exception("The meta-data is invalid or is corrupt");
579+
}
580+
return data;
581+
}
582+
577583
/**
578584
* Returns attributes (which have default values) and their default values
579585
*

0 commit comments

Comments
 (0)