<?php
namespace Lia\CompoTrait;
/**
* Wire methods with prefixes to their relevant APIs.
*
* All methods in this trait are prefixed with `Scanner_` to prevent naming conflicts. Some convenience methods without the prefix are given, too.
* Generally, override the convenience methods, not the `Scanner_` ones
*
* @tag component, internals
* @todo create 'getGlobalPrefixes()', 'getOwnPrefixes()', and 'getAllPrefixes()' (which combines the two prior).
* @todo I hate the `Scanner_` prefix used by the Scanner trait... Idk. Idk. Maybe change it?
* @todo add 'getPrefixRegex()' method to configure what pattern a prefix has to be
* @todo add a 'parsePrefix()' function that removes the prefix_, & replaces _ with '.'. Simply override it to do custom parsing (or none at all)
* @todo add support for Attributes. And/or add a sibling-naming convention... `prefixWhatever`,
* - Sibling-namings: `scannedPrefixWhatever(){return $thePreparedStuffYouNeed}` or something. Or leave that up to the Apis. Ex: sitemapBlog(), routeBlog(), handleBlog()
* @todo review method names for intuitiveness
*/
trait Scanner {
/**
* @deprecated I don't think this is used anywhere any more.
* @todo delete this property (and test)
*/
protected $Scanner_registered = [];
/**
* Get array of global api prefixes
* From getApiPrefixes(), you can call $this->Scanner_getApiPrefixes() to get the list from liaison.
* If you overide this method:
* `$prefixes = array_replace_recursive($this->Scanner_getApiPrefixes(), $apiPrefixes);`
*/
public function getApiPrefixes(){
return $this->Scanner_getApiPrefixes();
}
/**
* Get the api for the given prefix. Returns an array with index 0 == apiname & index 1 == handlerName
* Get api for given prefix.
* @return array like [0=>api.name, 1=>handlerName].
*/
public function getApiForPrefix($prefix){
return $this->Scanner_getApiForPrefix($prefix);
}
/**
* Get array of method names that have the prefix
*
* @param $prefix the prefix to filter for
* @return array of method names
*/
public function getMethodsWithPrefix($prefix){
return $this->Scanner_getMethodsWithPrefix($prefix);
}
/**
* Scan for all prefixed methods on this class & call the relevant API's prefix handler
*/
public function autoHandlePrefixedMethods(){
return $this->Scanner_autoHandlePrefixedMethods();
}
/**
* Scan for the given prefix & map it to the given api (or the configured api);
*
*/
public function autoHandlePrefix($prefix, $api=null){
return $this->Scanner_autoHandlePrefix($prefix, $api);
}
/**
* Get array of prefixes from `Liaison` like `[ 'prefix'=> ['api.key', 'handlerName'], 'prefix2'=>...]`
*
*/
public function Scanner_getApiPrefixes(){
$lia = $this->liaison ?? $this->lia ?? null;
if ($lia==null)return [];
$prefixes = $lia->getApiPrefixes();
return $prefixes;
}
/**
* Returns an array of `[$methodNameWithoutPrefix => $methodNameWithPrefix]`
*
* @return array like `[ '_MethodName' => 'prefix_MethodName', 'Another'=>'prefixAnother']`
*/
protected function Scanner_getMethodsWithPrefix($prefix){
$methods = get_class_methods($this);
$found = [];
foreach ($methods as $method){
if (!preg_match('/^'.$prefix.'(([A-Z])|(\_[a-zA-Z]))/',$method,$matches))continue;
$start = $matches[0];
$name = substr($method,strlen($start)-1);
if (substr($start, -2, 1)=='_')$name = '_'.$name;
$found[$name] = $method;
}
return $found;
}
/**
* Get api for `$prefix`
*
* @return array like `['api.key', 'handlerName']`
*/
protected function Scanner_getApiForPrefix($prefix){
$prefixes = $this->getApiPrefixes();
if (isset($prefixes[$prefix]))return $prefixes[$prefix];
throw new \Lia\Exception\Base("Prefix '{$prefix}' is not defined globally. In this component, override getApiForPrefix() or getApiPrefixes() to if you don't want to use global prefixes.");
}
/**
* Scan for all prefixed methods on this class & call the relevant API's prefix handler
*
*/
public function Scanner_autoHandlePrefixedMethods(){
$prefixes = $this->getApiPrefixes();
// print_r($prefixes);
foreach ($prefixes as $prefix => $api){
$this->autoHandlePrefix($prefix, $api);
}
}
/**
* Scan for the given prefix & map it to the given api (or the configured api);
*
*/
public function Scanner_autoHandlePrefix($prefix, $api=null){
$liaison = $liaison ?? $this->liaison ?? $this->lia ?? null;
if (isset($this->Scanner_prefixesHandled[$prefix]))return;
if ($api==null)$api = $this->getApiForPrefix($prefix);
$this->Scanner_prefixesHandled[$prefix] = $prefix;
$methods = $this->getMethodsWithPrefix($prefix);
foreach ($methods as $cleanName => $actualMethodName){
// Intention is to point to the 'prefix' handler, thus $api[1], generally should be 'prefix', but this can be modified.
$liaison->api($api, $cleanName, [$this, $actualMethodName]);
}
}
}