????
| Current Path : /proc/self/root/home/arabianr/www/wp-content/plugins/simplybook/app/Managers/ |
| Current File : //proc/self/root/home/arabianr/www/wp-content/plugins/simplybook/app/Managers/EndpointManager.php |
<?php
namespace SimplyBook\Managers;
use SimplyBook\Traits\HasNonces;
use SimplyBook\Traits\HasAllowlistControl;
use SimplyBook\Interfaces\MultiEndpointInterface;
use SimplyBook\Interfaces\SingleEndpointInterface;
final class EndpointManager extends AbstractManager
{
use HasNonces;
use HasAllowlistControl;
private array $routes = [];
/**
* @inheritDoc
*/
public function isRegistrable(object $class): bool
{
return ($class instanceof SingleEndpointInterface
|| $class instanceof MultiEndpointInterface
);
}
/**
* @inheritDoc
*/
public function registerClass(object $class): void
{
if ($class instanceof SingleEndpointInterface) {
$this->registerSingleEndpointRoute($class);
}
if ($class instanceof MultiEndpointInterface) {
$this->registerMultiEndpointRoute($class);
}
}
/**
* @inheritDoc
*/
public function afterRegister(): void
{
$this->registerWordPressRestRoutes();
do_action('simplybook_endpoints_loaded');
}
/**
* Register a plugin route for and endpoint instance that implements the
* {@see SingleEndpointInterface}
*/
private function registerSingleEndpointRoute(SingleEndpointInterface $endpoint): void
{
if ($endpoint->enabled() === false) {
return;
}
$this->routes[$endpoint->registerRoute()] = $endpoint->registerArguments();
}
/**
* Register plugin routes for an endpoint instance that implements the
* {@see MultiEndpointInterface}
*/
private function registerMultiEndpointRoute(MultiEndpointInterface $endpoint): void
{
if ($endpoint->enabled() === false) {
return;
}
$routeEndpoints = $endpoint->registerRoutes();
foreach ($routeEndpoints as $route => $arguments) {
$this->routes[$route] = $arguments;
}
}
/**
* This method provides a way to register custom REST routes via the
* simplybook_rest_routes filter. A controller of feature should be
* instantiated before this manager is called and the controller should
* hook into the simplybook_rest_routes filter to add its own routes.
* @uses apply_filters simplybook_rest_routes
* @throws \InvalidArgumentException
*/
public function registerWordPressRestRoutes(): void
{
$routes = $this->getPluginRestRoutes();
foreach ($routes as $route => $data) {
$version = ($data['version'] ?? $this->env->getString('http.version'));
$callback = ($data['callback'] ?? null);
$middleware = ($data['middleware'] ?? null);
if (!is_callable($callback)) {
throw new \InvalidArgumentException(
sprintf('The callback for the route "%s" is not callable.', $route)
);
}
$arguments = [
'methods' => $this->normalizeMethods($data['methods'] ?? 'GET'),
'callback' => $this->callbackMiddleware($callback, $middleware),
'permission_callback' => ($data['permission_callback'] ?? [$this, 'defaultPermissionCallback']),
];
if (!empty($data['args'])) {
$arguments['args'] = $data['args'];
}
register_rest_route($this->env->getString('http.namespace') . '/' . $version, $route, $arguments);
}
}
/**
* Get the plugins REST routes
* @uses apply_filters simplybook_rest_routes
*/
private function getPluginRestRoutes(): array
{
/**
* Filter: simplybook_rest_routes
* Can be used to add or modify the REST routes
*
* @param array $routes
* @return array
* @example [
* 'route' => [ // key is the route name
* 'methods' => 'GET', // required
* 'callback' => 'callback_function', // required
* 'permission_callback' => 'permission_callback_function', // optional to override the default permission callback
* 'version' => 'v1' // optional to override the default version
* ]
* ]
*/
return apply_filters('simplybook_rest_routes', $this->routes);
}
/**
* This method is used to add middleware to the callback function. The
* middleware should be a callable function that takes a request as an
* argument and returns a response. The default middleware is to switch
* the user locale to the current user locale.
*/
public function callbackMiddleware(?callable $callback, ?callable $middleware): callable
{
return function ($request) use ($callback, $middleware) {
if (is_callable($middleware)) {
$middleware($request);
} else {
$this->defaultMiddlewareCallback();
}
return $callback($request);
};
}
/**
* This method is used to switch the user locale to the current user locale.
* This is important because we will otherwise show the default site
* language to the user for the Tasks and Notifications. Those
* translations are created in PHP and not in JS.
*/
private function defaultMiddlewareCallback(): void
{
switch_to_user_locale(get_current_user_id());
}
/**
* The default permission callback, will check if the nonce is valid and if
* the user has the required permissions to do a request.
* @return bool|\WP_Error
*/
public function defaultPermissionCallback(\WP_REST_Request $request)
{
$method = $request->get_method();
$nonce = $request->get_param('nonce');
// For methods that modify data, verify the nonce
$methodsRequiringNonce = ['POST', 'PUT', 'PATCH', 'DELETE'];
if (in_array($method, $methodsRequiringNonce) && ($this->verifyNonce($nonce) === false)) {
return new \WP_Error(
'rest_forbidden',
__('Forbidden.', 'simplybook'),
['status' => 403]
);
}
return true;
}
/**
* Process the given methods and compare them to the allowed
* {@see \WP_REST_Server::ALLMETHODS} methods. Remove unwanted entries and
* cleanup method usage from, for example, "get " to "GET".
*
* @return string From "get, POSt, fake" to "GET,POST"
*/
private function normalizeMethods(string $methods): string
{
// Split into array, trim whitespace and uppercase entries
$methodsArray = array_map('trim', explode(',', $methods));
$methodsArray = array_map('strtoupper', $methodsArray);
// Split allowed entries into array and trim whitespaces
$allowedMethodsArray = array_map('trim', explode(',', \WP_REST_Server::ALLMETHODS));
// Keep only allowed methods
$methodsArray = array_intersect($methodsArray, $allowedMethodsArray);
$methodsArray = array_values(array_unique($methodsArray));
// Convert back to CSV format for register_rest_route usage
return implode(',', $methodsArray);
}
}