2014-10-29 2 views
0

Я хочу создать автоматический querybuilder, который принимает параметры из url в контроллере и передает его в мой репозиторий.Laravel automatic querybuilder от url

Теперь у меня есть набор ключей/фильтров, которые запрос может использовать для построения предложения where, он соответствует ключам к параметрам в URL-адресе и работает. Пока я использую только 1 ключ.

если я f.e. do:

".../api/v1/companies?is_accountant=0" -->WORKS 
".../api/v1/companies?is_accountant=0&name=test&street=testLane -->FAILS, returns empty 

Запись существует в моей БД, но она возвращает пустой объект. Если я попытаюсь разобраться с 1 ключом, он найдет запись

Может ли кто-нибудь выявить проблему?

private $filters = ['id','street','name','is_accountant','nr_ext','postal_code']; 

    public function getCompaniesFilterd($params, $limit) 
    { 
     if (!empty($params)) { 
      $query = Company::query(); 

      foreach($params as $param) 
      { 
       foreach($this->filters as $filter) 
       { 
        if(key($params) == $filter) 
        { 
         $query->where($filter,'=',$param); 
        } 
       } 
      } 
         $companies = $query->get(); 
      dd($query); 
      return $companies; 
     } 

     return Company::take(10)->get(); 
    } 

выход

{ 
"data": [] 
} 

Запрос дамп

object(Illuminate\Database\Eloquent\Builder)[222] 
    protected 'query' => 
    object(Illuminate\Database\Query\Builder)[221] 
     protected 'connection' => 
     object(Illuminate\Database\MySqlConnection)[212] 
      protected 'pdo' => 
      object(PDO)[181] 
       ... 
      protected 'readPdo' => null 
      protected 'reconnector' => 
      object(Closure)[220] 
       ... 
      protected 'queryGrammar' => 
      object(Illuminate\Database\Query\Grammars\MySqlGrammar)[211] 
       ... 
      protected 'schemaGrammar' => null 
      protected 'postProcessor' => 
      object(Illuminate\Database\Query\Processors\MySqlProcessor)[214] 
       ... 
      protected 'events' => 
      object(Illuminate\Events\Dispatcher)[14] 
       ... 
      protected 'paginator' => 
      object(Closure)[219] 
       ... 
      protected 'cache' => 
      object(Closure)[218] 
       ... 
      protected 'fetchMode' => int 8 
      protected 'transactions' => int 0 
      protected 'queryLog' => 
      array (size=1) 
       ... 
      protected 'loggingQueries' => boolean true 
      protected 'pretending' => boolean false 
      protected 'database' => string 'homestead' (length=9) 
      protected 'tablePrefix' => string '' (length=0) 
      protected 'config' => 
      array (size=9) 
       ... 
     protected 'grammar' => 
     object(Illuminate\Database\Query\Grammars\MySqlGrammar)[211] 
      protected 'selectComponents' => 
      array (size=11) 
       ... 
      protected 'tablePrefix' => string '' (length=0) 
     protected 'processor' => 
     object(Illuminate\Database\Query\Processors\MySqlProcessor)[214] 
     protected 'bindings' => 
     array (size=5) 
      'select' => 
      array (size=0) 
       ... 
      'join' => 
      array (size=0) 
       ... 
      'where' => 
      array (size=3) 
       ... 
      'having' => 
      array (size=0) 
       ... 
      'order' => 
      array (size=0) 
       ... 
     public 'aggregate' => null 
     public 'columns' => 
     array (size=1) 
      0 => string '*' (length=1) 
     public 'distinct' => boolean false 
     public 'from' => string 'companies' (length=9) 
     public 'joins' => null 
     public 'wheres' => 
     array (size=3) 
      0 => 
      array (size=5) 
       ... 
      1 => 
      array (size=5) 
       ... 
      2 => 
      array (size=5) 
       ... 
     public 'groups' => null 
     public 'havings' => null 
     public 'orders' => null 
     public 'limit' => null 
     public 'offset' => null 
     public 'unions' => null 
     public 'lock' => null 
     protected 'backups' => 
     array (size=0) 
      empty 
     protected 'cacheKey' => null 
     protected 'cacheMinutes' => null 
     protected 'cacheTags' => null 
     protected 'cacheDriver' => null 
     protected 'operators' => 
     array (size=19) 
      0 => string '=' (length=1) 
      1 => string '<' (length=1) 
      2 => string '>' (length=1) 
      3 => string '<=' (length=2) 
      4 => string '>=' (length=2) 
      5 => string '<>' (length=2) 
      6 => string '!=' (length=2) 
      7 => string 'like' (length=4) 
      8 => string 'not like' (length=8) 
      9 => string 'between' (length=7) 
      10 => string 'ilike' (length=5) 
      11 => string '&' (length=1) 
      12 => string '|' (length=1) 
      13 => string '^' (length=1) 
      14 => string '<<' (length=2) 
      15 => string '>>' (length=2) 
      16 => string 'rlike' (length=5) 
      17 => string 'regexp' (length=6) 
      18 => string 'not regexp' (length=10) 
    protected 'model' => 
    object(Winbooks\Core\Models\Company)[213] 
     protected 'table' => string 'companies' (length=9) 
     protected 'fillable' => 
     array (size=10) 
      0 => string 'name' (length=4) 
      1 => string 'street' (length=6) 
      2 => string 'nr_ext' (length=6) 
      3 => string 'postal_code' (length=11) 
      4 => string 'city' (length=4) 
      5 => string 'phone' (length=5) 
      6 => string 'fax' (length=3) 
      7 => string 'email' (length=5) 
      8 => string 'is_accountant' (length=13) 
      9 => string 'country_id' (length=10) 
     protected 'connection' => null 
     protected 'primaryKey' => string 'id' (length=2) 
     protected 'perPage' => int 15 
     public 'incrementing' => boolean true 
     public 'timestamps' => boolean true 
     protected 'attributes' => 
     array (size=0) 
      empty 
     protected 'original' => 
     array (size=0) 
      empty 
     protected 'relations' => 
     array (size=0) 
      empty 
     protected 'hidden' => 
     array (size=0) 
      empty 
     protected 'visible' => 
     array (size=0) 
      empty 
     protected 'appends' => 
     array (size=0) 
      empty 
     protected 'guarded' => 
     array (size=1) 
      0 => string '*' (length=1) 
     protected 'dates' => 
     array (size=0) 
      empty 
     protected 'touches' => 
     array (size=0) 
      empty 
     protected 'observables' => 
     array (size=0) 
      empty 
     protected 'with' => 
     array (size=0) 
      empty 
     protected 'morphClass' => null 
     public 'exists' => boolean false 
    protected 'eagerLoad' => 
    array (size=0) 
     empty 
    protected 'macros' => 
    array (size=0) 
     empty 
    protected 'onDelete' => null 
    protected 'passthru' => 
    array (size=12) 
     0 => string 'toSql' (length=5) 
     1 => string 'lists' (length=5) 
     2 => string 'insert' (length=6) 
     3 => string 'insertGetId' (length=11) 
     4 => string 'pluck' (length=5) 
     5 => string 'count' (length=5) 
     6 => string 'min' (length=3) 
     7 => string 'max' (length=3) 
     8 => string 'avg' (length=3) 
     9 => string 'sum' (length=3) 
     10 => string 'exists' (length=6) 
     11 => string 'getBindings' (length=11) 
+2

Вы не должны ставить 'test' в кавычки, если запись базы данных не совсем так (' «кавычки» '). но это имя, вероятно, 'test', а не' 'test" '. – Quasdunk

+0

Это действительно проблема № 1. Пробовал ли он без кавычек, все еще не работает? – Nsmet

+0

Неудачно или возвращается пустым? эти две вещи НЕ совпадают. – itachi

ответ

0

я смог reporoduce это поведение с вашим кодом, но я не совсем уверен, что это вызвано. Ошибка состоит в том, что значения фильтра не изменяются, вероятно, существует какая-то странная проблема с циклами. Поэтому я хотел бы принять это как возможность немного переписать и улучшить свой код, так как я думаю, что Laravel позволяет использовать более элегантный способ сделать это.

private $filters = ['id','street','name','is_accountant','nr_ext','postal_code']; 

public function getCompaniesFiltered($params, $limit = 10) 
{ 
    $params = array_diff_key($params, $this->filters); 

    if(empty($params)) 
    { 
     return Company::take($limit)->get(); 
    } 

    return Company::where($params)->get(); 
} 

Просто позвонив по номеру getCompaniesFiltered(Input::all());, я работал отлично.

EDIT: Посмотрев немного поближе на петлях, я уверен, что проблема только одна дополнительная 's':

if(key($params) == $filter) 

должен быть

if(key($param) == $filter) 

if (1 == 'name') (или сравнение логических, строк и некоторых int) может привести к довольно странному поведению в PHP.


EDIT 2:

Примечание: Пожалуйста, не спрашивайте отдельный вопрос по той же теме. Несмотря на то, что они связаны между собой, они все еще разные вопросы, но вы должны дать тому, кто отвечает на них, чтобы получить кредит для обоих. Поскольку вы, похоже, новичок в StackOverflow, давайте просто оставим это на этом, но, пожалуйста, помните об этом в своих будущих вопросах.

В ansewers:

«Если я использовать предыдущее предложение он работал, но я только что заметил, что если вы ввели неверные параметры по-прежнему хочет, чтобы искать таблицу -> в результате чего Ошибка строки в таблице не найдена.«

Право, array_diff был не самый лучший выбор здесь, должно быть:

$params = array_intersect_key($params, array_flip($this->filters)) 

» Я пытаюсь запросить как и раньше, но теперь я также хочу, чтобы иметь возможность поставить Params на моих связанных моделей.»

Опять же, Laravel делает это очень легко с Eloquent-х eager loading concept. Класс может выглядеть так:

private $mainFilters = ['id', 'name', 'preview','user_id', 'date', 'status']; 
private $fileFilters = ['path', 'uuid']; 
private $invoicesFilters = ['due_date', 'payment_status', 'type']; 

public function getDocumentsFiltered($params, $limit = 10) 
{ 
    $dependencies = $this->getDependencies($params); 
    $documentParams = $this->filterParams($params, $this->mainFilters)); 

    $documents = Document::with($dependencies); 

    if(empty($documentParams)) 
    { 
     return $documents->take($limit)->get(); 
    } 

    return $docuemnts->where($documentParams)->get(); 
} 

protected function getDependencies($params) 
{ 
    $fileParams = $this->filterParams($params, $this->fileFilters)); 
    $invoiceParams = $this->filterParams($params, $this->invoiceFilters)); 

    return [ 
     'file' => function($query) use ($fileParams) { 
      $query->where($fileParams); 
     }, 

     'invoice' => function($query) use ($invoiceParams) { 
      $query->where($invoiceParams); 
     }, 

     'user', 
     'folder', 
    ]; 
} 

protected function filterParams($input, $filter) 
{ 
    return array_intersect_key($input, array_flip($filter); 
} 

Код не комментируется, но я думаю, что это в значительной степени объясняет сам.

+0

СПАСИБО! Ваше решение сработало. Что касается оператора if, ключевой метод ожидает, что массив будет задан. $ param - строка, так что это не сработает. СПАСИБО снова – Nsmet

+0

@Nsmet Хорошо, поэтому это был простой ассоциативный массив, а не вложенный массив. В этом случае, если вы хотите работать с ключом, вы можете извлечь его в инструкции foreach: 'foreach ($ params as $ param => $ value)', а затем 'if ($ param == $ filter) { $ query-> где ($ param, $ value)}; 'Это вызвало бы у вас много головной боли;) – Quasdunk

+0

У меня есть вопрос, похожий на один выше. Как я могу сделать предложение where с моими параметрами в базовых моделях? Полный вопрос ниже – Nsmet

0

@Quasdunk Ваш последний ответ был действительно лучшим выбором/ответом. Если я использую ваше предыдущее предложение, это сработало, но я просто заметил, что если вы введете неправильный параметр, все равно хотите выполнить поиск в таблице -> в результате чего строка ошибок в таблице не найдена.

Это мой окончательный код

private $filters = ['id', 'name', 'date', 'status']; 

public function getDocumentListFilterd($params, $limit = 10) 
{ 

    if (!empty($params)) { 
     $query = Document::query(); 

     foreach($params as $param => $value) 
     { 

      foreach($this->filters as $filter) 
      { 

       if($param == $filter) 
       { 
        $query->where($filter,'=',$value); 
       } 
      } 
     } 
     $documents = $query->get(); 
     //dd($query); 
     return $documents; 
    } 

    return Company::take(10)->get(); 

} 
+0

Я отредактировал свой ответ соответственно, но еще раз примечание: Пожалуйста, не задавайте несколько вопросов в одном вопросительном потоке и не используйте ответы для обсуждения или задавайте другие вопросы. Каждый вопрос следует задавать отдельно, даже если они связаны друг с другом, они представляют разные проблемы. – Quasdunk