-
-
Notifications
You must be signed in to change notification settings - Fork 282
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
3,655 additions
and
3,638 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
Всичко, което винаги сте искали да знаете за {iterateWhile} | ||
*********************************************************** | ||
|
||
.[perex] | ||
Тагът `{iterateWhile}` е подходящ за различни трикове в цикли foreach. | ||
|
||
Да предположим, че имаме следната таблица в базата данни, в която елементите са разделени на категории: | ||
|
||
| id | categoryId | name | ||
|------------------ | ||
| 1 | 1 | Apple | ||
| 2 | 1 | Banana | ||
| 3 | 2 | PHP | ||
| 4 | 3 | Green | ||
| 5 | 3 | Red | ||
| 6 | 3 | Blue | ||
|
||
Разбира се, много е лесно да изведете елементите в цикъла foreach като списък: | ||
|
||
```latte | ||
<ul> | ||
{foreach $items as $item} | ||
<li>{$item->name}</li> | ||
{/foreach} | ||
</ul> | ||
``` | ||
|
||
Но какво да направите, ако искате да изведете всяка категория като отделен списък? С други думи, как се решава проблемът с групирането на елементи от линеен списък в цикъл foreach. Резултатът трябва да изглежда така: | ||
|
||
```latte | ||
<ul> | ||
<li>Apple</li> | ||
<li>Banana</li> | ||
</ul> | ||
|
||
<ul> | ||
<li>PHP</li> | ||
</ul> | ||
|
||
<ul> | ||
<li>Green</li> | ||
<li>Red</li> | ||
<li>Blue</li> | ||
</ul> | ||
``` | ||
|
||
Ще ви покажем как да решите този проблем лесно и елегантно с помощта на iterateWhile: | ||
|
||
```latte | ||
{foreach $items as $item} | ||
<ul> | ||
{iterateWhile} | ||
<li>{$item->name}</li> | ||
{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId} | ||
</ul> | ||
{/foreach} | ||
``` | ||
|
||
Докато `{foreach}` се отнася до външната част на цикъла, т.е. изготвянето на списъци за всяка категория, таговете `{iterateWhile}` се отнасят до вътрешната част, т.е. отделните елементи. | ||
Условието в крайния таг гласи, че повторението ще продължи, докато текущият и следващият елемент принадлежат към една и съща категория (`$iterator->nextValue` - [следващ елемент |/tags#iterator]). | ||
|
||
Ако условието е винаги изпълнено, всички елементи се изтеглят във вътрешния цикъл: | ||
|
||
```latte | ||
{foreach $items as $item} | ||
<ul> | ||
{iterateWhile} | ||
<li>{$item->name} | ||
{/iterateWhile true} | ||
</ul> | ||
{/foreach} | ||
``` | ||
|
||
Резултатът ще изглежда по следния начин: | ||
|
||
```latte | ||
<ul> | ||
<li>Apple</li> | ||
<li>Banana</li> | ||
<li>PHP</li> | ||
<li>Green</li> | ||
<li>Red</li> | ||
<li>Blue</li> | ||
</ul> | ||
``` | ||
|
||
Как е полезно да се използва iterateWhile по този начин? По какво се различава от решението, което показахме в началото на това ръководство? Разликата е, че ако таблицата е празна и не съдържа елементи, тя няма да се изведе празна `<ul></ul>`. | ||
|
||
|
||
Решение без `{iterateWhile}` .[#toc-solution-without-iteratewhile] | ||
------------------------------------------------------------------ | ||
|
||
Ако трябва да решим същия проблем, като използваме напълно елементарни шаблони, например в Twig, Blade или чист PHP, решението би изглеждало по следния начин | ||
|
||
```latte | ||
{var $prevCategoryId = null} | ||
{foreach $items as $item} | ||
{if $item->categoryId !== $prevCategoryId} | ||
{* the category has changed *} | ||
|
||
{* we close the previous <ul>, if it is not the first item *} | ||
{if $prevCategoryId !== null} | ||
</ul> | ||
{/if} | ||
|
||
{* we will open a new list *} | ||
<ul> | ||
|
||
{do $prevCategoryId = $item->categoryId} | ||
{/if} | ||
|
||
<li>{$item->name}</li> | ||
{/foreach} | ||
|
||
{if $prevCategoryId !== null} | ||
{* we close the last list *} | ||
</ul> | ||
{/if} | ||
``` | ||
|
||
Този код обаче е неразбираем и неинтуитивен. Връзката между началния и крайния HTML таг не е съвсем ясна. От пръв поглед не е ясно дали има грешка. А това изисква помощни променливи като `$prevCategoryId`. | ||
|
||
За разлика от това решението с `{iterateWhile}` е чисто, ясно, не изисква помощни променливи и е надеждно. | ||
|
||
|
||
Условие в затварящия таг .[#toc-condition-in-the-closing-tag] | ||
------------------------------------------------------------- | ||
|
||
Ако посочите условие в отварящия таг `{iterateWhile}`, поведението се променя: условието (и преходът към следващия елемент) се изпълнява в началото на вътрешния цикъл, а не в края. | ||
Така, докато `{iterateWhile}` без условие се въвежда винаги, `{iterateWhile $cond}` се въвежда само когато е изпълнено условието `$cond`. В същото време следващият елемент се записва в `$item`. | ||
|
||
Това е полезно например в ситуация, в която първият елемент във всяка категория трябва да се показва по различен начин, напр: | ||
|
||
```latte | ||
<h1>Apple</h1> | ||
<ul> | ||
<li>Banana</li> | ||
</ul> | ||
|
||
<h1>PHP</h1> | ||
<ul> | ||
</ul> | ||
|
||
<h1>Green</h1> | ||
<ul> | ||
<li>Red</li> | ||
<li>Blue</li> | ||
</ul> | ||
``` | ||
|
||
Променете изходния код, като визуализираме първия елемент и след това допълнителни елементи от същата категория във вътрешния цикъл `{iterateWhile}`: | ||
|
||
```latte | ||
{foreach $items as $item} | ||
<h1>{$item->name}</h1> | ||
<ul> | ||
{iterateWhile $item->categoryId === $iterator->nextValue->categoryId} | ||
<li>{$item->name}</li> | ||
{/iterateWhile} | ||
</ul> | ||
{/foreach} | ||
``` | ||
|
||
|
||
Вложени цикли .[#toc-nested-loops] | ||
---------------------------------- | ||
|
||
Можем да създадем няколко вътрешни цикъла в един цикъл и дори да ги вложим един в друг. По този начин например подкатегориите могат да бъдат групирани заедно. | ||
|
||
Да предположим, че в таблицата има още една колона `subcategoryId` и освен че всяка категория е в отделна колона, всяка подкатегория ще бъде в отделна колона. `<ul>`, всяка подкатегория ще бъде в отделна колона. `<ol>`: | ||
|
||
```latte | ||
{foreach $items as $item} | ||
<ul> | ||
{iterateWhile} | ||
<ol> | ||
{iterateWhile} | ||
<li>{$item->name} | ||
{/iterateWhile $item->subcategoryId === $iterator->nextValue->subcategoryId} | ||
</ol> | ||
{/iterateWhile $item->categoryId === $iterator->nextValue->categoryId} | ||
</ul> | ||
{/foreach} | ||
``` | ||
|
||
|
||
Филтриране | партида .[#toc-filter-batch] | ||
----------------------------------------- | ||
|
||
Групирането на елементите на реда се осигурява и от филтъра `batch`, в партида с фиксиран брой елементи: | ||
|
||
```latte | ||
<ul> | ||
{foreach ($items|batch:3) as $batch} | ||
{foreach $batch as $item} | ||
<li>{$item->name}</li> | ||
{/foreach} | ||
{/foreach} | ||
</ul> | ||
``` | ||
|
||
Тя може да бъде заменена с iterateWhile, както следва: | ||
|
||
```latte | ||
<ul> | ||
{foreach $items as $item} | ||
{iterateWhile} | ||
<li>{$item->name}</li> | ||
{/iterateWhile $iterator->counter0 % 3} | ||
{/foreach} | ||
</ul> | ||
``` | ||
|
||
{{leftbar: /@left-menu}} |
Oops, something went wrong.