Cgridview, Many_Many, Фильтрация Данных

Добрый день.

Есть две модели:

Note и Order.

Order:




...

public function relations()

{

	return array(

		'notes' => array(self::MANY_MANY, 'Note', 'order_note(order_id, note_id)'),

	);

}

...



Note:




...

public $assignedOrders;

...

public function rules()

{

	return array(

		...

		array(

			'..., assignedOrders, ...',

			'safe',

			'on' => 'search'

		),

		...

	);

}

...

public function relations()

{

	return array(

		...

		'orders'    => array(self::MANY_MANY, 'Order', 'order_note(note_id, order_id)'),

		...

	);

}

...

public function attributeLabels()

{

	return array(

		...

		'assignedOrders' => '№ заказа(ов)',

		...

	);

}

...

public function getRelatedOrderNames ()

{

    return implode(', ', CHtml::listData($this->orders, 'id', 'name'));

}

...



Во вьюшке:




...

$this->widget('zii.widgets.grid.CGridView', array(

    'id'           => 'notes-grid',

    'dataProvider' => $model->search(),

    'filter'       => $model,

    'columns' => array(

	...

        array(

            'name'        => 'assignedOrders',

            'value'       => '$data->relatedOrderNames',

            'htmlOptions' => array('style' => 'width:10%;'),

        ),			

	...

    ),

));

...



Заказы отображаются в таблице в виде строки через запятую, вот так:

Наименование | № заказа(ов)

Записка 1 | 1045, 2036

Записка 2 | 7584, 3036

Записка 3 | 7789

Никак не могу сообразить что нужно написать в модели Note в методе search(), чтобы можно было фильтровать заказы как строку по LIKE. Напимер, при вводе в поле фильтра 036, должны показываться только строки с Записка 1 и Записка 2.

P.S.: за основу брался этот топик

A что сейчас у вас прописано в методе search()?

По анологии с примером из топика должно быть что-то вроде




$criteria->compare('order_id',$this->assignedOrders);

$criteria->with=array('orders');

$criteria->together=true;



пробовал этот вариант, но появляется ошибка:




2013/03/28 16:19:50 [error] [system.db.CDbCommand] Не удалось выполнить CDbCommand::fetchAll(): SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in order clause is ambiguous. Выполнявшийся SQL-запрос: SELECT `t`.`id` AS `t0_c0`, `t`.`created_at` AS `t0_c1`, `t`.`status` AS `t0_c2`, `t`.`number` AS `t0_c3`, `t`.`release_date` AS `t0_c4`, `t`.`aggregate_type` AS `t0_c5`, `t`.`applicability` AS `t0_c6`, `t`.`release_reason` AS `t0_c7`, `t`.`note_content` AS `t0_c8`, `t`.`rework` AS `t0_c9`, `t`.`subdivision` AS `t0_c10`, `t`.`author_id` AS `t0_c11`, `t`.`ii_release_date` AS `t0_c12`, `t`.`ii_number` AS `t0_c13`, `t`.`aggregate_number` AS `t0_c14`, `orders`.`id` AS `t1_c0`, `orders`.`order_status_id` AS `t1_c1`, `orders`.`name` AS `t1_c2`, `orders`.`note` AS `t1_c3`, `orders`.`object` AS `t1_c4` FROM `note` `t`  LEFT OUTER JOIN `order_note` `orders_orders` ON (`t`.`id`=`orders_orders`.`note_id`) LEFT OUTER JOIN `order` `orders` ON (`orders`.`id`=`orders_orders`.`order_id`)  ORDER BY id DESC LIMIT 25.

2013/03/28 16:19:50 [error] [exception.CDbException] exception 'CDbException' with message 'CDbCommand не удалось исполнить SQL-запрос: SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in order clause is ambiguous' in E:\OpenServer\domains\notes.rf\framework\db\CDbCommand.php:528



сейчас эти строчки просто закомментированы

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


ORDER BY t.id

в запросе.

Спасибо!

Получилось почти то что нужно. Вставил в метод search модели Note такой код:




$criteria->compare('orders.name', $this->assignedOrders, true);

$criteria->with = array('orders');

$criteria->together = true;



Фильтрует правильно, но есть такой "побочный эффект", пример:

В виде index выводятся такие записки (Note) с заказами (Order):




Наименование записки | № заказа(ов)

Записка 1            | 0245, 0264, 0234

Записка 2            | 0155, 0314

Записка 3            | 0445

Записка 4            | 0111, 0234



Если ввести в поле фильтра заказов 45, то выводится вот что:




Наименование записки | № заказа(ов)

Записка 1            | 0245

Записка 3            | 0445



а должно выводится вот так:




Наименование записки | № заказа(ов)

Записка 1            | 0245, 0264, 0234

Записка 3            | 0445



Как такое побороть?

В методе getRelatedOrderNames(), используя $this->orders, на данный момент вы берете только отфильтрованные orders.

Я бы вместо $this->orders или напрямую из базы выбирала необходимые данные; или через еще одно relation, которое не подверглось фильтрации; или любым как-нибудь обновила бы $this->orders содержать не отфильтрованные данные на момент вывода их в CGridView.

Не очень понял что и в каком месте нужно выбирать из БД. getRelatedOrderNames(), на сколько я понимаю, возвращает список всех order, привязанных к note, через запятую. Что значит на данный момент беру только отфильтрованные orders? Берутся все что привязаны или я не правильно вас понял.

Вы не могли бы поподробнее рассказать как это сделать?

По всей видимости (это умозаключение, не проверенное на практике), на тот момент, когда вы вызываете getRelatedOrderNames(), $this->orders содержит только записи, соответсвующие критерию


$criteria->compare('order_id',$this->assignedOrders)

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

Чтобы обойти эту проблему, можно сделать так, например




public function getRelatedOrderNames ()

{

    return implode(', ', CHtml::listData(Order::model()->findAll($criteriaToSelectOnlyRelatedOrders), 'id', 'name'));

}



или




public function getRelatedOrderNames ()

{

    return implode(', ', CHtml::listData($this->oneMoreOrdersRelation, 'id', 'name'));

}



Заменил метод getRelatedOrderNames таким:




    public function getRelatedOrderNames()

    {

        $query = "

		SELECT name

		FROM `order`

		WHERE id IN(SELECT order_id FROM order_note WHERE note_id = :note_id)";


        $command = Yii::app()->db->createCommand($query);

	$command->bindParam(':note_id', $this->id, PDO::PARAM_INT);


        return implode(', ', $command->queryColumn());

    }



Все заработало. Спасибо большое Вам за помощь!

Отлично :)