добавление таблиц в БД

Добрый вечер!

Хочу приделать к модулю приложения полезную штуку - добавление в БД таблиц модуля при первом запуске, если они отсутствуют там. Столкнулся с проблемой, при создании action install и соответствующей функции в модели, мне выдается ошибка, то что таблица данного модуля отсутствует в бд. При том, что я ее нигде не запрашиваю. в чем может быть дело?

это как-то связано с работой модели, но не знаю как это обойти. т.е. это не ошибка в коде, а просто то, что модель видимо вызывает таблицу, определенную в function tableName();, а если ее там снести, то таблицу одноименную с названием модели…

Я такое сделал для себя. Использовал переопределение метода CActiveRecord::getMetaData().

В методе проверял существует ли таблица с помощью sql "show table status" и если нет, то запускал ее инсталляцию.

Более того, подскажу идею. Каждая модель у меня описана в таком виде:



    protected function getFields()


    {


        return array(


            "username" => array(


                "type" => array("string", 25)


            ),


            "password" => array(


                "type" => array("string", 100)


            ),


            "email" => array(


                "type" => "email"


            ),


            "datetime_create" => array(


                "type" => "datetime"


            ),


            "editor" => array(


                "type" => array("object", "User"),


                "default" => SUPER_USER_ID


            ),


            "editor_username" => array(


                "type" => array("string", "25"),


            ),


            "datetime_modify" => array(


                "type" => "datetime"


            ),            


        );


    }    


Специальные функции умеют перекодировать эту структуру в sql и обратно. Что в итоге имеем? Примерно вот такую последовательность.

  1. В getMetaData() проверяем создана ли таблица, если нет - создаем.

  2. Если включен режим автообновления, то сверяем существующую таблицу в базе с тем, что выдает метод getFields().

  3. Сверка и последующая синхронизация происходит по каждому полю.

rosko, а как ты переопределил getMetaData?

Насколько я вижу из кода AR при вызове Class::model() идет вызов CActiveRecordMetaData($model); и это происходит до обращения к функции getMetaData

В моем случае это выглядит, как некий клас, который является прослойкой между CActiveRecord и классами конкретных моделей.

Вот кусок моего кода:



abstract class TempoActiveRecord extends CActiveRecord


{


    public function getMetaData()


    {


        $status = self::getTableStatus($this->tableName());


        if  (($status === null)&&(Yii::app()->params["autoInstall"]))


        {


            $this->updateDbTable();


        }


        return parent::getMetaData();


    }


не совсем уловил последовательность:

  1. Имеем такую вот прослойку. а каждая модель будет являтся ее потомком?

  2. Какие функции позволяют массив перегнать в скл? Кстати классно. Мне определенно нравится такое представление мускула в массивах, удобно.

  1. Да.

  2. Я их писал сам.

rosko, идея клевая!! но все-таки я не понял твоей обвязки.

С переопределением getMetaData все ясно, но я так понимаю ты еще и метод model переписал?

Нет, я переопределил getMetaData(). Метод model() не трогал, он стандартный:



    public static function model($className=__CLASS__)


    {


        return parent::model($className);


    }


Тогда я не понимаю. если вызывать



$news = News::model()->...


при не существующей таблице он начинает ругаться еще до обращения к методу getMetaData.

Может ты еще что-то сделал?

У меня сделано чуть по-другому. В твоем случае тебе нужно все-таки переопределить метод model()

О чем и речь))) все равно спасибо за идею ;)

еще пара вопросов, если можно:

$this->updateDbTable(); - вот этот вызов, это соответственно нужен такой метод в самой модели, который и будет возвращать массив данных? или эта функция уже занимается конвертацией массива, а массив в другой находится?

нет ли какого-то готового решения на просторах инета по конвертации массива в mysql? Немного погуглил, пока не нашел. Может придется и написать…

$this->updateDbTable() - занимается конвертацией из массива в БД. Метод лучше определить в родительском для моделей классе.

А массив у меня находится в принадлежащем уже конкретной модели методе - getFields() (см. выше - http://www.yiiframew…html#msg14114)

все, с этим понял. и все-таки? я что-то подобное видел, но не могу вспомнить где, может в друпале? Когда из массива конвертировалось в mysql. не знаете? есть какие-то решения?

Нет, не помню.

Правда в yii есть нечто похожее в тех же данных, что возвращает getMetaData(). Исследуй классы CDbSchema, CMysqlSchema, CMysqlTableSchema, CMysqlColumnSchema

а я должен где-то вызывать данный или какой-то другой метод в контроллере? Просто я все сделал, пока без массивов, просто дамп sql, но при запуске данного модуля у меня ошибка:

The table "advertisements_categories" for active record class "Advertisements_mdl_categories" cannot be found in the database.

UPD

от этого недуга избавился, ошибок нет, но и добавления данных в базу не происходит. что=то наверное не так сделал. причем код добавления данных в базу исправный, работал раньше в другом месте.

кстати, вот и код:

это в файле модели, причем хочу обратить внимание что у меня в 1 модуле их несколько. как быть тогда? Просто логично разделить было - 1 модель отвечает за категории, другая за сами объявления (в данном случае) ну ит.д.



    public function getSchema()


	{


	    return array(


	    	'sql' => './protected/modules/advertisements/config/schema_advertisements.sql',


	    	'sep' => ';',


	    	)	


	}


а вот код новоиспеченной прослойки:



Abstract Class TempoActiveRecord extends CActiveRecord


{


    public function getMetaData()


    {


        $status = self::getTableStatus($this->tableName());


        if  (($status === null)&&(Yii::app()->params["autoInstallModules"]))


        {


            $this->updateDbTable();


        }


        return parent::getMetaData();


    }


    


    public function updateDbTable();


    {


    	$data = $this->getSchema();


  		$sql = file_get_contents($data['dump']);





		foreach (explode($data['sep'],$data['sql']) as $query)


		{


    		$query = trim($query);


    		if (!empty($query))


    		{


				$command = $connection->createCommand($query)->execute();


				return true;


    		}


    		else


	    	{


	    		return false;	


	    	}


  		}


    }


что не так?

Код слишком “слизан” :)

getTableStatus() - у тебя нету этой функции, поэтому код у тебя не работает. у меня она проверяла наличие таблицы в БД.

TempoActiveRecord - можешь еще изменить название прослойки. Tempo - это название CMS, которую я делаю на Yii.

Извините за некоторую “слизанность”, это в качестве эксперимента я просто по-быстрому пытался понять будет ли работать. Щас поразбираюсь  ;) Спасибо.

функцию сделал… и все равно ничего не срабатывает(( и не могу понять в чем тут дело(

кстати как и у Digital God у меня модель вызывается так же. может в этом дело? Хотя я не совсем понимаю, а как ее можно вызвать иначе?