Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 04.02.2013 18:27:37

Ikeaboy
Откуда: Киев
Сообщений: 28

Непонятное поведение при копировании экземпляра запроса

Добрый день, объясните пожалуйста данное поведение:

PHP
$items Item::where('some''='1);
$items->get();

Вернет ~много~ записей.

PHP
$items Item::where('some''='1);
$items->take(10);
$items->get();

Вернет 10 записей.

Почему,

PHP
$items Item::where('some''='1);
$things = clone $items;
$things->take(10);
$items->get();

вернет 10 записей? Я ведь установил лимит $things, а не $items. Заранее спасибо!

Не в сети

#2 04.02.2013 18:44:15

Re: Непонятное поведение при копировании экземпляра запроса

По всей видимости ты используешь Eloquent (PHPItem Laravel\Database\Eloquent\Model). Когда ты начинаешь запрос (PHP::where()) ты получаешь объект класса PHPLaravel\Database\Eloquent\Query — это обёртка над PHPLaravel\Database\Query. Соответственно, при клонировании ты клонируешь обёртку, но её поля PHP$model (здесь — PHPItem) и PHP$table (тот самый PHPQuery) остаются старыми. Когда ты делаешь PHPtake(10) ты изменяешь именно объект внутри PHP$table, который и «переживает» клонирование. В итоге у тебя получается два объекта Query Eloquent, которые внутренне привязаны к одному запросу.

Могу посоветовать такой вариант:

PHP
$items Item::where('some''='1);
$things = clone $items;
$things->table = clone $things->table;
$things->take(10);
$items->get();

Хотя, конечно, лучше всего бы это исправить в ядре через PHP__clone(), чтобы не писать так каждый раз.

Не в сети

#3 04.02.2013 19:15:18

Ikeaboy
Откуда: Киев
Сообщений: 28

Re: Непонятное поведение при копировании экземпляра запроса

PHP
$things = clone $items;
$things->table = clone $things->table;

Это порнография, сами понимаете. В любом случае у меня PHPclass Model extends Eloquent, в ядро я стараюсь не лазить.

Но на для подстраховки уточню:

PHP
class Model extends Eloquent {

    function 
__clone() {
        
$this->table = clone $this->table;
    }

}

Это допустимая конструкция? Я ничего не перекрываю?

Спасибо большое за разъяснение архитектуры! Вы, должно быть, структуру наизусть знаете.

Не в сети

#4 04.02.2013 19:49:50

Re: Непонятное поведение при копировании экземпляра запроса

  1. Это порнография, сами понимаете.

Естественно. Поэтому вариант — или менять ядро (чего я избегаю всеми методами), или добавлять метод. Собственно, в данном случае последнее вполне возможно.

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

  1. Это допустимая конструкция? Я ничего не перекрываю?

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

Из-за архитектуры Eloquent вопрос решается двумя частями: нужно расширить класс запроса, но кроме этого — перекрыть метод в PHPEloquent (он же — PHPLaravel\Database\Eloquent\Model), который возвращает наш перекрытый объект запроса, а не стандартный PHPLaravel\Database\Eloquent\Query без PHP__clone.

PHP
class Model extends Eloquent {
  function 
query() {
    return new 
EloquentQueryEx($this);
  }
}

class 
EloquentQueryEx extends Laravel\Database\Eloquent\Query {
  function 
__clone() {
    
$this->table = clone $this->table;
  }
}

Не в сети

#5 05.02.2013 13:18:19

Ikeaboy
Откуда: Киев
Сообщений: 28

Re: Непонятное поведение при копировании экземпляра запроса

FACEPALM, прочитал все понял, и написал глупость. Прошу прощения, был вечер. Единственное уточнение, что бы не заморачиваться с длинными именами свой класс назвал просто Query, в application.php/aliases это имя свободно, так что, думаю, проблем не будет. Правильно?

PHP
class Query extends Laravel\Database\Eloquent\Query {
    function 
__clone() {
        
$this->table = clone $this->table;
    }
}

Еще раз спасибо!

Не в сети

#6 05.02.2013 13:54:39

Re: Непонятное поведение при копировании экземпляра запроса

Да, можно убрать алиас и сделать свой класс. Моё имя было просто примером, так как я не знал, пишешь ли ты пакет или приложение.

Не в сети

Подвал раздела