Отладка need help!

разбираю тестовый пример(блог) с небольшими отклонениями в сторону, перечитываю примеры по 10 раз, по-другому так сказать наскоком не получается, добрался до отладки, сначала просто раскоментировал логирование в main.php и внизу экрана просматривал трейсы, затем почитал топики про yiidebugtool, поставил, однако сильно на качество выводящейся информации это не повлияло, так же промучался с Xdebug, поставить поставил, заработало, но что оно делает и как его кушать пока толком не понял (прочитаю 10 раз маны с 11-го пойму а нужно ли оно мне и с чем его едят)

собственно вопрос:

  • имеется форма создания нового поста блога

  • пост нужно определить в какую-то из существующих категорий

  • категории вытаскиваются из базы и помещаются в селект в текстовом виде

  • в базу нужно записать айди категории (int)

  • поле имени категории есть обязательным и прописано в rules

  • в rules запись о том что категория должны быть numerical - убрал

  • по алгоритму выбираю в селекте категорию и жму сабмит, перехватываю данные методом beforeSave() и тут уже делаю запрос в базу чтобы узнать какой id у моей категории и собственно устанавливаю его (this->category (varchar) превращается в this->category(int))

Вроди бы как должно работать, однако

Executing SQL: INSERT INTO tbl_post (title, content, tags, status, create_time, update_time, author_id) VALUES (:yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6)

однако этот запрос не срабатывает, как я бы сказал раньше не резалтит

Суть вопроса, хорошо, что есть отладчик и я вижу выполнение запроса, а могу ли я каким-то чудом увидеть параметры запроса? вот эти вот VALUES (:yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6)

ранее было хорошо для отладки писал echo "query = ".$query."<br />"; и видел что запрос пытается выполнить, а вот здесь я в замешательстве

подскажите, что бы Вы сделали в данной ситуации и каким инструментом для отладки приложений пользуетесь вообще

Я не совсем понял как эти параметры увидеть. Если происходит SQL ошибка, то я смотрю ей в логе protected/runtime/messages.log

Судя по твоему описанию, проблема может быть в $this->category, ты можешь сделать echo $this->category; там где ты её присваиваешь. Безотказный дедовский метод.

Но ты явно что то неверно делаешь с этими категориями. Зачем их держать в текстовом виде, а потом опять преобразовывать в числовой? Без необходимости BeforeSave и AfterFind лучше не трогать, если есть желание такого преобразования, то определи отдельное поле (которое не будет сохраняться в базу)…

Вот как я делаю в случае связей один-к-многим:

По первых лучше называть поля для внешних связей правильно. Не "post.category" а "post.category_id", это устранит проблему совпадения имен при реляционных связях.

Релационная связь, например если в модели Post определена следующая связь:




public function relations() {

	return array(

		'category' => array(self::BELONG_TO, 'Category', 'category_id'),

	);

}



то "$post->category_id" - это имя категории (число), а "$post->category" - уже модель категории (объект) откуда легко получить её имя, к примеру "$post->category->name"

Для получения списка категорий на форме редактирования поста необходимо определить метод в модели категорий, который вернет нам массив id->name:




static public function getList(){

    $arr=self::model()->findAll();

    return CHtml::listData($arr, 'id', 'name' );

}



потом в представлении задаем выпадающий список:




<?php echo $form->dropDownList($model,'category_id', Category::getList()); ?>



И все, никаких преобразований в beforeSave() не нужно.

Если надо в списке постов, который выводится с помощью CGridView, вместо номера категории вывести её имя, то просто в списке столбцов нужно вместо ‘category_id’ указать ‘category.name’ - где “category” это имя отношения, который должен быть задан, как указано выше.

увидел новые данные

Querying SQL: SELECT id FROM tbl_category t WHERE name =2

тоесть мой запрос отрабатывает, но $this->category отдаёт мне айди категории вместо её имени, не понимаю почему, в форме у меня селект с именами категорий, тогда как сюда попал айди? собственно и понятно почему я получаю непонятные данные из-за ошибки в запросе, но непонятно как ко мне из селекта попадает id вместо имени и как сделать, чтобы я всё же получил имя ане айди …

littledev Вы создаете слишком трудночитаемые сообщения, обратите внимание на форматирование и предварительный просмотр.

Вот тут вы должны были задать себе вопрос "А какое же тогда значение вставляется в $this->category = $postId;" и сделать


echo CVarDumper::dumpAsString($postId);

мне очень кажется, что findAll возвращает вам массив а не число, и лучше было использовать find();

А вообще код:




$postId = new CDbCriteria;

$postId->select = 'id';

$postId->condition = 'name ='.$this->category;

$postId = Category::model()->findAll($postId);



короче записать как




$category=Category::model()->findByAttributes(array('name'=>$this->category));

//и потом использовать $category->id;



Но вообще идея преобразования текста в число, как вы описали, в корне не верна. Нет, не юзер конечно должен видеть только текст и не запоминать внутренние номера для каждой категории, но в каком виде пользователь вводит категорию?

Если в виде текстового поля, то где обработка ввода такого имени категории, которого нет в таблице?

Если в виде выпадающего списка, то стыдно не знать о том что каждая его запись содержит значение и отображаемый текст, т.е. "<option value=1>Боевик</option>" и пользователь видит текст, а коду уходит именно value, т.е. id. Как создать такой список я описал в первом ответе и в таком случае не нужно будет никаких лишних преобразований.

Я Вам выражаю огромную благодарность за то, что тратите на меня своё время, но тем не менее есть некоторые нюансы о которых стоит упомянуть:

  • например в мануале основном к фреймворку не делается акцент на отладку, ни на базовую ни с помощью вспомогательных средств (да я новичек, но моё мнение это не есть гуд)

делаю find и оно мне вместо массива значений с кол-вом ответов 1 возвращает единственный ответ с кол-вом значений = 1, исключительные ситуации отработаны но не более того, тоесть в данном конкретном случае find и findAll абсолютно одинаково отвечают на запрос (ибо поле по которому ведется поиск является unique)

делаю echo CVarDumper::dumpAsString($postId); как Вы посоветовали, но где мне делать это echo и где его ловить ? в какой момент?

далее …

здесь я явно указал что пользователь из селекта выбирает то что ему нужно, тоесть никаких пользовательских вводов, что мы дадим - то и будет

и кстаи о птичках …изначальный вопрос …есть ли инструментарий котрый мне позволит вскрыть значения yp0 yp1 и т.д. ? если я буду видеть какие значения подставляются в запрос я буду знать, что идёт правильно, а что нет … если не буду видеть, то тогда мне в очередной раз придётся перестраиваться с процедурного мышления и отладки в сторону ООП и представления и отладки

то, что Вы написали вначале испробую,но вцелом это решит одну проблемку, но вероятнее всего у меня в будущем возникнут другие вопросы когда нужно будет увидеть даные идущие на запись в базу

Похвально, такому человеку приятно помогать.

Ура, я все-таки нашел ответ на ваш вопрос. При описании компонента db нужно указать параметр "enableParamLogging".




        'components'=>array(

            'db'=>array(

                'connectionString' => 'mysql:host=localhost;dbname=****',

                'enableProfiling'=>true,

                'enableParamLogging' => true,

                'username' => 'root',

                'password' => '',

                'charset' => 'utf8',



и тогда в логе после запроса будет: Bound with :ypl0=‘33’

С основным вопросом разобрались, давайте разберемся теперь с второстепенными.


    protected function beforeSave(){

        if(parent::beforeSave()){

            if($this->isNewRecord){

                $this->create_time=$this->update_time=time();


                $postId = new CDbCriteria;

                $postId->select = 'id';

                $postId->condition = 'name ='.$this->category;

                $postId = Category::model()->findAll($postId);


                $this->category = $postId;


            }

            else

                $this->update_time=time();

            return true;

        }

        else

            return false;

    }



Это ваша функция, вы присваиваете $this->category = $postId; и у вас ошибка, а когда вы делаете $this->category = 1; то ошибки нет. Значит ошибочен параметр и вы хотели увидеть его через лог, но я предложил вам посмотреть на этот параметр дедовским методом, сразу после определения переменной $postId вывести её: echo CVarDumper::dumpAsString($postId); и в браузере выполнить сохранение, функция dumpAsString напечатаем вам какого типа переменная $postId и её содержание. Может оказаться, например, что это массив а не число, и понятное дело конечном запросе из-за этого будет ошибка.

Теперь про то, как правильно формировать dropDownList и избежать необходимости с переопределением метода "beforeSave()"

Как я писал ранее, в моделе Category определите статический метод:


static public function getList(){

    $arr=self::model()->findAll();

    return CHtml::listData($arr, 'id', 'name' );

}

Он возвращает массив "id"=>"name" примерно: (1=>"Категория 1", 3=>"Категория 2", …) и этот массив нужно передать в dropDownList (вторым или третьим параметром, в зависимости от того какая функция используется dropDownList или activeDropDownList)

Ведь если я правильно вас понимаю (читаю мысли) массив для своего списка вы составляли либо как "имя категории"=>"имя категории"


("Категория 1"=>"Категория 1", "Категория 2"=>"Категория 2", ...)

либо как "номер по порядку"=>"имя категории" вместо "id категории"=>"Имя категории"


(0=>"Категория 1", 1=>"Категория 2", ...)

Ответ на 10 баллов - именно то, что я искал. Теперь жить стало значительно легче

остальное прорепетирую позднее (особенно интересно с селектом, я ведь привык по-старинке к такому

<form action=‘action.php’ method=‘POST’>

  &lt;?php


  &#036;arr = array (


         1 =&gt; bmw,


         2 =&gt; volvo,


         3 =&gt; chevrolet,


         4 =&gt; audi,


          );


   ?&gt;


    


   &lt;select name='cars'&gt;





   &lt;?php


      foreach(&#036;arr as &#036;key=&gt;&#036;value)


      echo &quot;&lt;option&gt;&quot;.&#036;value.&quot;&lt;/option&gt;&quot;;


   ?&gt;





   &lt;/select&gt;

<input type=‘submit’ value=‘Go’ />

</form>

и естественно $_POST[‘cars’] вернет мне название машины ане её айди, посему я как-то совсем попал в замешательство и поэтому же мне дважды интересно прокрутить это в голове и в коде ну и дампер тоже обязательно попробую

спасибо огромное за помощь

О даа, это совсем по старинке :)

В Yii есть хелперы для того же выпадающего списка и пользоваться ими просто изумительно просто.

Еще напутствие, не знаю как тестовый блог, но советую вам настроить генератор кода gii, сгенерировать им модель для своих таблиц категорий и постов, а потом создать им же CRUD модели для них, и вот с ними уже разбираться. Т.к. в будущем будете работать уже с генератором а не с "тестовым блогом", а он отличается в лучшую сторону.