Skip to content

Instantly share code, notes, and snippets.

@broiniac
Created March 30, 2015 13:22
Show Gist options
  • Save broiniac/17a4338e577ccbe9e090 to your computer and use it in GitHub Desktop.
Save broiniac/17a4338e577ccbe9e090 to your computer and use it in GitHub Desktop.
Doctrine - example search miniengine - Polish comments
/**
* Filter application via given parameters.
*
* @param QueryBuilder $qb
* @param array $data
*
* @return QueryBuilder $qb filtered results
*/
public function filter($qb, $data = []) {
$qb->leftJoin('a.experiences', 'ae') // dołączam referencje (relacje), po których też będę szukał
->leftJoin('ae.job', 'j')
->leftJoin('a.languages', 'al')
;
// empty() sprawdza, czy coś niesie ze sobą jakąś wartość
// jeżeli coś takiego jak $data['nazwa pola']
// 1. nie istnieje (pole w wyszukiwarce zostało niewypełnione)
// 2. przyszło puste (w przypadku niektórych pól przychodzi pusty ciąg znaków)
//#notice poniżej "zaawansowany" QueryBuilder (korzystanie z wyrażeń pomocniczych expr)
// tutaj szukamy w danych personalnych
if (!empty($data['text'])) {
$qb->andWhere( //i gdzie
$qb->expr()->orX( //pasujące jest którekolwiek z poniższych wyrażeń
$qb->expr()->like( //w polu firstname występuje podany ciąg znaków
'a.firstname',
$qb->expr()->literal('%'.$data['text'].'%')
),
$qb->expr()->like( //LUB w polu lastname występuje podany ciąg znaków
'a.lastname',
$qb->expr()->literal('%'.$data['text'].'%')
),
$qb->expr()->like( //LUB itd...
'a.email',
$qb->expr()->literal('%'.$data['text'].'%')
),
$qb->expr()->like(
'a.phone',
$qb->expr()->literal('%'.$data['text'].'%')
),
$qb->expr()->like(
'a.hobby',
$qb->expr()->literal('%'.$data['text'].'%')
),
$qb->expr()->like(
'a.additional',
$qb->expr()->literal('%'.$data['text'].'%')
)
)
);
}
//to samo co powyżej, ale dla danych adresowych
if (!empty($data['address'])) {
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->like(
'a.street',
$qb->expr()->literal('%'.$data['address'].'%')
),
$qb->expr()->like(
'a.number',
$qb->expr()->literal('%'.$data['address'].'%')
),
$qb->expr()->like(
'a.city',
$qb->expr()->literal('%'.$data['address'].'%')
),
$qb->expr()->like(
'a.zipCode',
$qb->expr()->literal('%'.$data['address'].'%')
),
$qb->expr()->like(
'a.zipCity',
$qb->expr()->literal('%'.$data['address'].'%')
),
$qb->expr()->like(
'a.country',
$qb->expr()->literal('%'.$data['address'].'%')
)
)
);
}
// przykład szukania w referencjach (prymitywny)
// w polu formularza 'jobs' można było wybrać wiele 'zawodów'
// Do akcji indexującej przychodziła wtedy tablica:
// [
// 0 => 'pierwsze id',
// 1 => 'drugie id',
// n => 'n-te id'
// ],
// gdzie id-ki są oczywiście liczbami całkowitymi.
// Poniżej przykład jak obsłużyłem wyszukiwanie
if (!empty($data['jobs'])) {
$qb->andWhere(
// korzystam z expr->in(), który sprawdza,
// czy lewy argument znajduje się w tablicy (prawy argument)
$qb->expr()->in('j.id', $data['jobs'])
);
}
//tutaj przykład wyszukiwania po wieku (przychodzi liczba całkowita)
if (!empty($data['age_min'])) {
// do $ageMin wsadzam rok, w który "trafia" dany wiek. Czyli obecny czas minus wiek, który przyszedł
$ageMin = new \DateTime("-" . $data['age_min'] . "years");
$qb->andWhere(
//lte - lesser then equal - mniejsze lub równe (nie wiem kto to wymyślał)
// HERE BE DRAGONS:
// baza danych potrafi sprawdzać, który ciąg znaków jest większy.
// porównuję więc dwa ciągi znaków - data w bazie z moją datą
// Nie lubię takich zabiegów. IMHO są "brudne". Ale skuteczne.
$qb->expr()->lte(
'a.birthday', //pole, które sprawdzam
$qb->expr()->literal( //W bazie siedzi data jako string, np "1991-01-22"
$ageMin->format('Y-m-d') //formatuję więc mój wyliczony rok do tego formatu. Resztą zajmuje się expr()->lte()
)
)
);
}
//to co wyżej, ale "górny przedział"
if (!empty($data['age_max'])) {
$ageMax = new \DateTime("-" . $data['age_max'] . "years");
$qb->andWhere(
$qb->expr()->gte(
'a.birthday',
$qb->expr()->literal(
$ageMax->format('Y-m-d')
)
)
);
}
// tutaj natomiast porównuję już dwie daty, więc nie muszę niczego wyliczać
if (!empty($data['birthday_min'])) {
$qb->andWhere(
$qb->expr()->gte( // gte - greater then equal - większe lub równe
'a.birthday',
//trochę "chojraczenie", ale mam pewność, że to co przychodzi ma odpowiedni format (walidacja mi to zapewnia),
// więc odważam się wrzucić to bezpośrednio do bazy danych
$qb->expr()->literal($data['birthday_min'])
)
);
}
if (!empty($data['birthday_max'])) {
$qb->andWhere(
$qb->expr()->lte(
'a.birthday',
$qb->expr()->literal($data['birthday_max'])
)
);
}
if (!empty($data['price_min'])) {
$qb->andWhere(
$qb->expr()->gte(
'a.price',
$data['price_min']
)
);
}
if (!empty($data['price_max'])) {
$qb->andWhere(
$qb->expr()->lte(
'a.price',
$data['price_max']
)
);
}
if (!empty($data['readyAt_min'])) {
$qb->andWhere(
$qb->expr()->gte(
'a.readyAt',
$qb->expr()->literal($data['readyAt_min'])
)
);
}
if (!empty($data['readyAt_max'])) {
$qb->andWhere(
$qb->expr()->lte(
'a.readyAt',
$qb->expr()->literal($data['readyAt_max'])
)
);
}
// Tutaj 'brudny' sposób - ale szybki i skuteczny
// jeżeli coś przyszło i nie jest to równe 0 (istotny warunek)...
if (!empty($data['work_type']) && $data['work_type'] != 0) {
// to jeżeli to 1, to szukaj tylko w encjach, gdzie pole seasonalWork posiada wartość true
// a pole fullWork ma false
if ($data['work_type'] == 1) {
$qb->andWhere('a.seasonalWork = :true')
->andWhere('a.fullWork = :false')
;
// jeżeli natomiast przyszło 2, to...
} else if ($data['work_type'] == 2) {
$qb->andWhere('a.seasonalWork = :false')
->andWhere('a.fullWork = :true')
;
}
// dlaczego tutaj? bo zawsze jeśli wejdzie do środka tego ifa, to
// będę potrzebował zmiennych :true i :false
$qb->setParameter('true', 1)
->setParameter('false', 0)
;
}
//ok, ale czemu wykluczyłem 0? Bo w formularzu wyświetla mi się coś takiego:
// 0 => wszystkie oferty pracy
// 1 => TYLKO oferty pracy dorywszej
// 2 => TYLKO oferty pracy stałej
// w bazie danych siedzi 0 lub 1. Więc to, co przyszło z formularza szukania
// wsadzam od razu do QueryBuildera (przez setParameter)
if (!empty($data['local'])) {
$qb->andWhere('a.local = :local')
->setParameter('local', $data['local'])
;
}
if (!empty($data['abroad'])) {
$qb->andWhere('a.abroad = :abroad')
->setParameter('abroad', $data['abroad'])
;
}
// tutaj nie korzystam z empty(), tylko z
// isset oraz != ''
// Czemu? Bo tak też można.
if (isset($data['status']) && $data['status'] != '') {
$qb->andWhere('a.status = :status')
->setParameter('status', $data['status'])
;
}
//zrobiłem wszystko - zwracam $qb.
// później $qb jest przekazywany do metody paginującej, która sortuje wyniki,
// a później wylicza odpowiednią stronę do wyświetlenia (co za tym idzie "kroi" ilość wyników).
return $qb;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment