Hello,
I have implemented a meta cache for my modesl based on the tutorial-models-init example here
I have now:
<?php
use Phalcon\Mvc\ModelInterface,
Phalcon\DiInterface,
Phalcon\Mvc\Model\MetaData,
Phalcon\Db\Column;
class MetaDataInitializer
{
/**
* Initializes the model's meta-data
*
* @param Phalcon\Mvc\ModelInterface $model
* @param Phalcon\DiInterface $di
* @return array
*/
public function getMetaData(ModelInterface $model, DiInterface $di)
{
$reflection = $di['annotations']->get($model);
$properties = $reflection->getPropertiesAnnotations();
if (!$properties)
{
throw new Exception("There are no properties defined on the class");
}
$attributes = array();
$nullables = array();
$dataTypes = array();
$dataTypesBind = array();
$numericTypes = array();
$primaryKeys = array();
$nonPrimaryKeys = array();
$identity = false;
foreach ($properties as $name => $collection)
{
if ($collection->has('Column')) {
$arguments = $collection->get('Column')->getArguments();
/**
* Get the column's name
*/
if (isset($arguments['column']))
{
$columnName = $arguments['column'];
}
else {
$columnName = $name;
}
/**
* Check for the 'type' parameter in the 'Column' annotation
*/
if (isset($arguments['type']))
{
switch ($arguments['type'])
{
case 'integer':
$dataTypes[$columnName] = Column::TYPE_INTEGER;
$dataTypesBind[$columnName] = Column::BIND_PARAM_INT;
$numericTypes[$columnName] = true;
break;
case 'string':
$dataTypes[$columnName] = Column::TYPE_VARCHAR;
$dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
break;
case 'text':
$dataTypes[$columnName] = Column::TYPE_TEXT;
$dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
break;
case 'decimal':
$dataTypes[$columnName] = Column::TYPE_DECIMAL;
$dataTypesBind[$columnName] = Column::BIND_PARAM_DECIMAL;
break;
case 'enum':
$dataTypes[$columnName] = Column::TYPE_VARCHAR;
$dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
break;
case 'boolean':
$dataTypes[$columnName] = Column::TYPE_BOOLEAN;
$dataTypesBind[$columnName] = Column::BIND_PARAM_BOOL;
break;
case 'date':
$dataTypes[$columnName] = Column::TYPE_DATE;
$dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
break;
case 'datetime':
$dataTypes[$columnName] = Column::TYPE_DATETIME;
$dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
break;
}
}
else
{
$dataTypes[$columnName] = Column::TYPE_VARCHAR;
$dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
}
/**
* Check for the 'nullable' parameter in the 'Column' annotation
*/
if (!$collection->has('Identity'))
{
if (isset($arguments['nullable']))
{
if (!$arguments['nullable'])
{
$nullables[] = $columnName;
}
}
}
$attributes[] = $columnName;
/**
* Check if the attribute is marked as primary
*/
if ($collection->has('Primary'))
{
$primaryKeys[] = $columnName;
}
else
{
$nonPrimaryKeys[] = $columnName;
}
/**
* Check if the attribute is marked as identity
*/
if ($collection->has('Identity')) {
$identity = $columnName;
}
}
}
return array(
//Every column in the mapped table
MetaData::MODELS_ATTRIBUTES => $attributes,
//Every column part of the primary key
MetaData::MODELS_PRIMARY_KEY => $primaryKeys,
//Every column that isn't part of the primary key
MetaData::MODELS_NON_PRIMARY_KEY => $nonPrimaryKeys,
//Every column that doesn't allows null values
MetaData::MODELS_NOT_NULL => $nullables,
//Every column and their data types
MetaData::MODELS_DATA_TYPES => $dataTypes,
//The columns that have numeric data types
MetaData::MODELS_DATA_TYPES_NUMERIC => $numericTypes,
//The identity column, use boolean false if the model doesn't have
//an identity column
MetaData::MODELS_IDENTITY_COLUMN => $identity,
//How every column must be bound/casted
MetaData::MODELS_DATA_TYPES_BIND => $dataTypesBind,
//Fields that must be ignored from INSERT SQL statements
MetaData::MODELS_AUTOMATIC_DEFAULT_INSERT => array(),
//Fields that must be ignored from UPDATE SQL statements
MetaData::MODELS_AUTOMATIC_DEFAULT_UPDATE => array()
);
}
/**
* Initializes the model's column map
*
* @param Phalcon\Mvc\ModelInterface $model
* @param Phalcon\DiInterface $di
* @return array
*/
public function getColumnMaps(ModelInterface $model, DiInterface $di)
{
$reflection = $di['annotations']->get($model);
$columnMap = array();
$reverseColumnMap = array();
$renamed = false;
foreach ($reflection->getPropertiesAnnotations() as $name => $collection)
{
if ($collection->has('Column')) {
$arguments = $collection->get('Column')->getArguments();
/**
* Get the column's name
*/
if (isset($arguments['column']))
{
$columnName = $arguments['column'];
}
else
{
$columnName = $name;
}
$columnMap[$columnName] = $name;
$reverseColumnMap[$name] = $columnName;
if (!$renamed)
{
if ($columnName != $name)
{
$renamed = true;
}
}
}
}
if ($renamed)
{
return array(
MetaData::MODELS_COLUMN_MAP => $columnMap,
MetaData::MODELS_REVERSE_COLUMN_MAP => $reverseColumnMap
);
}
return null;
}
}
and
<?php
use Phalcon\Events\Event,
Phalcon\Mvc\Model\Manager as ModelsManager;
class AnnotationsInitializer extends Phalcon\Mvc\User\Plugin
{
/**
* This is called after initialize the model
*
* @param Phalcon\Events\Event $event
*/
public function afterInitialize(Event $event, ModelsManager $manager, $model)
{
$reflector = $this->annotations->get($model);
$annotations = $reflector->getClassAnnotations();
if ($annotations)
{
foreach ($annotations as $annotation)
{
switch ($annotation->getName())
{
case 'Source':
$arguments = $annotation->getArguments();
$manager->setModelSource($model, $arguments[0]);
break;
case 'hasOne':
$arguments = $annotation->getArguments();
if (isset($arguments[3]))
{
$manager->addHasOne($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3]);
}
else
{
$manager->addHasOne($model, $arguments[0], $arguments[1], $arguments[2]);
}
break;
case 'hasMany':
$arguments = $annotation->getArguments();
if (isset($arguments[3]))
{
$manager->addHasMany($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3]);
}
else
{
$manager->addHasMany($model, $arguments[0], $arguments[1], $arguments[2]);
}
break;
case 'hasManyToMany':
$arguments = $annotation->getArguments();
if (isset($arguments[6]))
{
$manager->addHasManyToMany($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]);
}
else
{
$manager->addHasManyToMany($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]);
}
break;
case 'belongsTo':
$arguments = $annotation->getArguments();
if (isset($arguments[3]))
{
$manager->addBelongsTo($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3]);
}
else
{
$manager->addBelongsTo($model, $arguments[0], $arguments[1], $arguments[2]);
}
break;
}
}
}
}
}
I have a model like this:
<?php
/**
* Articles
*
* Model Articles
*
* @Source('articles');
* @useDynamicUpdate(true);
* @belongsTo('publishid','Users','id', {'alias': 'publisher'});
* @hasOne('iconid','Images','id', {'alias': 'icon'});
*/
class Articles extends \Phalcon\Mvc\Model
{
/**
* @Primary
* @Identity
* @Column(type="integer", nullable=false, column="id", size="11")
*/
public $id;
/**
* @Column(type="string", nullable=false, column="languagekey", size="3")
*/
public $languagekey;
/**
* @Column(type="integer", nullable=false, column="iconid", size="11")
*/
public $iconid;
/**
* @Column(type="integer", nullable=false, column="publishid")
*/
public $publishid;
/**
* @Column(type="string", nullable=false, column="pagetitle", size="100")
*/
public $pagetitle;
/**
* @Column(type="string", nullable=false, column="listtitle", size="100")
*/
public $listtitle;
/**
* @Column(type="string", nullable=false, column="listdescription", size="250")
*/
public $listdescription;
/**
* @Column(type="text", nullable=false, column="content")
*/
public $content;
}
The cache works perfect. There are files written, but the hasOne relations does not work. when I use for example
$article=Article::findFirst(12);
echo $article->listtitle."<br />";
echo $article->icon->thumbnail."<br />";
It says:
Notice: Trying to get property of non-object in /hosts/application/frontend/app/controllers/ArticlesController.php on line 24
(where $article->icon->thumbnail is on line 24)
The belonsgTo relation works fine.
My question:
Do I forgot something, or is there a fix for this?