2016-12-05 16 views
3

레시피와 관련 재료에 대한 검색 기능을 구현하고 싶습니다. 사용자는 검색에서 배제하려는 재료와 동시에 그가 찾고있는 조리법에 포함 된 재료를 지정해야합니다. 내가 전화 컨트롤러에서Cakephp3.1 : 동일한 관련 모델에 대해 동시에 matching() 및 notMatching() 사용

public function findByContainingIngredients(Query $query, array $params) 
{ 
    $ingredients = preg_replace('/\s+/', '', $params['containing_ingredients']); 

    if($ingredients) { 
     $ingredients = explode(',', $ingredients); 
     $query->distinct(['Recipes.id']); 
     $query->matching('Ingredients', function ($query) use($ingredients) { 
      return $query->where(function ($exp, $query) use($ingredients) { 
       return $exp->in('Ingredients.title', $ingredients); 
      }); 
     }); 
    } 
    return $query; 
} 


public function findByExcludingIngredients(Query $query, array $params) 
{ 
    $ingredients = preg_replace('/\s+/', '', $params['excluding_ingredients']); 

    if($ingredients) { 
     $ingredients = explode(',', $ingredients); 
     $query->distinct(['Recipes.id']); 
     $query->notMatching('Ingredients', function ($query) use ($ingredients) { 
      return $query->where(function ($exp, $query) use ($ingredients) { 
       return $exp->in('Ingredients.title', $ingredients); 
      }); 
     }); 

    } 
    return $query; 
} 

:

내 두 줍는있는 사용자가 검색에서 성분을 제외하고 그가 포함하고 싶어 하나 개 광석 개 성분을 지정

  $recipes = $this->Recipes->find() 
      ->find('byExcludingIngredients', $this->request->data) 
      ->find('byContainingIngredients', $this->request->data); 

경우 결과가 0입니다.

SELECT 
    Recipes.id AS `Recipes__id`, 
    Recipes.title AS `Recipes__title`, 
    ..... 

FROM 
    recipes Recipes 
    INNER JOIN ingredients Ingredients ON (
    Ingredients.title IN (: c0) 
    AND Ingredients.title IN (: c1) 
    AND Recipes.id = (Ingredients.recipe_id) 
) 
WHERE 
    (
    Recipes.title like '%%' 
    AND (Ingredients.id) IS NULL 
) 
GROUP BY 
    Recipes.id, 
    Recipes.id 

문제는 "AND (Ingredients.id가) NULL IS"내가 생성 된 SQL을 살펴 때 가 나는 문제를 참조하십시오. 이 선은 포함 된 재료의 결과를 사라지게합니다. 내 접근 방법 :

  • 회 협회에 notMatching()를 호출 할 때 별칭을 만들기. 나는 이것이 Cake3.1에서는 가능하지 않다고 생각한다.
  • PK/FK와 제외 된 타이틀에서 왼쪽 조인을 사용하고 별칭을 만드는 것이다. 기본적으로 내 자신의 notMatching 함수를 작성합니다. 이것은 효과가 있지만 옳은 생각은 아닙니다.

다른 해결책이 있습니까?

답변

1

해당 페이지로 와서 당신이 결합 할 수 없습니다 결론 matching()notMatching()에서 사용할 생각

네, 가능합니다 (어쨌든 Cake 3.4.9에서) 그런 찾기를 할 수 있습니다. 그러나 목표 테이블에 대해 다른 별명을 사용해야합니다. 이는 일반 클래스 이름과 다른 별명입니다.

public function initialize(array $config) { 
    ... usual stuff 

    $this->belongsToMany('Ingredients', [ 
     'foreignKey' => 'recipe_id', 
     'targetForeignKey' => 'ingredient_id', 
     'joinTable' => 'ingredients_recipes' 
    ]); 
    // the next association uses an alias, 
    // but is otherwise *exactly* the same as the previous assoc. 
    $this->belongsToMany('ExcludedIngredients', [ 
     'className' => 'Ingredients', 
     'foreignKey' => 'recipe_id', 
     'targetForeignKey' => 'ingredient_id', 
     'joinTable' => 'ingredients_recipes' 
    ]); 
} 

을 그리고 당신은이 같은 발견 문을 쓸 수 있어야 :

그래서 OP의 상황에서, 당신은 RecipesTable.php에 넣고 것

$this->find() 
    -> ... usual stuff 
    ->matching('Ingredients',function($q) use($okIngredients) { 
     ... check for ingredients ... 
    }) 
    ->notMatching('ExcludedIngredients', function($q) use($excludedIngredients) { 
     ... check for ingredients ... 
    }); 

작업을 수행합니다. 불행히도 수천 행의 내 'Recipes' 테이블에 비슷한 상황에서 사용하면 쿼리를 실행하는 데 40 초 정도 걸립니다. 그래서 돌아가서 어쨌든 notMatching()을 수제 조인으로 바꿔야했습니다.

1

은 당신이 무엇을 할 수 있는지 수동으로 다른 별명 (http://book.cakephp.org/3.0/en/orm/query-builder.html#adding-joins)와 함께 한 번 더 ingridients 테이블을 조인하고 일치/notMatching

사람으로
+1

일치하는/notMatching 함수는 첫 번째 매개 변수가 테이블 이름이나 별칭이 아닌 assoiciation의 이름이 될 것으로 예상합니다. 슬프게도, 이것은 작동하지 않습니다. – napolin