How can i group routes by a middleware or route prefix, using Closure? Similar to laravel (without using 'use' like other answers in the community and doing with static call).
I dont know how to group all these calls inside the closure. How can i do this? Some example?
web.php (file routes):
//web.php file
Router::middleware(['auth', 'okok'])->group(function(){
Router::get('/teste', [TestController::class, 'test']);
Router::get('/teste2', [TestController::class, 'test2']);
});
Router.php (Router Class):
<?php
namespace Core;
use Core\RouterHandler;
use Closure;
class Router
{
protected static $routes = [];
protected static $middlewares = [];
protected static string $uriMethod;
protected static string $trigger;
/**
* start
* START THE ROUTER IN INDEX.PHP
* #param Router $router
* #return void
*/
public static function start()
{
$routerHandler = new RouterHandler(self::$routes);
$routerHandler->run();
}
/**
* constructByMethod
* CONSTRUCT THE ROUTE OBJECT WHEN CALLED BY THE MAINS METHODS
* #param string $uri
* #param array $trigger
* #param string $uriMethod
* #return object
*/
private static function constructByMethod(string $uri, array $trigger, string $uriMethod): object
{
self::$uriMethod = $uriMethod;
self::$trigger = $trigger[0].'::'.$trigger[1];
self::$routes[$uriMethod][self::$trigger]['uri'] = $uri;
self::$routes[$uriMethod][self::$trigger]['uriMethod'] = $uriMethod;
self::$routes[$uriMethod][self::$trigger]['controller'] = $trigger[0];
self::$routes[$uriMethod][self::$trigger]['action'] = $trigger[1];
if (!empty(self::$middlewares)) {
self::$routes[$uriMethod][self::$trigger]['middlewares'] = self::$middlewares;
}
self::$middlewares = [];
return new static();
}
/**
* get
* MAIN METHOD TO CONSTRUCT GET ROUTE
* #param string $uri
* #param array $trigger
* #return object
*/
public static function get(string $uri, array $trigger): object
{
self::constructByMethod($uri, $trigger, 'GET');
return new static();
}
/**
* post
* MAIN METHOD TO CONSTRUCT POST ROUTE
* #param string $uri
* #param array $trigger
* #return object
*/
public static function post(string $uri, array $trigger): object
{
self::constructByMethod($uri, $trigger, 'POST');
return new static();
}
/**
* put
* MAIN METHOD TO CONSTRUCT POST ROUTE
* #param string $uri
* #param array $trigger
* #return object
*/
public static function put(string $uri, array $trigger): object
{
self::constructByMethod($uri, $trigger, 'PUT');
return new static();
}
/**
* delete
* MAIN METHOD TO CONSTRUCT DELETE ROUTE
* #param string $uri
* #param array $trigger
* #return object
*/
public static function delete(string $uri, array $trigger): object
{
self::constructByMethod($uri, $trigger, 'DELETE');
return new static();
}
public static function group($callback)
{
$callback();
}
/**
* name
* ADD A NAME TO A ROUTE
* #param string $name
* #return object
*/
public static function name(string $name): object
{
self::$routes[self::$uriMethod][self::$trigger]['name'] = $name;
return new static();
}
/**
* middleware
* ADD A GROUP OF MIDDLEWARE FOR A ROUTES
* #param array|null $middlewares
* #return object
*/
public static function middleware(array|null $middlewares): object
{
self::$middlewares = $middlewares;
return new static();
}
/**
* where
* ADD A REGEX CONDITION FOR A VARIABLE PARAMETER IN ROUTE
* #param array $where
* #return object
*/
public static function where(array $where): object
{
self::$routes[self::$uriMethod][self::$trigger]['where'] = $where;
return new static();
}
}
What to do after that?
public static function group($callback)
{
$callback();
}
Tried all ways, but I can't understand how to group the routes using closure.
I need to understand how to use the closure in this specific case.
First, you'll need to use the method Closure::call, in order to temporarily bind the group handler (function(){...}) to the instance of the router.
After that you'll need to execute the group handler. Then:
each group inside it will be binded and executed as well (as described above), and
each route defined inside it will be added to the router.
Below is a short example of my code, regarding adding a group to the route collection, with detailed comments (see RouteCollection::group method).
Note that I add groups/routes to a RouteCollection, which is further added to my Router. Instead you are adding them directly to your Router.
Further down under I also posted my whole RouteCollection code, for better understanding.
Note: You are using static methods/properties. I suggest not to use any at all. Instead, you should use dependency injection.
Short code version:
RouteCollectionInterface (short version, regarding binding & executing a group):
<?php
namespace PajuranCodes\Router;
use Closure;
/**
* An interface to a collection of routes.
*
* #author pajurancodes https://github.com/pajurancodes
*/
interface RouteCollectionInterface extends \Countable, \IteratorAggregate {
/**
* Add a group.
*
* #param string $pattern A group pattern.
* #param Closure $handler A group handler.
* #return static
*/
public function group(string $pattern, Closure $handler): static;
}
RouteCollection (short version, regarding binding & executing a group):
<?php
namespace PajuranCodes\Router;
use function array_pop;
use PajuranCodes\Router\{
RouteCollectionInterface,
};
use Closure;
/**
* A collection of routes.
*
* #author pajurancodes https://github.com/pajurancodes
*/
class RouteCollection implements RouteCollectionInterface {
[...]
/**
* A list of group patterns as an indexed array.
*
* {#internal Each time a group handler is executed, the group
* pattern is pushed to this list. When a route is added to the
* routes list (inside the scope of a group handler), the route
* pattern is prefixed with the string formed by concatenating
* all group patterns saved in this list.}
*
* #var string[]
*/
private array $groupPatterns = [];
/**
* #inheritDoc
*/
public function group(string $pattern, Closure $handler): static {
$this->addGroup($pattern, $handler);
return $this;
}
/**
* Add a group.
*
* #param string $pattern A group pattern.
* #param Closure $handler A group handler.
* #return static
*/
private function addGroup(string $pattern, Closure $handler): static {
$this->saveGroupPattern($pattern);
$this->executeGroupHandler($handler);
/*
* Remove the last group pattern from the group patterns list.
* This step is performed only after all calls for adding
* groups/routes inside the scope of the current group
* handler have finished their processing.
*/
$this->popLastGroupPattern();
return $this;
}
/**
* Save a group pattern.
*
* #param string $pattern A group pattern.
* #return static
*/
private function saveGroupPattern(string $pattern): static {
$this->groupPatterns[] = $pattern;
return $this;
}
/**
* Execute a group handler.
*
* {#internal This method temporarily binds the given group handler to
* the instance of the route collection - defined by the argument of
* Closure::call - and executes it. Inside the scope of the group handler,
* the route collection will be accessed using the keyword "$this".}
*
* #link https://www.php.net/manual/en/closure.call.php Closure::call
*
* #param Closure $handler A group handler.
* #return static The value returned by executing the group handler.
*/
private function executeGroupHandler(Closure $handler): static {
$handler->call($this);
return $this;
}
/**
* Pop and return the last group pattern in the list of group patterns.
*
* The list will be shortened by one element.
*
* #return string|null The last group pattern, or null if the list is empty.
*/
private function popLastGroupPattern(): ?string {
return array_pop($this->groupPatterns);
}
[...]
}
Long code version:
RouteCollectionInterface (complete version):
<?php
namespace PajuranCodes\Router;
use Closure;
use PajuranCodes\Router\RouteInterface;
/**
* An interface to a collection of routes.
*
* #author pajurancodes https://github.com/pajurancodes
*/
interface RouteCollectionInterface extends \Countable, \IteratorAggregate {
/**
* Add a group.
*
* #param string $pattern A group pattern.
* #param Closure $handler A group handler.
* #return static
*/
public function group(string $pattern, Closure $handler): static;
/**
* Add a route for one or more HTTP methods.
*
* #param string|string[] $methods One or more HTTP methods.
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function route(
string|array $methods,
string $pattern,
string|array|object $handler
): RouteInterface;
/**
* Add a route for all HTTP methods.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function routeForAllMethods(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method GET.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function get(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method HEAD.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function head(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method POST.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function post(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method PUT.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function put(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method DELETE.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function delete(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method CONNECT.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function connect(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method OPTIONS.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function options(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method TRACE.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function trace(string $pattern, string|array|object $handler): RouteInterface;
/**
* Add a route for the HTTP method PATCH.
*
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
public function patch(string $pattern, string|array|object $handler): RouteInterface;
/**
* Get a route by id.
*
* #param string $id A route id.
* #return RouteInterface The found route.
* #throws \UnexpectedValueException No route found.
*/
public function getRouteById(string $id): RouteInterface;
/**
* Get a route by name.
*
* #param string $name A route name.
* #return RouteInterface The found route.
* #throws \UnexpectedValueException No route found.
*/
public function getRouteByName(string $name): RouteInterface;
/**
* Check if a route exists in the collection.
*
* #param string $id A route id.
* #return bool True if the specified route id exists, or false otherwise.
*/
public function exists(string $id): bool;
/**
* Remove a route from the collection.
*
* #param string $id A route Id.
* #return static
*/
public function remove(string $id): static;
/**
* Get all routes from the collection.
*
* #return RouteInterface[] All routes in the collection.
*/
public function all(): array;
/**
* Remove all routes from the collection.
*
* #return static
*/
public function clear(): static;
/**
* Check if the collection is empty.
*
* #return bool True if the collection is empty, or false otherwise.
*/
public function isEmpty(): bool;
/**
* Count the routes in the collection.
*
* #return int Number of routes in the collection.
*/
public function count(): int;
/**
* Get an iterator to iterate through the collection.
*
* #return \Traversable The routes iterator.
*/
public function getIterator(): \Traversable;
}
RouteCollection (complete version):
<?php
namespace PajuranCodes\Router;
use function count;
use function implode;
use function array_pop;
use function array_key_exists;
use PajuranCodes\Router\{
Route,
RouteInterface,
RouteCollectionInterface,
};
use Closure;
use Fig\Http\Message\RequestMethodInterface as RequestMethod;
/**
* A collection of routes.
*
* #author pajurancodes https://github.com/pajurancodes
*/
class RouteCollection implements RouteCollectionInterface {
/**
* A string to be concatenated to a counter in order to form a route id.
*
* #var string
*/
private const ROUTE_ID_PREFIX = 'route';
/**
* A list of allowed HTTP methods.
*
* #link https://tools.ietf.org/html/rfc7231#section-4 4. Request Methods
* #link https://www.iana.org/assignments/http-methods/http-methods.xhtml Hypertext Transfer Protocol (HTTP) Method Registry
* #link https://tools.ietf.org/html/rfc5789 PATCH Method for HTTP
*
* #var string[]
*/
private const ROUTE_ALLOWED_METHODS = [
RequestMethod::METHOD_GET,
RequestMethod::METHOD_HEAD,
RequestMethod::METHOD_POST,
RequestMethod::METHOD_PUT,
RequestMethod::METHOD_DELETE,
RequestMethod::METHOD_CONNECT,
RequestMethod::METHOD_OPTIONS,
RequestMethod::METHOD_TRACE,
RequestMethod::METHOD_PATCH,
];
/**
* A list of routes as an associative array.
*
* The key of each list item is a route id
* built from a prefix string and a counter.
*
* #var RouteInterface[]
*/
private array $routes = [];
/**
* A list of group patterns as an indexed array.
*
* {#internal Each time a group handler is executed, the group
* pattern is pushed to this list. When a route is added to the
* routes list (inside the scope of a group handler), the route
* pattern is prefixed with the string formed by concatenating
* all group patterns saved in this list.}
*
* #var string[]
*/
private array $groupPatterns = [];
/**
* A counter used to be prefixed with a given string in order to form a route id.
*
* {#internal After a route is added to the
* routes list this counter is incremented.}
*
* #var int
*/
private int $routeIdCounter = 0;
/**
* #inheritDoc
*/
public function group(string $pattern, Closure $handler): static {
$this->addGroup($pattern, $handler);
return $this;
}
/**
* Add a group.
*
* #param string $pattern A group pattern.
* #param Closure $handler A group handler.
* #return static
*/
private function addGroup(string $pattern, Closure $handler): static {
$this->saveGroupPattern($pattern);
$this->executeGroupHandler($handler);
/*
* Remove the last group pattern from the group patterns list.
* This step is performed only after all calls for adding
* groups/routes inside the scope of the current group
* handler have finished their processing.
*/
$this->popLastGroupPattern();
return $this;
}
/**
* Save a group pattern.
*
* #param string $pattern A group pattern.
* #return static
*/
private function saveGroupPattern(string $pattern): static {
$this->groupPatterns[] = $pattern;
return $this;
}
/**
* Execute a group handler.
*
* {#internal This method temporarily binds the given group handler to
* the instance of the route collection - defined by the argument of
* Closure::call - and executes it. Inside the scope of the group handler,
* the route collection will be accessed using the keyword "$this".}
*
* #link https://www.php.net/manual/en/closure.call.php Closure::call
*
* #param Closure $handler A group handler.
* #return static The value returned by executing the group handler.
*/
private function executeGroupHandler(Closure $handler): static {
$handler->call($this);
return $this;
}
/**
* Pop and return the last group pattern in the list of group patterns.
*
* The list will be shortened by one element.
*
* #return string|null The last group pattern, or null if the list is empty.
*/
private function popLastGroupPattern(): ?string {
return array_pop($this->groupPatterns);
}
/**
* #inheritDoc
*/
public function route(
string|array $methods,
string $pattern,
string|array|object $handler
): RouteInterface {
return $this->addRoute($methods, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function routeForAllMethods(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(self::ROUTE_ALLOWED_METHODS, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function get(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_GET, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function head(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_HEAD, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function post(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_POST, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function put(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_PUT, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function delete(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_DELETE, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function connect(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_CONNECT, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function options(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_OPTIONS, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function trace(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_TRACE, $pattern, $handler);
}
/**
* #inheritDoc
*/
public function patch(string $pattern, string|array|object $handler): RouteInterface {
return $this->addRoute(RequestMethod::METHOD_PATCH, $pattern, $handler);
}
/**
* Add a route.
*
* #param string|string[] $methods One or more HTTP methods.
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
private function addRoute(
string|array $methods,
string $pattern,
string|array|object $handler
): RouteInterface {
$this
->validateRouteMethods($methods)
->validateRouteHandler($handler)
;
$prefixedPattern = $this->prefixRoutePatternWithGroupPatterns($pattern);
$route = $this->createRoute($methods, $prefixedPattern, $handler);
return $this->saveRoute($route);
}
/**
* Validate a list of route methods.
*
* #param string|string[] $methods One or more HTTP methods.
* #return static
* #throws \InvalidArgumentException The list of HTTP methods is empty.
*/
private function validateRouteMethods(string|array $methods): static {
if (empty($methods)) {
throw new \InvalidArgumentException('One or more HTTP methods must be provided.');
}
return $this;
}
/**
* Validate a route handler.
*
* #param string|array|object $handler A route handler.
* #return static
* #throws \InvalidArgumentException An empty route handler.
*/
private function validateRouteHandler(string|array|object $handler): static {
if (empty($handler)) {
throw new \InvalidArgumentException('The route handler can not be empty.');
}
return $this;
}
/**
* Prefix a route pattern with the pattern formed by
* concatenating the list of group patterns in a single string.
*
* #param string $pattern A route pattern.
* #return string The prefixed route pattern.
*/
private function prefixRoutePatternWithGroupPatterns(string $pattern): string {
return $this->getConcatenatedGroupPatterns() . $pattern;
}
/**
* Get the pattern formed by concatenating the
* list of group patterns in a single string.
*
* #return string The resulted pattern.
*/
private function getConcatenatedGroupPatterns(): string {
return $this->groupPatterns ? implode('', $this->groupPatterns) : '';
}
/**
* Create a route.
*
* #param string|string[] $methods One or more HTTP methods.
* #param string $pattern A route pattern.
* #param string|array|object $handler A route handler.
* #return RouteInterface The route.
*/
private function createRoute(
string|array $methods,
string $pattern,
string|array|object $handler
): RouteInterface {
return new Route($methods, $pattern, $handler);
}
/**
* Save a route.
*
* Before saving, an id is assigned to the route.
*
* #param RouteInterface $route A route.
* #return RouteInterface The route.
*/
private function saveRoute(RouteInterface $route): RouteInterface {
$id = $this->buildRouteId();
$route->setId($id);
$this->routes[$id] = $route;
$this->routeIdCounter++;
return $route;
}
/**
* Build a route id.
*
* The id is built by concatenating the
* route id prefix and the route id counter.
*
* #return string The route id.
*/
private function buildRouteId(): string {
return self::ROUTE_ID_PREFIX . (string) $this->routeIdCounter;
}
/**
* #inheritDoc
*/
public function getRouteById(string $id): RouteInterface {
if (!$this->exists($id)) {
throw new \UnexpectedValueException(
'A route with the id "' . $id . '" could not be found.'
);
}
return $this->routes[$id];
}
/**
* #inheritDoc
*/
public function getRouteByName(string $name): RouteInterface {
foreach ($this->routes as $route) {
if ($route->getName() === $name) {
return $route;
}
}
throw new \UnexpectedValueException(
'A route with the name "' . $name . '" could not be found.'
);
}
/**
* #inheritDoc
*/
public function exists(string $id): bool {
return array_key_exists($id, $this->routes);
}
/**
* #inheritDoc
*/
public function remove(string $id): static {
if ($this->exists($id)) {
unset($this->routes[$id]);
}
return $this;
}
/**
* #inheritDoc
*/
public function all(): array {
return $this->routes;
}
/**
* #inheritDoc
*/
public function clear(): static {
$this->routes = [];
return $this;
}
/**
* #inheritDoc
*/
public function isEmpty(): bool {
return !($this->count() > 0);
}
/**
* #inheritDoc
*/
public function count(): int {
return count($this->routes);
}
/**
* #inheritDoc
*/
public function getIterator(): \Traversable {
return new \ArrayIterator($this->routes);
}
}
Related
ive an Laravel Openid Script for Wargaming Openid Login. at the moment i dont use laravel. So i will convert it into an normal PHP Script for an MVC Model based CMS called ilch 2.x
For iLch i do some plugins. But im so stupid to convert it.
The Problems comes from the request parts of this script. but i cant solf the problems.
My Skills are not so good.
`
<?php
declare(strict_types=1);
namespace Azate\Laravel\WargamingAuth;
use GuzzleHttp\Client as GuzzleClient;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Illuminate\Contracts\Routing\UrlGenerator;
use Illuminate\Http\Request;
/**
* Class WargamingAuth
*
* #package Azate\Laravel\WargamingAuth
*/
class WargamingAuth
{
/**
* Config repository.
*
* #var ConfigRepository
*/
protected $configRepository;
/**
* Illuminate request class.
*
* #var Request
*/
protected $request;
/**
* Illuminate url class.
*
* #var UrlGenerator
*/
protected $urlGenerator;
/**
* Region.
*
* #var string
*/
protected $region;
/**
* Realm
*
* #var string
*/
protected $realm;
/**
* Callback url.
*
* #var string
*/
protected $callbackUrl;
/**
* Creates new instance.
*
* #param ConfigRepository $configRepository
* #param Request $request
* #param UrlGenerator $urlGenerator
*/
public function __construct(
ConfigRepository $configRepository,
Request $request,
UrlGenerator $urlGenerator
) {
$this->configRepository = $configRepository;
$this->request = $request;
$this->urlGenerator = $urlGenerator;
$this->region = $this->configRepository->get('wargamingAuth.defaultRegion');
$this->realm = $this->configRepository->get('app.url');
$this->callbackUrl = $this->urlGenerator->route(
$this->configRepository->get('wargamingAuth.callbackRoute')
);
}
/**
* Returns the region.
*
* #return string
*/
public function getRegion(): string
{
return $this->region;
}
/**
* Set the region.
*
* #param string $region
*/
public function setRegion(string $region)
{
$this->region = $region;
}
/**
* Returns the realm.
*
* #return string
*/
public function getRealm(): string
{
return $this->realm;
}
/**
* Set the realm.
*
* #param string $realm
*/
public function setRealm(string $realm)
{
$this->realm = $realm;
}
/**
* Returns the OpenID URL.
*
* #return string
*/
public function getOpenIdUrl(): string
{
return 'https://' . $this->region . '.wargaming.net/id/openid/';
}
/**
* Returns the redirect URL.
*
* #return string
*/
public function redirectUrl(): string
{
$params = [
'openid.ax.if_available' => 'ext0,ext1',
'openid.ax.mode' => 'fetch_request',
'openid.ax.type.ext0' => 'http://axschema.openid.wargaming.net/spa/id',
'openid.ax.type.ext1' => 'http://axschema.org/namePerson/friendly',
'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select',
'openid.identity' => 'http://specs.openid.net/auth/2.0/identifier_select',
'openid.mode' => 'checkid_setup',
'openid.ns' => 'http://specs.openid.net/auth/2.0',
'openid.ns.ax' => 'http://openid.net/srv/ax/1.0',
'openid.realm' => $this->realm,
'openid.return_to' => $this->callbackUrl,
];
return $this->getOpenIdUrl() . '?' . http_build_query($params, '', '&');
}
/**
* OpenID Positive Assertions.
*
* #return bool
*/
private function isPositiveAssertion(): bool
{
$hasFields = $this->request->has([
'openid_assoc_handle',
'openid_claimed_id',
'openid_identity',
'openid_mode',
'openid_ns',
'openid_op_endpoint',
'openid_response_nonce',
'openid_return_to',
'openid_sig',
'openid_signed',
]);
$isModeIdRes = $this->request->get('openid_mode') === 'id_res';
return $hasFields && $isModeIdRes;
}
/**
* OpenID Verifying the Return URL.
*
* #return bool
*/
public function verifyingReturnUrl(): bool
{
return $this->request->get('openid_return_to') === $this->request->url();
}
/**
* Get param list for OpenID validation
*
* #return array
*/
private function getOpenIdValidationParams(): array
{
$params = [];
$signedParams = explode(',', $this->request->get('openid_signed'));
foreach ($signedParams as $item) {
$params['openid.' . $item] = $this->request->get('openid_' . str_replace('.', '_', $item));
}
$params['openid.mode'] = 'check_authentication';
$params['openid.sig'] = $this->request->get('openid_sig');
return $params;
}
/**
* OpenID Verifying Signatures (Wargaming uses Direct Verification).
*
* #return bool
*
* #throws \GuzzleHttp\Exception\GuzzleException
*/
public function verifyingSignatures(): bool
{
$httpClient = new GuzzleClient;
$response = $httpClient->request('POST', $this->getOpenIdUrl(), [
'form_params' => $this->getOpenIdValidationParams(),
]);
$content = $response->getBody()->getContents();
return strpos($content, 'is_valid:true') !== false;
}
/**
* Process to verify an OpenID assertion.
*
* #return bool
*
* #throws \GuzzleHttp\Exception\GuzzleException
*/
public function verify(): bool
{
return $this->isPositiveAssertion()
&& $this->verifyingReturnUrl()
&& $this->verifyingSignatures();
}
/**
* Returns the user data.
*
* #return array
*/
public function user(): array
{
return [
'id' => $this->request->get('openid_ax_value_ext0_1'),
'nickname' => $this->request->get('openid_ax_value_ext1_1'),
];
}
}
`
I hope i can get help from you
I fail with the requests especially with has()
I am trying to filter Laravel Nova resource (Reviews) data using 2 'select-filters'.
I have a filter A = Manufacturers and filter B = Models.
A Manufacturer has many Models. I have manufacturer and model column in products table.
'Model' filter by default show all the values in the select dropdown. I want to reduce the select options in the 'Model' filter when 'Manufacturer' is selected.
so, for example: When Manufacturer = "Apple" then 'Model' filter should show only Apple 'Models'.
In my Review Resource, I have below code:
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [
new Manufacturer(),
new Model(),
];
}
Manufacturer Filter code
class Manufacturer extends Filter
{
/**
* The filter's component.
*
* #var string
*/
public $component = 'select-filter';
/**
* Apply the filter to the given query.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Database\Eloquent\Builder $query
* #param mixed $value
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Request $request, $query, $value)
{
return $query->whereHas('product', function ($query) use ($value) {
$query->where('manufacturer', $value);
});
}
/**
* Get the filter's available options.
*
* #param \Illuminate\Http\Request $request
*
* #return array
*/
public function options(Request $request)
{
return Product::select('manufacturer')
->withoutGlobalScopes()
->withoutTrashed()
->groupBy('manufacturer')
->orderBy('manufacturer')
->pluck('manufacturer')
->mapWithKeys(function ($manufacturer) {
return [$manufacturer => strtolower($manufacturer)];
})
->toArray();
}
}
Model Filter code
class Model extends Filter
{
/**
* The filter's component.
*
* #var string
*/
public $component = 'select-filter';
/**
* Apply the filter to the given query.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Database\Eloquent\Builder $query
* #param mixed $value
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Request $request, $query, $value)
{
return $query->whereHas('product', function ($query) use ($value) {
$query->where('model', $value);
});
}
/**
* Get the filter's available options.
*
* #param \Illuminate\Http\Request $request
*
* #return array
*/
public function options(Request $request)
{
//
//
//I want to add a condition below ->where('manufacturer', $manufacturer)
//
//
return Product::select('model')
->withoutGlobalScopes()
->withoutTrashed()
->groupBy('model')
->orderBy('model')
->pluck('model')
->mapWithKeys(function ($model) {
return [$model => strtolower($model)];
})
->toArray();
}
}
I tried to decode $request to get the filter values but returns null.
I found the library that helps achieve exactly what I wanted.
The library can be found here: https://github.com/awesome-nova/dependent-filter
Once the above library is installed, the two filters can be set as shown below:
Filter A
<?php
namespace App\Nova\Filters;
use Illuminate\Http\Request;
use App\Models\Product;
use AwesomeNova\Filters\DependentFilter;
class Manufacturer extends DependentFilter
{
/**
* Name of filter.
*
* #var string
*/
public $name = 'Manufacturer';
/**
* Attribute name of filter. Also it is key of filter.
*
* #var string
*/
public $attribute = 'manufacturer';
/**
* The filter's component.
*
* #var string
*/
public $component = 'awesome-nova-dependent-filter';
/**
* Apply the filter to the given query.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Database\Eloquent\Builder $query
* #param mixed $value
* #return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Request $request, $query, $value)
{
return $query->whereHas('product', function ($query) use ($value) {
$query->where('manufacturer', $value);
});
}
/**
* Get the filter's available options.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function options(Request $request, array $filters = [])
{
return Product::select('manufacturer')
->pluck('manufacturer')
->mapWithKeys(function ($manufacturer) {
return [$manufacturer => $manufacturer];
})->toArray();
}
Filter B
<?php
namespace App\Nova\Filters;
use App\Models\Product;
use Illuminate\Http\Request;
use AwesomeNova\Filters\DependentFilter;
class Model extends DependentFilter
{
/**
* Name of filter.
*
* #var string
*/
public $name = 'Model';
/**
* Attribute name of filter. Also it is key of filter.
*
* #var string
*/
public $attribute = 'model';
/**
* The filter's component.
*
* #var string
*/
public $component = 'awesome-nova-dependent-filter';
/**
* The filter's dependentOf.
*
* #var array
*/
public $dependentOf = ['manufacturer'];
public $hideWhenEmpty = true;
/**
* Apply the filter to the given query.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Database\Eloquent\Builder $query
* #param mixed $value
* #return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Request $request, $query, $value)
{
return $query->whereHas('product', function ($query) use ($value) {
$query->where('model', $value);
});
}
/**
* Get the filter's available options.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function options(Request $request, array $filters = [])
{
return Product::select('model')
->where('manufacturer', $filters['manufacturer'])
->pluck('model')
->mapWithKeys(function ($model) {
return [$model => $model];
})->toArray();
}
}
Resource File
public function filters(Request $request)
{
return [
Manufacturer::make(),
Model::make(),
];
}
Currently, I am working on Facade Pattern which doesn't resolve through the application main Container class where i have implement bind method through the interface.
Index.php
use Bundles\Support\Facades\Route;
Route::get('/users', function () {
return 'Hello';
});
Facade:
Route facade
namespace Bundles\Support\Facades;
class Route extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'route';
}
}
Facade.php
namespace Bundles\Support\Facades;
use Bundles\Foundations\Application;
use RuntimeException;
class Facade
{
/**
* The application instance being facaded.
*/
protected static Application $app;
/**
* The resolved object instances.
*
* #var array
*/
protected static $resolvedInstance;
/**
* Indicates if the resolved instance should be cached.
*
* #var bool
*/
protected static $cached = true;
/**
* #param $method
* #param $args
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (!$instance) {
throw new RuntimeException('A facade root has not been set.');
}
var_dump($method, $args, static::getFacadeAccessor());
Application::$app->bind(static::getFacadeAccessor(), $args, $method);
exit;
}
/**
* Get the root object behind the facade.
*
* #return mixed
*/
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Get the registered name of the component.
*
* #throws \RuntimeException
*
* #return string
*/
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
/**
* Resolve the facade root instance from the container.
*
* #param string $name
*
* #return mixed
*/
protected static function resolveFacadeInstance($name)
{
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$app) {
if (static::$cached) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
return static::$app[$name];
}
}
}
Container.php
namespace Bundles\Containers;
use Bundles\Foundations\Application;
use Bundles\Interfaces\Application as ApplicationContract;
use Bundles\Routes\Route;
class Container implements ApplicationContract
{
/**
* #var Route
*/
public Route $router;
/**
* #var Application
*/
public static Application $app;
// register method called in Application constructor
public function register()
{
$this->router = new Route();
}
/**
* > The `bind` function takes a string as the first argument, and a second argument that can be either a string or a
* closure.
*
* #param string abstract The abstract type to bind to
* #param concrete the class name or a closure that returns an instance of the class
* #param shared whether the object should be shared or not
* #param null|mixed $concrete
* #param mixed $shared
*/
public function bind(string $abstract, $concrete = null, $shared = ''): void
{
var_dump($abstract, $concrete);
exit;
}
}
anyone can help on this?
Thanks in advance
I have an application in my local environment and in a production server. This application have a controller called ArticlesController with this code:
<?php
namespace App\Admin\Controllers;
use App\Core\Controllers\CoreController;
use App\Admin\Requests\ArticlesRequest;
use App\Admin\Interfaces\ArticlesRepositoryInterface;
class ArticlesController extends CoreController
{
/**
* #var ArticlesRepositoryInterface
*/
private $articleRepository;
public function __construct(ArticlesRepositoryInterface $articleRepository)
{
$this->articleRepository = $articleRepository;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\View\View
*/
public function index()
{
$articles = $this->articleRepository->all();
return view('admin.articles.index')->with(compact('articles'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\View\View
*/
public function create()
{
return view('admin.articles.create');
}
/**
* Store a newly created resource in storage.
*
* #param \App\Admin\Requests\ArticlesRequest $request
* #return \Illuminate\Routing\Redirector
*/
public function store(ArticlesRequest $request)
{
$data = $request->validated();
$article = $this->articleRepository->create($data);
return redirect()->route('articles.edit', $article)->with('successMessage', 'Article created! Now you can edit the article with new information');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show(int $id)
{
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$article = $this->articleRepository->find($id);
return view('admin.articles.edit')->with(compact('article'));
}
/**
* Update the specified resource in storage.
*
* #param \App\Admin\Requests\ArticlesRequest $request
* #param int $id
* #return \Illuminate\Routing\Redirector
*/
public function update(ArticlesRequest $request, int $id)
{
$data = $request->validated();
$this->articleRepository->update($data, $id);
return redirect()->route('articles.index')->with('successMessage', 'Article updated!');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
$this->articleRepository->delete($id);
return redirect()->route('articles.index')->with('successMessage', 'Article deleted!');;
}
}
How you can see, this controller uses ArticlesRepositoryInterface. This is the code:
<?php
namespace App\Admin\Interfaces;
use App\Admin\Models\Article;
use Illuminate\Database\Eloquent\Collection;
interface ArticlesRepositoryInterface extends BaseRepositoryInterface
{
/**
* #return Collection
*/
public function all(): Collection;
/**
* #param array $data
* #return Article
*/
public function create(array $data): Article;
/**
* #param array $data
* #param int $id
* #return int
*/
public function update(array $data, int $id): int;
/**
* #param int $id
* #return int
*/
public function delete(int $id): int;
/**
* #param int $id
* #return Article
*/
public function find(int $id): ?Article;
}
Also, I have a provider that I use to instantiate the repositories with this code:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Admin\Interfaces\BaseRepositoryInterface;
use App\Admin\Interfaces\ArticlesRepositoryInterface;
use App\Admin\Interfaces\FilesRepositoryInterface;
use App\Admin\Repositories\BaseRepository;
use App\Admin\Repositories\ArticlesRepository;
use App\Admin\Repositories\FilesRepository;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(BaseRepositoryInterface::class, BaseRepository::class);
$this->app->bind(ArticlesRepositoryInterface::class, ArticlesRepository::class);
$this->app->bind(FilesRepositoryInterface::class, FilesRepository::class);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
The code of the BaseRepository is this:
<?php
namespace App\Admin\Repositories;
use App\Admin\Interfaces\BaseRepositoryInterface;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
class BaseRepository implements BaseRepositoryInterface
{
/**
* #var Model
*/
protected $model;
/**
* #param Model $model
*/
public function __construct(Model $model)
{
$this->model = $model;
}
/**
* #return Collection
*/
public function all(): Collection
{
return $this->model->all();
}
/**
* #param array $data
* #return Model
*/
public function create(array $data): Model
{
return $this->model->create($data);
}
/**
* #param array $data
* #param int $id
* #return int
*/
public function update(array $data, int $id): int
{
return $this->model->where('id', $id)->update($data);
}
/**
* #param int $id
* #return int
*/
public function delete(int $id): int
{
return $this->model->destroy($id);
}
/**
* #param int $id
* #return Model
*/
public function find($id): ?Model
{
return $this->model->find($id);
}
}
And finally, the code of the ArticlesRepository is this:
<?php
namespace App\Admin\Repositories;
use App\Admin\Interfaces\ArticlesRepositoryInterface;
use App\Admin\Models\Article;
use Illuminate\Database\Eloquent\Collection;
use App\Admin\Repositories\BaseRepository;
class ArticlesRepository extends BaseRepository implements ArticlesRepositoryInterface
{
/**
* #var Article
*/
protected $article;
/**
* #param Article $article
*/
public function __construct(Article $article)
{
$this->article = $article;
}
/**
* #return Collection
*/
public function all(): Collection
{
return $this->article->all();
}
/**
* #param array $data
* #return Article
*/
public function create(array $data): Article
{
return $this->article->create($data);
}
/**
* #param array $data
* #param int $id
* #return int
*/
public function update(array $data, int $id): int
{
return $this->article->where('id', $id)->update($data);
}
/**
* #param int $id
* #return int
*/
public function delete(int $id): int
{
return $this->article->destroy($id);
}
/**
* #param int $id
* #return Article
*/
public function find($id): ?Article
{
return $this->article->find($id);
}
}
It works perfectly in my local environment, but, is strange, because in the remote server, with exactly the same code, it throws an error:
Declaration of App\Admin\Repositories\ArticlesRepository::create(array $data): App\Admin\Models\Article must be compatible with App\Admin\Repositories\BaseRepository::create(array $data): Illuminate\Database\Eloquent\Model
Any ideas?
All function declarations should be exactly the same, including the return type declarations:
ArticlesRepositoryInterface:
public function create(array $data): Article;
BaseRepository:
public function create(array $data): Model
ArticlesRepository:
public function create(array $data): Article;
App\Admin\Models\Article and Illuminate\Database\Eloquent\Model cannot be used both.
Perhaps this doesn't throw an exception locally because of a different PHP version?
Note: you might want to consider to extend all the repositories from a single BaseRepository.
I am trying to make rest api with dingo for laravel 5.3 . I have setup dingo on my project and created a api route like this for test .
$api->version('v1', function ($api) {
$api->get('hello',function (){
return "hello";
});
});
But when i run http://localhost:8000/api/hello
Then
{
message: "Call to undefined method Illuminate\Routing\Route::getUri()",
code: 1,
status_code: 500,
debug: {
line: 98,
file: "C:\xampp\htdocs\apiTest\vendor\dingo\api\src\Routing\Adapter\Laravel.php",
class: "Symfony\Component\Debug\Exception\FatalErrorException",
trace: [
"#0 {main}"
]
}
}
is shown .
i have searched and find this solution
Call to undefined method Illuminate\Routing\Route::get()
but when i used
use Illuminate\Support\Facades\Route;
then this problem shown
FatalErrorException in Laravel.php line 116:
Call to undefined method Illuminate\Support\Facades\Route::where()
This is the Laravel.php file
<?php
namespace Dingo\Api\Routing\Adapter;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Routing\Router;
use Illuminate\Routing\RouteCollection;
use Dingo\Api\Contract\Routing\Adapter;
use Dingo\Api\Exception\UnknownVersionException;
class Laravel implements Adapter
{
/**
* Laravel router instance.
*
* #var \Illuminate\Routing\Router
*/
protected $router;
/**
* Array of registered routes.
*
* #var array
*/
protected $routes = [];
/**
* Old routes already defined on the router.
*
* #var \Illuminate\Routing\RouteCollection
*/
protected $oldRoutes;
/**
* Create a new laravel routing adapter instance.
*
* #param \Illuminate\Routing\Router $router
*
* #return void
*/
public function __construct(Router $router)
{
$this->router = $router;
}
/**
* Dispatch a request.
*
* #param \Illuminate\Http\Request $request
* #param string $version
*
* #return mixed
*/
public function dispatch(Request $request, $version)
{
if (! isset($this->routes[$version])) {
throw new UnknownVersionException;
}
$routes = $this->mergeExistingRoutes($this->routes[$version]);
$this->router->setRoutes($routes);
return $this->router->dispatch($request);
}
/**
* Merge the existing routes with the new routes.
*
* #param \Illuminate\Routing\RouteCollection $routes
*
* #return \Illuminate\Routing\RouteCollection
*/
protected function mergeExistingRoutes(RouteCollection $routes)
{
if (! isset($this->oldRoutes)) {
$this->oldRoutes = $this->router->getRoutes();
}
foreach ($this->oldRoutes as $route) {
$routes->add($route);
}
return $routes;
}
/**
* Get the URI, methods, and action from the route.
*
* #param mixed $route
* #param \Illuminate\Http\Request $request
*
* #return array
*/
public function getRouteProperties($route, Request $request)
{
return [$route->getUri(), $route->getMethods(), $route->getAction()];
}
/**
* Add a route to the appropriate route collection.
*
* #param array $methods
* #param array $versions
* #param string $uri
* #param mixed $action
*
* #return \Illuminate\Routing\Route
*/
public function addRoute(array $methods, array $versions, $uri, $action)
{
$this->createRouteCollections($versions);
$route = new Route($methods, $uri, $action);
$route->where($action['where']);
foreach ($versions as $version) {
$this->routes[$version]->add($route);
}
return $route;
}
/**
* Create the route collections for the versions.
*
* #param array $versions
*
* #return void
*/
protected function createRouteCollections(array $versions)
{
foreach ($versions as $version) {
if (! isset($this->routes[$version])) {
$this->routes[$version] = new RouteCollection;
}
}
}
/**
* Get all routes or only for a specific version.
*
* #param string $version
*
* #return mixed
*/
public function getRoutes($version = null)
{
if (! is_null($version)) {
return $this->routes[$version];
}
return $this->routes;
}
public function getIterableRoutes($version = null)
{
return $this->getRoutes($version);
}
/**
* Set the routes on the adapter.
*
* #param array $routes
*
* #return void
*/
public function setRoutes(array $routes)
{
$this->routes = $routes;
}
/**
* Prepare a route for serialization.
*
* #param mixed $route
*
* #return mixed
*/
public function prepareRouteForSerialization($route)
{
$route->prepareForSerialization();
return $route;
}
/**
* Gather the route middlewares.
*
* #param \Illuminate\Routing\Route $route
*
* #return array
*/
public function gatherRouteMiddlewares($route)
{
return $this->router->gatherRouteMiddlewares($route);
}
}
Has there any solution ?
Thanks
Use $route->uri()
insted of $route->getUri()
create a pull request to dingo api after updating this