GET /nl/product/panda-onesie-tiener
Call to a member function products() on null
page_product->render() shop.php:141
shop->section() app.php:113
shop() app.php:120
app->controller() functions.php:116
phlo() phlo.php:23
phlo_app() phlo.php:8
phlo_app_jsonfile() app.php:5
- <?php
- // source: /srv/shop/page.product.phlo
- // phlo: 1.0
- class page_product extends obj {
- public static function __handle(){
- return null;
- }
- public function render($product){
- $category = shop_category::record(cacheKey: cacheKey("prod:$product->id/cat"), joins: 'LEFT JOIN category_products p ON p.category=categories.id', where: 'p.product=?', product: $product->id, order: 'RAND()', limit: 1);
- $products = $category->products(limit: 5, order: 'RAND()');
- phlo('crumbs')->add($product->url, $product->title);
- main($this->view($product, $products), $product->title, crumb: true);
- }
- public function view($product, $products):string {
- $phloView = "<main id=\"product\" class=\"content\">\n".
- "\t".indentView(phlo('crumbs'))."\n".
- "\t<div class=\"container\">\n".
- "\t\t<div class=\"col\">\n".
- "\t\t\t<div class=\"product-image-container\">\n".
- "\t\t\t\t<div class=\"product-images\">\n";
- foreach ($product->images AS $image){
- $phloView .= "\t\t\t\t\t<img src=\"$image->thumbSrc\" alt=\"".esc($product->title)."\">\n";
- }
- $phloView .= "\t\t\t\t</div>\n".
- "\t\t\t\t<div id=\"product-image\" class=\"product-image\"><img src=\"".$product->image->src."\" alt=\"".esc($product->title)."\"></div>\n".
- "\t\t\t</div>\n".
- "\t\t</div>\n".
- "\t\t<div class=\"col\">\n".
- "\t\t\t<div class=\"product-data\">\n".
- "\t\t\t\t<h1>$product->title</h1>\n".
- "\t\t\t\t<div class=\"product-price\">".($product->priceOld ? '<span class="price-old">€ '.$product->priceOld.'</span>' : void)."€ $product->price</div>\n".
- "\t\t\t\t<div class=\"product-content-review\">".($product->reviews ? $this->rating($product->reviews) : void)."</div>\n".
- "\t\t\t\t<div class=\"size-helper-section\">\n".
- "\t\t\t\t\t<label>".nl('Kies je maat op lichaamslengte:')."</label>\n".
- "\t\t\t\t\t<div id=\"lengthButtons\" class=\"size-helper-buttons\">\n";
- foreach (sortVariants($product->variants) AS $variant){
- $phloView .= "\t\t\t\t\t\t<a class=\"async size-helper-btn\" href=\"/cart/$variant->id\">$variant->minBody-{$variant->maxBody}cm ($variant->size)</a>\n";
- }
- $phloView .= "\t\t\t\t\t</div>\n".
- "\t\t\t\t\t<div class=\"margin-top-15\"><a class=\"async size-chart-btn\" href=\"#sizeChart\" title=\"size-chart\"><img src=\"/images/size-chart.png\" alt=\"size-chart\" style=\"vertical-align:middle\"><span class=\"size-chart-txt margin-left-15\">".nl('Maattabel')."</span></a></div>\n".
- "\t\t\t\t</div>\n".
- "\t\t\t</div>\n".
- "\t\t\t<div class=\"usp\">\n".
- "\t\t\t\t<ul class=\"usp-list\">\n".
- "\t\t\t\t\t<li><i class=\"icon check\"></i>".nl('Werkdagen voor 20:00 besteld = 98% volgende dag bezorgd')."</li>\n".
- "\t\t\t\t\t<li><i class=\"icon check\"></i>".nl('Niet goed, geld terug.')."</li>\n".
- "\t\t\t\t\t<li><i class=\"icon check\"></i>".nl('Verzending naar NL, BE en DE €4,95.')."</li>\n".
- "\t\t\t\t\t<li><i class=\"icon check\"></i>".nl('Afrekenen zonder registratie.')."</li>\n".
- "\t\t\t\t\t<li><i class=\"icon check\"></i>".nl('Makkelijk en veilig bestellen via diverse betaalopties.')."</li>\n".
- "\t\t\t\t</ul>\n".
- "\t\t\t</div>\n".
- "\t\t</div>\n".
- "\t</div>\n".
- "\t<div class=\"container container-column\">\n".
- "\t\t<div class=\"col\">\n".
- "\t\t\t<h2>$product->title</h2>\n".
- "\t\t\t<p class=\"product-text\">".indent($product->text)."</p>\n".
- "\t\t\t<p><b>PRODUCTINFORMATIE:</b><br><br>Bij elk product komen hieronder enkele eigenschappen:<br><b>Stof:</b> 70% polyester, 30% katoen<br><b>Heeft zakken:</b> ja/nee<br><b>Sluiting:</b> (1)Rits/(2)Knopen/(3)Knopen voor en een horizontale rits achter voor gemakkelijke toiletbezoekjes<br><b>Wasinstructies:</b> 30 graden, niet in de droger.<br>Op basis van het type sluiting wordt hier automagisch getoond: <b>(1)</b> Onesies met rits dienen dichtgeritst te worden in de was OF <b>(2)</b> onesies met knopen dienen opengeknoopt gewassen te worden.</p>\n".
- "\t\t\t<div class=\"margin-top-15\"><a class=\"async size-chart-btn\" href=\"#sizeChart\" title=\"size-chart\"><img src=\"/images/size-chart.png\" alt=\"size-chart\" style=\"vertical-align:middle\"><span class=\"size-chart-txt margin-left-15\">".nl('Maattabel')."</span></a></div>\n".
- "\t\t</div>\n".
- "\t</div>\n".
- "\t<div class=\"container-xl\">\n".
- "\t\t<div class=\"product-container\">\n".
- "\t\t\t".indentView(loop($products, fn($product) => $product->view, lf), 3)."\n".
- "\t\t</div>\n".
- "\t</div>\n";
- if ($reviews = $product->reviews){
- $phloView .= "\t".indentView($this->reviews($reviews))."\n";
- }
- $phloView .= "</main>";
- return $phloView;
- }
- public function ratingValue($reviews){
- return array_sum(loop($reviews, fn($review) => $review->rating)) / count($reviews);
- }
- public function rating($reviews, $link = true):string {
- return "<p>".$this->ratingStars($this->ratingValue($reviews))." ".number_format($this->ratingValue($reviews), 1)." / 5.0 ".last($reviewCount = ($count = count($reviews)).space.nl('review'.($count === 1 ? void : 's')), $link ? '<a href="#reviews">'.$reviewCount.'</a>' : $reviewCount)."</p>";
- }
- public function ratingStars($rating){
- return loop(range(1, 5), fn($number) => $this->ratingStar($number > round($rating)), void);
- }
- public function ratingStar($blurred):string {
- return "<i class=\"icon star".($blurred ? '-blurred' : void)."\"></i>";
- }
- public function reviews($reviews):string {
- $phloView = "<div id=\"reviews\" class=\"container container-column\">\n".
- "\t<div class=\"col\">\n".
- "\t\t<h2>".nl('Reviews')."</h2>\n".
- "\t\t".indentView($this->rating($reviews, false), 2)."\n".
- "\t\t<div class=\"product-reviews\">\n";
- foreach ($reviews AS $review){
- $phloView .= "\t\t\t".indentView($this->review($review), 3)."\n";
- }
- $phloView .= "\t\t</div>\n".
- "\t</div>\n".
- "</div>";
- return $phloView;
- }
- public function review($review):string {
- $phloView = "<div class=\"product-review\">\n".
- "\t<div class=\"product-review-stars\">".$this->ratingStars($review->rating)."</div>\n".
- "\t<p>".esc($review->text)."</p>\n".
- "\t<ul class=\"product-review-list\">\n".
- "\t\t<li>".time_human($review->created)."</li>\n".
- "\t\t<li>$review->name</li>\n".
- "\t</ul>\n".
- "</div>";
- return $phloView;
- }
- }