New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught exception: Column 'cate_id' doesn't belong to any of the selected models (1) #1731

Closed
dancebear opened this Issue Dec 23, 2013 · 4 comments

Comments

Projects
None yet
4 participants
@dancebear
Copy link
Contributor

dancebear commented Dec 23, 2013

I use the following statement to cache metadata

$di->set ( 'modelsMetadata', function () use($config) {
    if (! $config->application->debug && isset ( $config->metadata )) {
        $metaDataConfig = $config->metadata;
        $metadataAdapter = '\Phalcon\Mvc\Model\Metadata\\' . $metaDataConfig->adapter;
        $metaData = new $metadataAdapter ( $config->metadata->toArray () );
    } else {
        $metaData = new \Phalcon\Mvc\Model\MetaData\Memory ();
    }
            $metaData->setStrategy ( new \Core\Model\AnnotationsMetaDataInitializer () );
    return $metaData;
}, true );

class AnnotationsMetaDataInitializer

<?php
namespace Core\Model;

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

class AnnotationsMetaDataInitializer
{

    /**
     * 初始化模型的元数据
     *
     * @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();

    $attributes = array();
    $nullables = array();
    $dataTypes = array();
    $dataTypesBind = array();
    $numericTypes = array();
    $primaryKeys = array();
    $nonPrimaryKeys = array();
    $identity = null;

    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;
        }

        /**
         * 处理列注释的类型参数
         */
        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 'char':
                $dataTypes[$columnName] = Column::TYPE_CHAR;
                $dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
                break;
            case 'text':
                $dataTypes[$columnName] = Column::TYPE_TEXT;
                $dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
                break;
            case 'float':
                $dataTypes[$columnName] = Column::TYPE_FLOAT;
                $dataTypesBind[$columnName] = Column::BIND_PARAM_STR;
                break;
            case 'decimal':
                $dataTypes[$columnName] = Column::TYPE_DECIMAL;
                $dataTypesBind[$columnName] = Column::BIND_PARAM_DECIMAL;
                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;
        }

        /**
         * 处理列注释的'nullable'参数
         */
        if (!$collection->has('Identity')) {
            if (isset($arguments['nullable'])) {
            if (!$arguments['nullable']) {
                $nullables[] = $columnName;
            }
            }
        }

        $attributes[] = $columnName;

        /**
         * 检查是否为主键
         */
        if ($collection->has('Primary')) {
            $primaryKeys[] = $columnName;
        } else {
            $nonPrimaryKeys[] = $columnName;
        }

        /**
         * 属性是否表示为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()

    );
    }

    /**
     * 初始化模型
     *
     * @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();

        /**
         * 列名
         */
        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;
    }

    /**
     * 获取所有模型的元数据
     *
     * @param DiInterface $di Dependency Injection.
     *
     * @return array
     */
    public function getAllModelsMetadata(DiInterface $di)
    {
    $models = array();
    foreach ($di->get('modules') as $module => $enabled) {
        $modelsDirectory = $di->get('config')->application->modulesDir . ucfirst($module) . '/Model';
        foreach (glob($modelsDirectory . '/*.php') as $modelPath) {
        $modelInfo = array();
        $modelClass = '\\Elk\\' . ucfirst($module) . '\Model\\' . basename(str_replace('.php', '', $modelPath));
        $reflector = $di->get('annotations')->get($modelClass);

        // Get table name.
        $annotations = $reflector->getClassAnnotations();
        if ($annotations) {
            foreach ($annotations as $annotation) {
            if ($annotation->getName() == 'Source') {
                $arguments = $annotation->getArguments();
                $modelInfo['name'] = $arguments[0];
            }
            }
        }

        // 数据表的字段属性
        $modelInfo['columns'] = array();

        $properties = $reflector->getPropertiesAnnotations();
        foreach ($properties as $name => $collection) {
            if ($collection->has('Column')) {
            $arguments = $collection->get('Column')->getArguments();
            /**
             * 列名
             */
            if (isset($arguments['column'])) {
                $columnName = $arguments['column'];
            } else {
                $columnName = $name;
            }
            $modelInfo['columns'][$columnName] = array();

            /**
             * 类型
             */
            if (isset($arguments['type'])) {
                switch ($arguments['type']) {
                case 'integer':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_INTEGER;
                    $modelInfo['columns'][$columnName]['is_numeric'] = true;
                    break;
                case 'string':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_VARCHAR;
                    break;
                case 'text':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_TEXT;
                    break;
                case 'char':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_CHAR;
                    break;
                case 'float':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_FLOAT;
                    break;
                case 'decimal':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_DECIMAL;
                    break;
                case 'boolean':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_BOOLEAN;
                    break;
                case 'date':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_DATE;
                    break;
                case 'datetime':
                    $modelInfo['columns'][$columnName]['type'] = Column::TYPE_DATETIME;
                    break;
                }
            }

            /**
             * 数据长度
             */
            if (isset($arguments['length'])) {
                $modelInfo['columns'][$columnName]['size'] = $arguments['length'];
            }

            /**
             * 列的'nullable'属性
             */
            if (!$collection->has('Identity')) {
                if (isset($arguments['nullable'])) {
                $modelInfo['columns'][$columnName]['nullable'] = $arguments['nullable'];
                }
            }

            /**
             * 是否为主键
             */
            if ($collection->has('Primary')) {
                $modelInfo['columns'][$columnName]['is_primary'] = true;
            }

            /**
             * 是否标记为identity
             */
            if ($collection->has('Identity')) {
                $modelInfo['columns'][$columnName]['identity'] = true;
            }

            }
        }
        $models[] = $modelInfo;
        }
    }

    return $models;

    }

}

When I use the adapter Files everything is normal, but when using the APC adapter output the following errors:
Uncaught exception: Column 'cate_id' doesn't belong to any of the selected models (1), when preparing: SELECT [Elk\News\Model\News].* FROM [Elk\News\Model\News] WHERE cate_id=🆔 ORDER BY creation_date ASC LIMIT 5
Uncaught exception: Column 'serial_name' doesn't belong to any of the selected models (1), when preparing: SELECT [Elk\Company\Model\SuccessStories].* FROM [Elk\Company\Model\SuccessStories] WHERE serial_name = ?1 LIMIT 1

Does this mean that APC adapter contains some bug? Or was I doing something wrong?

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@dreamsxin

This comment has been minimized.

Copy link
Contributor

dreamsxin commented Dec 24, 2013

好像是 meta_data::hasattribute 去匹配 model 没有找到 model 有对应的 column_name。你可以输出model 对应 的 metaData 看看。

@dancebear

This comment has been minimized.

Copy link
Contributor Author

dancebear commented Dec 24, 2013

var_dump($collection);输出

object(Phalcon\Annotations\Collection)#895 (2) {
  ["_position":protected]=> int(0)
  ["_annotations":protected]=> array(3) {
    [0]=> object(Phalcon\Annotations\Annotation)#894 (3) {
      ["_name":protected]=> string(7) "Primary"
      ["_arguments":protected]=> NULL
      ["_exprArguments":protected]=> NULL
    }
    [1]=> object(Phalcon\Annotations\Annotation)#893 (3) {
      ["_name":protected]=> string(8) "Identity"
      ["_arguments":protected]=> NULL
      ["_exprArguments":protected]=> NULL
    }
    [2]=> object(Phalcon\Annotations\Annotation)#892 (3) {
      ["_name":protected]=> string(6) "Column"
      ["_arguments":protected]=> array(3) {
    ["type"]=> string(7) "integer"
    ["nullable"]=> bool(false)
    ["column"]=> string(7) "case_id"
      }
      ["_exprArguments":protected]=> array(3) {
    [0]=> array(2) {
      ["expr"]=> array(2) {
        ["type"]=> int(303)
        ["value"]=> string(7) "integer"
      }
      ["name"]=> string(4) "type"
    }
    [1]=> array(2) {
      ["expr"]=>  array(1) {
        ["type"]=> int(305)
      }
      ["name"]=> string(8) "nullable"
    }
    [2]=> array(2) {
      ["expr"]=> array(2) {
        ["type"]=> int(303)
        ["value"]=> string(7) "case_id"
      }
      ["name"]=> string(6) "column"
    }
      }
    }
  }
}

var_dump($collection->has('Column'));输出

bool(true)

var_dump($collection);

object(Phalcon\Annotations\Collection)#891 (2) {
  ["_position":protected]=> int(0)
  ["_annotations":protected]=> array(1) {
    [0]=>
    object(Phalcon\Annotations\Annotation)#890 (3) {
      ["_name":protected]=> string(6) "Column"
      ["_arguments":protected]=> array(4) {
    ["type"]=> string(6) "string"
    ["nullable"]=> bool(false)
    ["column"]=> string(9) "case_name"
    ["length"]=> string(3) "200"
      }
      ["_exprArguments":protected]=> array(4) {
    [0]=>
    array(2) {
      ["expr"]=> array(2) {
        ["type"]=> int(303)
        ["value"]=> string(6) "string"
      }
      ["name"]=> string(4) "type"
    }
    [1]=>
    array(2) {
      ["expr"]=> array(1) {
        ["type"]=> int(305)
      }
      ["name"]=> string(8) "nullable"
    }
    [2]=>
    array(2) {
      ["expr"]=> array(2) {
        ["type"]=> int(303)
        ["value"]=> string(9) "case_name"
      }
      ["name"]=> string(6) "column"
    }
    [3]=>
    array(2) {
      ["expr"]=> array(2) {
        ["type"]=> int(301)
        ["value"]=> string(3) "200"
      }
      ["name"]=> string(6) "length"
    }
      }
    }
  }
}

var_dump($collection->has('Column'));输出

bool(true)

此问题仅在使用\Phalcon\Mvc\Model\Metadata\Apc时出现,\Phalcon\Mvc\Model\Metadata\Files并无此问题

@dreamsxin

This comment has been minimized.

Copy link
Contributor

dreamsxin commented Dec 24, 2013

能提交你的Model代码上来么,这样好重现下问题?
我这里昨天测试,忘记给models添加Annotations了,今天测试没问题。

    $metaData = new \Phalcon\Mvc\Model\Metadata\Files(array(
            'metaDataDir' => '../apps/cache/'
        ));
        $metaData = new \Phalcon\Mvc\Model\MetaData\Memory();
        $metaData = new \Phalcon\Mvc\Model\MetaData\Apc(array(
            "lifetime" => 86400,
            "prefix" => "my-prefix"
        ));

测试了这三个,无法重现这个问题。

@stale

This comment has been minimized.

Copy link

stale bot commented Apr 17, 2018

Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalconphp.com/post/github-closing-old-issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment