Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

[Phalcon 2.0.3] The meta-data is invalid or is corrupt

Hi Phalcon team,

I'm developing a webapp with Phalcon framework, i'm using the model annotations parser + * model metadata set* to customize my model property class.

But some problem appear and i did not fix it. For example:

I create a user manager feature with CRUD code. Read and Delete action is done and work okay, but Create and Update action is error, when add or edit the model appear message "The meta-data is invalid or is corrupt", can u help me fix my error, i'm tried change metadata storage from file to memory but it not work.

Machine develop enviroment: Mac OS X 10.10 Homebrew package * - Nginx 1.8 * - PHP-FPM 5.5 * - Phalcon 2.0.3 * - MySQL 5.6

Bootstrap.php
public function initMetadata($options = [])
    {
        $config = $this->di['config'];

        $this->di->set('modelsMetadata', function() use ($config) {
            // $metaData = new PhMetadataFiles(
            //     ['metaDataDir' => $config->app_model->metadata]
            // );

            $metaData = new PhMetadataMemory();

            //Set a custom meta-data database introspection
            $metaData->setStrategy(new FlyAnnotationsMetaDataInitializer());

            return $metaData;
        });
    }
public function initAnnotations($options = [])
    {
        $config = $this->di['config'];

        $this->di->set('annotations', function() use ($config) {
            // return new PhAnnotationsAdapter([
            //     'annotationsDir' => $config->app_annotations->cache
            // ]);

            return new PhAnnotationsAdapterMemory();
        });
    }
AnnotationsInitializer.php
<?php
/**
 * \Fly\AnnotationInitializer
 * AnnotationInitializer.php
 *
 * Model Annotation Initializer class
 *
 * @author      phalconphp.com
 * @since       2014-12-19
 * @category    Fly
 *
 */

namespace Fly;

use Phalcon\Events\Event;
use Phalcon\Mvc\Model\Manager as ModelsManager;
use Phalcon\Mvc\ModelInterface;

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, ModelInterface $model)
    {
        //Reflector
        $reflector = $this->annotations->get($model);

        /**
         * Read the annotations in the class' docblock
         */
        $annotations = $reflector->getClassAnnotations();

        if ($annotations) {

            /**
             * Traverse the annotations
             */
            foreach ($annotations as $annotation) {
                switch ($annotation->getName()) {

                    /**
                     * Initializes the model's source
                     */
                    case 'Source':
                        $arguments = $annotation->getArguments();
                        $manager->setModelSource($model, $arguments[0]);
                        break;

                    /**
                     * Initializes Has-Many relations
                     */
                    case 'HasMany':
                        $arguments = $annotation->getArguments();
                        $manager->addHasMany($model, $arguments[0], $arguments[1], $arguments[2]);
                        break;

                    /**
                     * Initializes Has-Many relations
                     */
                    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;

                }
            }
        }

    }

}
AnnotationsMetaDataInitializer.php
<?php
/**
 * \Fly\AnnotationsMetaDataInitializer
 * AnnotationsMetaDataInitializer.php
 *
 * Metadata Annotation Initializer class
 *
 * @author      phalconphp.com
 * @since       2014-12-19
 * @category    Fly
 *
 */

namespace Fly;

use Phalcon\Db\Column;
use Phalcon\DiInterface;
use Phalcon\Mvc\Model\MetaData;
use Phalcon\Mvc\ModelInterface;

class AnnotationsMetaDataInitializer
{

    /**
     * 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 = [];
        $nullables = [];
        $dataTypes = [];
        $dataTypesBind = [];
        $numericTypes = [];
        $primaryKeys = [];
        $nonPrimaryKeys = [];
        $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;
                    }
                } 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 [

            //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 => [],

            //Fields that must be ignored from UPDATE SQL statements
            MetaData::MODELS_AUTOMATIC_DEFAULT_UPDATE => []

        ];
    }

    /**
     * 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 = [];
        $reverseColumnMap = [];

        $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 [
                MetaData::MODELS_COLUMN_MAP => $columnMap,
                MetaData::MODELS_REVERSE_COLUMN_MAP => $reverseColumnMap
            ];
        }

        return null;
    }

}
ModelUser.php
<?php
namespace Model;

use Phalcon\DI\FactoryDefault as DI;
use Fly\BaseModel as FlyModel;

/**
 * User
 *
 * Represents a User
 *
 * @Source('fly_user');
 */
class User extends FlyModel
{
    /**
    * @Primary
    * @Identity
    * @Column(type="integer", nullable=false, column="u_id")
    */
    public $id;

    /**
    * @Column(type="string", nullable=true, column="u_name")
    */
    public $name;

    /**
    * @Column(type="string", nullable=true, column="u_email")
    */
    public $email;

    /**
    * @Column(type="string", nullable=false, column="u_password")
    */
    public $password;

    /**
    * @Column(type="integer", nullable=false, column="u_role")
    */
    public $role;

    /**
    * @Column(type="string", nullable=true, column="u_avatar")
    */
    public $avatar;

    /**
    * @Column(type="integer", nullable=false, column="u_status")
    */
    public $status;

    /**
    * @Column(type="integer", nullable=true, column="u_datecreated")
    */
    public $datecreated;

    /**
    * @Column(type="integer", nullable=true, column="u_datemodified")
    */
    public $datemodified;


    const STATUS_ENABLE = 1;
    const STATUS_DISABLE = 3;

    protected $lang;

    public function initialize()
    {
        parent::initialize();
    }

    public function onConstruct()
    {
        $this->lang = DI::getDefault()->get('lang');
    }

    public function beforeCreate()
    {
        $this->datecreated = time();
    }

    public function beforeUpdate()
    {
        $this->datemodified = time();
    }

    public function validation()
    {
        $this->validate(new \Phalcon\Mvc\Model\Validator\PresenceOf(
            [
                'field'  => 'name',
                'message' => $this->lang->get('message_name_notempty')
            ]
        ));

        $this->validate(new \Phalcon\Mvc\Model\Validator\Uniqueness(
            [
                'field'  => 'email',
                'message' => $this->lang->get('message_email_unique')
            ]
        ));

        $this->validate(new \Phalcon\Mvc\Model\Validator\PresenceOf(
            [
                'field'  => 'password',
                'message' => $this->lang->get('message_password_notempty')
            ]
        ));

        $this->validate(new \Phalcon\Mvc\Model\Validator\Numericality(
            [
                'field'  => 'role',
                'message' => $this->lang->get('message_role_isnum')
            ]
        ));

        $this->validate(new \Phalcon\Mvc\Model\Validator\Numericality(
            [
                'field'  => 'status',
                'message' => $this->lang->get('message_status_isnum')
            ]
        ));


        return $this->validationHasFailed() != true;
    }

    /**
     * Extends Phalcon findFirst to handle cache
     */
    public static function findFirst($parameters=null)
    {
        $data = parent::findFirst($parameters);
        return $data;
    }
}
UserController.php
public function addAction()
    {
        $redirectUrl = (string) urldecode(base64_decode($this->dispatcher->getParam('redirect')));
        $formData = [];
        $message = '';

        if ($this->request->hasPost('fsubmit')) {
            if ($this->security->checkToken()) {
                $formData = array_merge($formData, $this->request->getPost());

                $myUser = new \Model\User();
                $myUser->assign([
                    'name' => $formData['fname'],
                    'email' => $formData['femail'],
                    'password' => $this->security->hash($formData['fpassword']),
                    'role' => $formData['frole'],
                    'avatar' => $formData['favatar'],
                    'status' => $formData['fstatus'],
                ]);

                if ($myUser->create()) {
                    $this->flash->success($this->lang->get('message_add_success'));
                } else {
                    foreach ($myUser->getMessages() as $msg) {
                        $message .= $msg->getMessage() . "</br>";
                    }
                    $this->flash->error($message);
                }
            } else {
                $this->flash->error('CSRF Detected.');
            }
        }

        $this->tag->prependTitle($this->lang->get('title_add'));
        $this->breadcrumb->add($this->lang->get('title_add'), 'admin/user');
        $this->breadcrumb->add($this->lang->get('title_adding'), 'admin/user/add');
        $this->view->setVars([
            'redirectUrl' => $redirectUrl,
            'formData' => $formData,
            'breadcrumb' => $this->breadcrumb->generate(),
            'statusList' => \Model\User::getStatusList(),
            'roleList' => \Model\User::getRoleList(),
        ]);
    }


33.4k
Accepted
answer

getMetaData() is missing two indexes required MODELSDEFAULTVALUES and MODELSEMPTYSTRING_VALUES: https://docs.phalconphp.com/en/latest/reference/models.html#manual-meta-data

Thank so much Phalcon Team :) I was fixed it.