|
1 | 1 | ---
|
2 |
| -title: How it works |
| 2 | +title: Introduction to loops |
3 | 3 | ---
|
4 | 4 |
|
5 | 5 | Loops are the most convenient feature in Thelia for front developers. Already there in Thelia's first version, they deserved a makeover for Thelia v2.
|
@@ -211,3 +211,163 @@ List of output parameters :
|
211 | 211 | </ul>
|
212 | 212 | </div>
|
213 | 213 | ```
|
| 214 | + |
| 215 | + |
| 216 | +## Declare your loops |
| 217 | + |
| 218 | +```xml |
| 219 | +<loops> |
| 220 | + <loop name="mymodule_product" class="MyModule\Loop\Product" /> |
| 221 | + <loop name="mymodule_myloop" class="MyModule\Loop\MyLoop" /> |
| 222 | +</loops> |
| 223 | +``` |
| 224 | + |
| 225 | +You have to create as many loop node as loop you have into the loops node. In this example there is 2 loops. Name and |
| 226 | +class properties are mandatory. The name is the loop name used into the template ( like in Thelia v1 : ```<THELIA_name |
| 227 | +type="MyModule_Product">...</THELIA_name>```), class property is the class executed by the template engine. This |
| 228 | +class must extends the Thelia\Core\Template\Element\BaseLoop abstract class, if not an exception is thrown. |
| 229 | +**If you name your loop like a default loop (eg : product), your loop will replace the default loop.** |
| 230 | + |
| 231 | +## Implement your loops |
| 232 | + |
| 233 | +Your loop can be anywhere (Thanks to namespace) in your module but it's better to create a Loop directory and put all your loops in this directory. |
| 234 | + |
| 235 | +You have to extends the Thelia\Core\Template\Element\BaseLoop abstract class and implement either Thelia\Core\Template\Element\PropelSearchLoopInterface or Thelia\Core\Template\Element\ArraySearchLoopInterface. Therefore you will have to create *getArgDefinitions*, *parseResults* and either *buildModelCriteria* or *buildArray* methods. |
| 236 | + |
| 237 | +NB : You can also extend BaseI18nLoop which itself extends BaseLoop. This will provide tools to manage i18n in your loop. |
| 238 | + |
| 239 | +### What's the difference betwen *PropelSearchLoopInterface* and *ArraySearchLoopInterface* |
| 240 | + |
| 241 | +It's a matter of data type. If the data your loop returns come from the database you must implement *PropelSearchLoopInterface* and create *buildModelCriteria* method which return a *Propel\Runtime\ActiveQuery\ModelCriteria*. Conversely if your loop displays data from an array you must implement *ArraySearchLoopInterface* and create *buildArray* method which return an array. |
| 242 | + |
| 243 | +The *parseResults* method is used to render the template. It must return a Thelia\Core\Template\Element\LoopResult instance. |
| 244 | + |
| 245 | +The getArgDefinitions method defines all args used in your loop. Args can be mandatory, optional, with default value, etc. This method must return an Thelia\Core\Template\Loop\Argument\ArgumentCollection. ArgumentCollection contains Thelia\Core\Template\Loop\Argument which contains a Thelia\Type\TypeCollection. Types in the collection must implement Thelia\Type\TypeInterface. |
| 246 | + |
| 247 | +If you don't define your arguments here, you can't use them in your new loop. All arguments are accessible in the ```parseResults``` method. |
| 248 | + |
| 249 | +Baseloop class declares 3 public properties you might overload in your new loop. |
| 250 | + |
| 251 | +```php |
| 252 | +public $countable = true; |
| 253 | +public $timestampable = false; |
| 254 | +public $versionable = false; |
| 255 | +``` |
| 256 | + |
| 257 | +With these properties set to true, the loop will automatically render - or not - the following outputs : |
| 258 | + |
| 259 | +```php |
| 260 | +if($countable === true) |
| 261 | +``` |
| 262 | + |
| 263 | +* LOOP_COUNT |
| 264 | +* LOOP_TOTAL |
| 265 | + |
| 266 | +```php |
| 267 | +if($timestampable === true) //available if your table is timestampable |
| 268 | +``` |
| 269 | + |
| 270 | +* CREATE_DATE |
| 271 | +* CREATE_UPDATE |
| 272 | + |
| 273 | +### Example 1 |
| 274 | + |
| 275 | +Here an example for my module "MyModule" and my loops in the loop directory. This is the architecture : |
| 276 | + |
| 277 | + ``` |
| 278 | + \local |
| 279 | + \modules |
| 280 | + \MyModule |
| 281 | + ... |
| 282 | + \Loop |
| 283 | + MyLoop.php |
| 284 | + ``` |
| 285 | + |
| 286 | +MyLoop.php file : |
| 287 | + |
| 288 | + ```php |
| 289 | + namespace MyModule\Loop; |
| 290 | + |
| 291 | + use Thelia\Core\Template\Element\BaseLoop; |
| 292 | + use Thelia\Core\Template\Element\LoopResult; |
| 293 | + use Thelia\Core\Template\Element\LoopResultRow; |
| 294 | + use Thelia\Core\Template\Element\ArraySearchLoopInterface; |
| 295 | + use Thelia\Core\Template\Loop\Argument\ArgumentCollection; |
| 296 | + use Thelia\Core\Template\Loop\Argument\Argument; |
| 297 | + |
| 298 | + class MyLoop extends BaseLoop implements ArraySearchLoopInterface { |
| 299 | + |
| 300 | + public $countable = true; |
| 301 | + public $timestampable = false; |
| 302 | + public $versionable = false; |
| 303 | + |
| 304 | + public function getArgDefinitions() |
| 305 | + { |
| 306 | + return new ArgumentCollection( |
| 307 | + Argument::createIntListTypeArgument('start', 0), |
| 308 | + Argument::createIntListTypeArgument('stop', null, true) |
| 309 | + ); |
| 310 | + } |
| 311 | + |
| 312 | + public function buildArray() |
| 313 | + { |
| 314 | + $items = array(); |
| 315 | + |
| 316 | + $start = $this->getStart(); |
| 317 | + $stop = $this->getStop(); |
| 318 | + |
| 319 | + for($i=$start; $i<=$stop; $i++ { |
| 320 | + $items[] = $i; |
| 321 | + } |
| 322 | + |
| 323 | + return $items; |
| 324 | + |
| 325 | + } |
| 326 | + |
| 327 | + public function parseResults(LoopResult $loopResult) |
| 328 | + { |
| 329 | + foreach ($loopResult->getResultDataCollection() as $item) { |
| 330 | + |
| 331 | + $loopResultRow = new LoopResultRow(); |
| 332 | + |
| 333 | + $loopResultRow->set("MY_OUTPUT", $item); |
| 334 | + |
| 335 | + $loopResult->addRow($loopResultRow); |
| 336 | + } |
| 337 | + |
| 338 | + return $loopResult; |
| 339 | + } |
| 340 | + } |
| 341 | + |
| 342 | + ``` |
| 343 | + |
| 344 | +Of course you can use all classes you want in your own loop class, like model class. All Thelia's model classes are in the |
| 345 | +namespace Thelia\Model |
| 346 | + |
| 347 | +So if I want to add some search in my DB and return results from product table I can use something like this : |
| 348 | + |
| 349 | + ```php |
| 350 | +/** |
| 351 | +* |
| 352 | +* return Thelia\Core\Template\Element\LoopResult |
| 353 | +*/ |
| 354 | +public function buildModelCriteria() |
| 355 | +{ |
| 356 | + return ProductQuery::create(); |
| 357 | +} |
| 358 | + |
| 359 | +public function parseResults(LoopResult $loopResult) |
| 360 | +{ |
| 361 | + foreach ($loopResult->getResultDataCollection() as $product) { |
| 362 | + |
| 363 | + $loopResultRow = new LoopResultRow($product); |
| 364 | + |
| 365 | + $loopResultRow->set("REF", $product->getRef()); |
| 366 | + |
| 367 | + $loopResult->addRow($loopResultRow); |
| 368 | + } |
| 369 | + |
| 370 | + return $loopResult; |
| 371 | +} |
| 372 | +``` |
| 373 | + |
0 commit comments