LazyLoader
, (*1)
LazyLoader provides efficient mechanism for lazy loading with closures., (*2)
In LazyLoader one or more named closures can be defined. Any closure is called at most once when its output is needed., (*3)
Basic Usage
LazyLoader implements ArrayAccess, thus the easiest way how to use is like an associative array., (*4)
$lazy_loader = new LazyLoader();
// Setting up a closure,
$lazy_loader["recent_articles"] = function(){
return Article::FindAll(["order_by" => "published_at DESC", "limit" => 10]);
};
// ... another closure
$lazy_loader["top_product"] = function(){
return Product::FindFirst(["order_by" => "pieces_sold DESC"]);
}
// Reading - closure is being executed only during the first occurence of reading
if($lazy_loader["recent_articles"]){
foreach($lazy_loader["recent_articles"] as $article){
// ...
}
}
//
$top_product = $lazy_loader["top_product"];
There are total three ways how to set a closure or get its output. All of them do the same thing and can be mixed., (*5)
// Setting a closure
$lazy_loader->set("recent_articles",function(){ /* ... */ });
// or
$lazy_loader["recent_articles"] = function(){ /* ... */ };
// or
$lazy_loader->setRecentArticles(function(){ /* ... */ });
// Getting the output
$recent_articles = $lazy_loader->get("recent_articles");
// or
$recent_articles = $lazy_loader["recent_articles"];
// or
$recent_articles = $lazy_loader->getRecentArticles();
Also arguments can be involved. In this case the usage of camelized virtual methods comes in handy., (*6)
$lazy_loader->setRecentArticles(function($limit = 10){
return Article::FindAll(["order_by" => "published_at DESC", "limit" => $limit]);
});
$five_recent_articles = $lazy_loader->getRecentArticles(5);
Usage in a template engine
LazyLoader can be gracefully used in any template engine, for instance in the Smarty., (*7)
Preparing data for a Smarty template:, (*8)
$smarty->assign("lazy_loader",$lazy_loader);
In a Smarty template:, (*9)
<h3>Recent Articles</h3>
<ul>
{foreach $lazy_loader.recent_articles as $article}
<li><a href="{$article->getUrl()}">{$article->getTitle()}</a></li>
{/foreach}
</ul>
Usage in the ATK14 Framework
<?php
// file: app/controllers/application.php
class ApplicationController extends Atk14Controller {
// ..
function _before_render(){
$lazy_loader = new $lazy_loader;
$lazy_loader["recent_articles"] = function(){
return Article::FindAll(["order_by" => "published_at DESC", "limit" => 10]);
};
$this->tpl_data["lazy_loader"] = $lazy_loader;
}
}
Recent articles are displayed on every page in the sidebar. So caching is appropriate., (*10)
{* file: app/layouts/default.tpl *}
{cache key=sidebar expire=600}
<div class="sidebar">
{render partial="shared/recent_articles" recent_articles=$lazy_loader.recent_articles}
</div>
{/cache}
A shared template doesn't have to know anything about lazy loading., (*11)
{* file: app/views/shared/_recent_articles.tpl *}
<h3>Recent Articles</h3>
<ul>
{foreach $recent_articles as $article}
<li><a href="{$article->getUrl()}">{$article->getTitle()}</a></li>
{/foreach}
</ul>
As you may expected, the "recent_articles" closure is executed only when the cache is re-created., (*12)
Tracy panel integration
LazyLoader package comes with LazyLoaderPanel for easy integration into the popular debugger Tracy (https://packagist.org/packages/tracy/tracy), (*13)
$tracy_bar = Tracy\Debugger::getBar();
$tracy_bar->addPanel(new LazyLoaderPanel($lazy_loader));
Installation
The best way how to install LazyLoader is to use a Composer:, (*14)
composer require yarri/lazy-loader
Testing
Install required dependencies for development:, (*15)
composer update --dev
Run tests:, (*16)
./test/run_tests.sh
License
LazyLoader is free software distributed under the terms of the MIT license, (*17)