Packages
A Liaison package wraps together a bunch of fuctionality into a single directory and integrates seamlessly with Liaison.
A Liaison package includes addons, public files (routes), views, methods, hooks, configuration, a bootsrap file, custom Package subclass and more (or less!). A most basic package will typically include public files and views.
Most Liaison features can be accessed without using a package, such as if you just want to add a route or two, but Packages are generally recommended for building Liaison-powered websites. If you're integrating existing Liaison packages into a non-Liaison website, you likely won't create your own package.
There is a base package class, but most Liaison packages will extend from the Server package subclass, and this documentation is geared toward that Server subclass.
Related: Views, Routes, Addons, Package Base Class, Server Package Subclass, Redirect Addon, Http Addon, Configure Site
Docs
- Useful Methods
- Initialize a package
- Directory Structure
- Configs (config.json)
- bootstrap.php
- Subclassing Server Package
- Package Lifecycle
- Methods to override
Useful Methods
-
$package->dir('/rel-dir/')gets the path to a directory within the package. Does NOT remove any path traversal or double-slashes. -
$package->url('/some-relative-url/')prepends the package's base_url and returns a full path (no domain). Any double-slashes are removed. Does NOT remove any path traversal. -
$package->goto('/some-relative-url/')redirects to a path within$package, using the Redirect addon. (same rules asurl()method) -
$package->config(string $key)get a config from a package -
$package->setConfig(string $key, mixed $value)set a configuration value
Initialize a package
A package can use the built-in Server package class or a subclass of it.
<?php
// Create your site's package, containing your routes, views, theme, addons, hooks, and more
$site_package = new \Lia\Package\Server($lia, 'vendor:namespace', __DIR__.'/Site/', '/base_url/');
// or using a subclass
$site_package = new \My\WebsitePackage($lia);
// base_url could be overwritten, but the package fqn and directory should typically be pre-defined in your package class's code.
Directory Structure
This is the structure for a typical package, with each file and directory being optional.
packages/Site/
- config.json <- Package settings
- bootstrap.php <- called right after the package is initialized. Use `$this` for your `Package`.
- public/ <- Public files to be routed to.
- index.php <- home page
- contact.php <- /contact/
- view/ <- Views
- theme.php <- site layout
- theme.css <- automatically included when theme is displayed
- addon/ <- Addons (extend \Lia\Addon)
- MarkdownSupport.php <- A custom addon to add features to Liaison
- class/ <- Point composer's autoloader to this directory. The Autoload addon within Liaison is not recommended.
Configs (config.json)
The config.json configures some settings on a package, and provides dynamic configurability for other packages to reference. For example, an addon that enables markdown support might check if an added package set vendor:namespace.markdown_support = true in its config.json.
(NOTE: For site-wide configurations, see Configure Site)
Built-in configuratinos available:
{
"base_url": "/my-package/",
"fqn": "vendor:namespace",
"public_file_params": {}
}
Notes:
-
$package->config(string $key)get a config from a package -
$package->setConfig(string $key, mixed $value)set a configuration value -
base_urldefaults to/, can be set inconfig.jsonor can be overwritten via a paramater passed to the constructor. -
fqnis the fully qualified name of a package -
public_file_paramsareextract()ed and exposed to public files within the package. -
2025-02-11: The
config.jsonis loaded BEFORE the bootstrap is loaded, howeverbase_url,fqn, andpublic_file_paramsare set AFTER bootstrapping.base_urlandfqnwill be overwritten by configs/constructor, whereaspublic_file_paramswill bearray_merge()d (config ovewrites same-named-keys). This implementation is likely to be changed.
bootstrap.php
If bootstrap.php exists in the root of your package, it is called at the end of Package::__construct(), prior to any additional setup done by the Server package subclass.
Example boostrap.php, adding some routes & protecting requests to /admin/ pages within it:
<?php
/**
* This file is loaded after the base Package class is initialized, before addons are loaded. For access to addons within your package, call `$this->load_addons()`. For guarantees that other packages are loaded, setup hooks here (*assuming you've loaded the main package first*).
*
* @param $this \Lia\Package the package this bootstrap file belongs to (typically a subclass)
*/
$package = $this;
$lia = $this->lia;
// Add a directory of additional routes for admin pages
\Lia\Addon\Router::from($lia)
->addDirectoryRoutes($package, \My\ClassOfConsts::DIR_ADMIN, $package->url('/admin/'),['.php']);
// `['.php']` is an array of extensions to be hidden. i.e. public2/bear.php becomes /bear/
// protect all requests to `admin/*` with a hook, only if this package is being requested.
$lia->hook(\Lia\Hooks::ROUTES_FILTERED,
function(\Lia\Obj\Route $route) use ($package){
if ($route->package() !== $package)return; // we're not filtering for other's packages.
$admin_url = $package->url("/admin/"); // we must consider the base_url if the package is portable.
if (substr($route->url(), 0, strlen($admin_url)) == $admin_url){
// current_user_is_admin() is NOT part of Liaison, but might be part of your package subclass.
if (!$package->current_user_is_admin()){
// Elsewhere, you might catch \My\Exception and display a message to the user.
throw new \My\Exception(\My\ClassOfConsts::ERR_ADMIN_REQUIRED);
}
}
}
);
Subclassing Server Package
A custom Package class makes it easier for others to setup your package, allows you to declare properties and methods, and the constructor can serve as a bootstrapper.
Minimal Example:
<?php
namespace ReedyBear\PageCreator;
class Package extends \Lia\Package\Server {
public string $fqn = 'reedybear:page_creator';
public string $name = 'page_creator';
// define a custom constructor for easier setup, or add a public static method
public function __construct(\Lia $lia, ?string $base_url=null){
parent::__construct($lia, $this->fqn, \ReedyBear\PageCreator::DIR_PACKAGE, $base_url);
}
// define convenience methods for your addons to call
// override lifecycle methods (see below docs)
}
Package Lifecycle
All onSOMETHING() methods are empty and meant to be overridden (only if needed).
When a Package is instantiated, the following happens:
($this referring to the package that is being instantiated.)
-
PACKAGE_DIR/config.jsonis loaded to$this->configarray. -
$this->onConfigured($this->config)is called. -
PACKAGE_DIR/bootstrap.phpis executed. -
$this->onBootstrapped()is called. - Addons are loaded from
PACKAGE_DIR/addons/into$this->addons. -
$this->onAddonsLoaded($this->addons)is called. -
$this->load_global_configs(array $configs)is called with values that were set via$lia->configure($global_configs).- These configs are propagated to loaded addons' properties, unless you override this method.
-
$addon->filter_global_configs(array $addon_configs): arrayis called for each addon before configs are set. You may override this in each addon to return modified configuration values before they are set.
-
$addon->onParentReady($this)is called for each loaded addon -
onPackageAdded($this)is called on each other package (and on each of their addons) -
$this->onPackageAdded($other_package)is called for each other package. (and called on each of$this->addons)
Methods to override
Overridable methods are below. See Package Base Class for more information.
<?php
/**
* Called after configurations are loaded from `PACKAGE_DIR/config.json`, before bootstrapping.
*
* @override to modify configurations, add new configs dynamically, or otherwise prepare for bootstrapping.
*
* @param array $configs the configs that were loaded from disk. These have already been set to `$this->configs`.
*/
public function onConfigured(array $configs){
}
/**
* Called after bootstrap file is `require`d (PACKAGE_DIR/bootstrap.php). This is called even if there is no bootstrap file.
*
* @override to bootstrap further. Typically, bootstrap.php is preferred.
*/
public function onBootstrapped(){
}
/**
* Called after addons have been instantiated. Addons may not be fully setup yet, as addon->onParentReady() has not been called yet.
*
* @override to do additional setup that depends upon addons
*
* @param array $addons addons that were loaded, in no particular order.
*/
public function onAddonsLoaded(array $addons){
}
/**
* Get global configs from Liaison and propagate them to this package's addons. Called after onAddonsLoaded.
*
* @override to customize the way global configs are setup
* @param $addon_configs array<string addon_name, array configured_key_value_pairs> array of configs for each addon within the package
*/
protected function load_global_configs(array $addon_configs){
//... this has a default implementation to propagate key=>value pairs to addon properties, but can be overridden for custom implementation.
// You may alternatively wish to override `\Lia\Addon::filter_global_configs(array $configs): array`, which does no filtering by default.
}
/**
* Called when any other package is added, after it is fully setup (config, bootstrap, and addons have been loaded).
*
* This is also called for previously-added packages. When Package 2 is added, Package1->onPackageAdded(Package2) will be called AND Package2->onPackageAdded(Package1) will be called.
*
* Never called for itself. When Package 2 is added, Package2->onPackageAdded(Package2) will never be called.
*/
public function onPackageAdded(\Lia\Package $package){
}
The following methods can be overridden in Addons:
<?php
/**
* Called after the addon's parent package has finished loading. (configs loaded, bootstrapped, all other addons instantiated).
*
* onPackageAdded() has not been called yet.
*/
public function onParentReady(\Lia\Package $package){
}
/**
* Called after a Package is added to Liaison, after it has been fully initialized, after configs loaded, bootstrapped, all other addons instantiated, and `onParentReady()` called on each of its addons.
*
*/
public function onPackageAdded(\Lia\Package $package){
}
/**
* Return array of configs that can be set to this addon from global configuration.
*
* @override to return a modified array of configs that will be set to this addon. Alternatively, you could do custom setting here and then return an empty array.
*/
public function filter_global_configs(array $configs): array {
return $configs;
}