Searching the gazette

Exercise 6 of 7 in chapter 6 · 150 XP · 5 objectives checked by tests

Topics covered: GET method$_GETQuery stringstr_contains()array_filter()

Odette can't find the article about the soup contest anymore, and she doesn't feel like going through every section. The gazette needs a search: a field in the masthead, and a page that displays the articles whose title contains the word typed.

Your mission

  1. In templates/mise-en-page.php, in the masthead, right under </nav>, add the form <form class="recherche" method="get" action="…">, which leads to /search (with Url::vers()). It contains an <input type="search" name="q"> field and a “Search” button.
  2. In Redaction, add a static method chercher(string $mot): array (search, $mot is the word), which returns the articles whose title contains $mot, in upper or lower case: “SOUP” finds the soup contest.
  3. Declare the /search route. The word arrives in $_GET['q']: just as for the ads, accept only a string, without the spaces around it. Only search if the word is not empty.
  4. Write the template templates/recherche.php (search) and display it in a page whose tab reads Search — The Saint-Glinglin Gazette:
    • without a word: <main class="lecture"> with <p class="aucun-resultat">Type a word to search for.</p>;
    • with a word: <h2 class="titre-rubrique">Search: “soup”</h2>, then <main class="articles"> with the articles found or, in their place inside that same <main>, <p class="aucun-resultat">No article mentions “soup”.</p> if there are none.

Léo is lying in wait: the searched word is displayed again on the page, so escape it.

Reminder

A form with method="get" does not put its fields in the body of the request, but in the address: /search?q=soup. PHP puts them in $_GET. It is the right choice for a search: the address of the results can be shared or bookmarked. For anything that changes something, like posting an ad, stick with POST.

str_contains($texte, $morceau) is true if $texte contains $morceau. To search regardless of upper case, put both strings in lower case before comparing: str_contains(mb_strtolower($titre), mb_strtolower($mot)). And to keep the matching articles, array_filter() and an arrow function do the job, just like for the table of contents (exercise 14).