Cherrycake examples version 1.x
Items iterate in a pattern
src/ItemsGuide/ItemsGuide.php
<?php

namespace CherrycakeApp\ItemsGuide;
use CherrycakeApp\Movie;
use CherrycakeApp\Movies;

class ItemsGuide extends \Cherrycake\Module {
    protected $dependentCoreModules = [
        "Database",
        "Patterns"
    ];

    public static function mapActions() {
        global $e;

        $e->Actions->mapAction(
            "itemsGuideBasicUsage",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "basicUsage",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "basic-usage"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideItemLists",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "itemLists",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "item-lists"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideIterate",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "iterate",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "iterate"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideIterateInPattern",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "iterateInPattern",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "iterate-in-pattern"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideCustomFilters",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "customFilters",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "custom-filters"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideCustomOrdering",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "customOrdering",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "custom-ordering"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideFiltersAndOrdering",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "filtersAndOrdering",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "filters-and-ordering"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideRelationships",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "relationships",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "relationships"
                        ])
                    ]
                ])
            ])
        );

        $e->Actions->mapAction(
            "itemsGuideFiltersWithRelationships",
            new \Cherrycake\Actions\ActionHtml([
                "moduleType" => \Cherrycake\ACTION_MODULE_TYPE_APP,
                "moduleName" => "ItemsGuide",
                "methodName" => "filtersWithRelationships",
                "request" => new \Cherrycake\Actions\Request([
                    "pathComponents" => [
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "items-guide"
                        ]),
                        new \Cherrycake\Actions\RequestPathComponent([
                            "type" => \Cherrycake\REQUEST_PATH_COMPONENT_TYPE_FIXED,
                            "string" => "filters-with-relationships"
                        ])
                    ]
                ])
            ])
        );
    }

    function basicUsage() {
        global $e;

        $movie = new Movie([
            "loadMethod" => "fromId",
            "id" => 15
        ]);

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "
                <html><body>
                    {$movie->title} ({$movie->year})
                </body></html>
            "
        ]));
    }

    function itemLists() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters"
        ]);

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "
                <html><body>
                    {$movies->count()} Movies found
                </body></html>
            "
        ]));
    }

    function iterate() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters"
        ]);

        $html = "";
        foreach ($movies as $movie)
            $html .= "{$movie->title} ({$movie->year})<br>";

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "<html><body>$html</body></html>"
        ]));
    }

    function iterateInPattern() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters",
            "p" => [
                "limit" => 5
            ]
        ]);

        $e->Patterns->out("ItemsGuide/IterateInPattern.html", [
            "variables" => [
                "movies" => $movies
            ]
        ]);
    }

    function customFilters() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters",
            "p" => [
                "year" => 1968
            ]
        ]);

        $html = "";
        foreach ($movies as $movie)
            $html .= "{$movie->title} ({$movie->year})<br>";

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "<html><body>$html</body></html>"
        ]));
    }

    function customOrdering() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters",
            "p" => [
                "order" => ["released"]
            ]
        ]);

        $html = "";
        foreach ($movies as $movie)
            $html .= "{$movie->title} ({$movie->year})<br>";

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "<html><body>$html</body></html>"
        ]));
    }

    function filtersAndOrdering() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters",
            "p" => [
                "minYear" => 1980,
                "maxYear" => 1989,
                "order" => ["released", "title"]
            ]
        ]);

        $html = "";
        foreach ($movies as $movie)
            $html .= "{$movie->title} ({$movie->year})<br>";

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "<html><body>$html</body></html>"
        ]));
    }

    function relationships() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters",
            "p" => [
                "limit" => 5,
                "order" => ["random"]
            ]
        ]);

        $html = "";
        foreach ($movies as $movie)
            $html .= "{$movie->title} directed by {$movie->getDirector()->name}<br>";

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "<html><body>$html</body></html>"
        ]));
    }

    function filtersWithRelationships() {
        global $e;

        $movies = new Movies([
            "fillMethod" => "fromParameters",
            "p" => [
                "releasedWhenDirectorWasYoungerThan" => 35
            ]
        ]);

        $html = "";
        foreach ($movies as $movie)
            $html .=
                "\"{$movie->title}\"".
                " directed by ".
                $movie->getDirector()->name.
                " at age ".
                ($movie->year - $movie->getDirector()->birthYear).
                "<br>";

        $e->Output->setResponse(new \Cherrycake\Actions\ResponseTextHtml([
            "code" => \Cherrycake\Output\RESPONSE_OK,
            "payload" => "<html><body>$html</body></html>"
        ]));
    }
}
src/Movies.php
<?php

namespace CherrycakeApp;

class Movies extends \Cherrycake\Items {
    protected $tableName = "movies";
    protected $itemClassName = "\CherrycakeApp\Movie";

    function fillFromParameters($p = false) {
        // Treat parameters
        self::treatParameters($p, [
            "year" => ["default" => false],
            "releasedWhenDirectorWasYoungerThan" => [
                "default" => false
            ],
            "minYear" => ["default" => false],
            "maxYear" => ["default" => false],
            "title" => ["default" => false],
            "orders" => ["addArrayKeysIfNotExist" => [
                "released" => "movies.year asc",
                "title" => "movies.title asc"
            ]]
        ]);

        // Modify $p accordingly
        if ($p["year"]) {
            $p["wheres"][] = [
                "sqlPart" => "movies.year = ?",
                "values" => [
                    [
                        "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_INTEGER,
                        "value" => $p["year"]
                    ]
                ]
            ];
        }

        if ($p["releasedWhenDirectorWasYoungerThan"]) {
            $p["tables"][] = "directors";
            $p["wheres"][] = ["sqlPart" => "directors.id = movies.directorId"];
            $p["wheres"][] = [
                "sqlPart" => "movies.year - directors.birthYear <= ?",
                "values" => [
                    [
                        "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_INTEGER,
                        "value" => $p["releasedWhenDirectorWasYoungerThan"]
                    ]
                ]
            ];
        }

        if ($p["minYear"]) {
            $p["wheres"][] = [
                "sqlPart" => "movies.year >= ?",
                "values" => [
                    [
                        "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_INTEGER,
                        "value" => $p["minYear"]
                    ]
                ]
            ];
        }

        if ($p["maxYear"]) {
            $p["wheres"][] = [
                "sqlPart" => "movies.year <= ?",
                "values" => [
                    [
                        "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_INTEGER,
                        "value" => $p["maxYear"]
                    ]
                ]
            ];
        }

        if ($p["title"]) {
            $p["wheres"][] = [
                "sqlPart" => "movies.title like ?",
                "values" => [
                    [
                        "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_STRING,
                        "value" => "%".$p["title"]."%"
                    ]
                ]
            ];
        }

        // Call the parent fillFromParameters
        return parent::fillFromParameters($p);
    }
}
src/Movie.php
<?php

namespace CherrycakeApp;

class Movie extends \Cherrycake\Item {
    protected $tableName = "movies";
    protected $fields = [
        "id" => [
            "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_INTEGER
        ],
        "title" => [
            "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_STRING
        ],
        "summary" => [
            "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_TEXT
        ],
        "year" => [
            "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_YEAR
        ],
        "imdbRating" => [
            "type" => \Cherrycake\Database\DATABASE_FIELD_TYPE_FLOAT
        ]
    ];

    function getDirector() {
        return new Director([
            "loadMethod" => "fromId",
            "id" => $this->directorId
        ]);
    }

    function updateImdbRating() {
    }
}
patterns/ItemsGuide/IterateInPattern.html
<html><body>

    <ul>
        <?php foreach ($movies as $movie) { ?>
            <li><?=$movie->title?> (<?=$movie->year?>)</li>
        <?php } ?>
    </ul>
    
</body></html>
/items-guide/iterate-in-pattern