My previous framework had some pretty snazzy conviniance methods. one of thsoe was ->get() being rather powerful. the entire system used a sort of “hive” structure. so ->get() brought values from that. (->get(“GET.id”) ->get(“POST.username”) ->get(“SESSION.sid”) etc.
i really want to replicate this ability in slim.
so my Q is… if i create my own container with this type of thing included, what are the issues i could face with it? (not being able to swap out di containers for instance)
the Container isnt as decent as i would want it, right now just going to POC on this.
thoughts?
// Init the container
$container = new Container(array(
"ROUTE"=>null,
"ALIAS"=>null,
"PARAMS"=>array(),
"GET"=>$_GET,
"POST"=>$_POST,
));
// setting route middleware to populate the params / route parts in the container
$app->add(function (Request $request, RequestHandler $handler) {
$routeContext = RouteContext::fromRequest($request);
$route = $routeContext->getRoute();
// return NotFound for non existent route
if (empty($route)) {
throw new HttpNotFoundException($request);
}
$name = $route->getName();
$groups = $route->getGroups();
$methods = $route->getMethods();
$arguments = $route->getArguments();
$this->set('PARAMS',$arguments);
$this->set('ROUTE',$route);
$this->set('ALIAS',$name);
return $handler->handle($request);
});
usage
$app->get('/[{test}]', function ($request, $response) {
var_dump($this->get("GET.id"));
var_dump($this->get("PARAMS.test"));
})
and lastly the Container itself.
the basics are if the key being provided doesnt exist then split the “key” on . and see if the base key exists. if the base key is an array then transverse that element in the container by dot notation.
<?php
declare(strict_types=1);
namespace system\container;
use Closure;
use LogicException;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use function array_key_exists;
use function call_user_func_array;
use system\utilities\Arrays;
class Container implements ContainerInterface {
/**
* @var array
*/
private $container;
/**
* @param array $entries Array of string => mixed.
*/
public function __construct(array $entries = []) {
$this->container = $entries;
}
private function cut($key) {
return preg_split('/\[\h*[\'"]?(.+?)[\'"]?\h*\]|(->)|\./',
$key, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
);
}
/**
* @param string $key magic method for ->get
*/
public function __get(string $key) {
return $this->get($key);
}
/**
* {@inheritdoc}
*/
public function get(string $key) {
$args = func_get_args();
reset($args);
if (!$this->has($key)){
$parts = $this->cut($key);
$key_base = array_shift($parts);
if ($this->has($key_base)){
if (is_array($this->container[$key_base])){
return Arrays::getValueByKey(implode(".",$parts),(array)$this->container[$key_base]);
}
return call_user_func_array($this->container[$key_base], [$this, ...$args]);
}
}
if (!$this->resolved($key)) {
$this->container[$key] = call_user_func_array($this->container[$key], [$this, ...$args]);
}
return $this->container[$key];
}
/**
* {@inheritdoc}
*/
public function has(string $key): bool {
return array_key_exists($key, $this->container);
}
/**
* @param string $key
* @param mixed $entry
*/
public function set(string $key, $entry): void {
$this->container[$key] = $entry;
}
/**
* Returns whether a given service has already been resolved
* into its final value, or is still a callable.
*
* @throws NotFoundExceptionInterface No entry was found for **this** identifier.
*/
public function resolved(string $key): bool {
if (!$this->has($key)) {
throw new class extends LogicException implements NotFoundExceptionInterface {
};
}
return !$this->container[$key] instanceof Closure;
}
}