<?php
namespace Lia;
class Package {
/** example: package */
public string $name;
/** example: vendor:package */
public string $fqn;
/**
* The root dir for the package
*/
public ?string $dir = null;
/**
* Liaison object
*/
public \Lia $lia;
/** array of addons */
public array $addons = [];
/** Configurations for the package */
protected array $config = [];
/**
* @param $liaison a lia object
* @param $fqn a string like `vendor:package_name`
* @param $dir the root dir of this package
*/
public function __construct(\Lia $liaison, string $fqn, ?string $dir=null){
$this->lia = $liaison;
$this->dir = $dir ?? $this->dir;
$this->fqn = $fqn ?? $this->fqn;
$this->lia->addPackage($this, $this->fqn);
//$this->lia->fqn_packages[$this->fqn] = $this;
$pos = strpos($this->fqn, ':');
if ($pos!==false)$pos +=1;
$short_name = substr($this->fqn, $pos);
$this->name = $short_name;
//$this->lia->packages[$short_name] = $this;
if ($dir != null){
$config = $dir.'/config.json';
if (is_file($config)){
$props = json_decode(file_get_contents($config), true);
$this->config = $props;
}
}
$this->onConfigured($this->config);
$this->bootstrap();
$this->onBootstrapped();
$this->load_addons('addon');
$this->onAddonsLoaded($this->addons);
$this->ready();
$this->lia->package_added($this);
}
/**
* Calls `addon->onParentReady()` for each addon in this package. This is called automatically during package constructor, but can also be triggered manually if addons are added manually after instantiation.
*
*/
public function ready(){
foreach ($this->addons as $addon){
$addon->onParentReady($this);
}
}
/**
* 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){
}
/**
* 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){
}
/**
* `require()` the bootstrap.php file in the package's root dir, if it exists.
*
* It's called after the Package class has been initialized, with name, dir, lia, and fqn set. Addons are not yet loaded.
* If you use addons, call '$this->load_addons()' in your bootstrap.php file
* @NOTE subclass `\Lia\Package` or `\Lia\Package\Server` and implement a custom 'bootstrap()' method.
*/
protected function bootstrap(){
if (file_exists($this->dir.'/bootstrap.php')){
require($this->dir.'/bootstrap.php');
}
}
/**
* instantiate all addons in the given addon subdirectory.
*/
public function load_addons($sub_dir = 'addon'){
$dir = $this->dir.'/'.$sub_dir;
$classes = \Lia\Utility\ClassFinder::classesFromDir($dir);
if (count($classes)==0)return;
$addons = [];
foreach ($classes as $info){
// if (!in_array('Lia\\iCore\\Compo',$info['interfaces']))continue;
$className = $info['class'];
// if (!class_exists($className,true))continue;
$addon = new $className($this);
}
}
/**
* Return the absolute path to a directory inside your package
*/
public function dir(string $sub_dir): string{
return $this->dir.'/'.$sub_dir.'/';
}
/**
* Get a config's value or `null` if it is not set
*
* @param string $key the config's key
* @return mixed the config's value or null
*/
public function config(string $key): mixed {
return $this->config[$key] ?? null;
}
/**
* Set the config's value to a primitive value or array. Arrays should NOT contain objects, only that which can be expressed in JSON.
*
* @param $key string a config name
* @param int|string|bool|float|array $value a primitive value or array
*/
public function setConfig(string $key, int|string|bool|float|array $value): void {
$this->config[$key] = $value;
}
}