HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/farmfun/reserveren.farmfun.be/app/Http/Middleware/WildcardResolver.php
<?php

namespace App\Http\Middleware;

use App\Http\Wildcards\WildcardInterface;
use App\Komma\Routes\Models\Route;
use Closure;
use Illuminate\Http\Request;

final class WildcardResolver extends AbstractResolver
{
    private static $wildcardFileNamespace = 'App\Http\Wildcards\\';

    /**
     * @param Request $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // Check if route should be excluded from resolving
        if ($this->isExcludedFromResolving($request)) {
            return $next($request);
        }
        $this->log('trying to resolve uri: '.$request->path());

        // Check if route is already resolved
        if ($this->isRouteResolved($request)) {
            $this->log('Request already resolved. Ignoring it. WildcardResolver done.');

            return $next($request);
        }

        $wildcardRoute = $this->getWildcardRoute($request);

        //The request did not represent a wildcard route. So pass the request further into the application and return that.
        if (! $wildcardRoute) {
            $this->log('Request was not a wildcard. Ignoring it. WildcardResolver done.');

            return $next($request);
        }

        $wildcardTail = $this->getWildcardTail($request, $wildcardRoute);
        $this->log('WildcardRoute tail: '.$wildcardTail);

        // Create wildcard instance for type
        $wildcardFQCN = $this->getWildcardFQCN($wildcardRoute->route.'Wildcard'); //The value of the route for example is "products".
        /** @var WildcardInterface $wildcardInstance */
        $wildcardInstance = new $wildcardFQCN;

        //Duplicate the request so we can generate an restful Request
        $modifiedRequest = $request->duplicate();

        // Append original path, else have to done some ugly shit to grab it again
        $modifiedRequest->attributes->add([
            'original_path' => $request->url(),
        ]);

        // Let the wildcard instance handle the rest of resolving
        $modifiedRequest = $wildcardInstance->handle($modifiedRequest, $wildcardRoute, $wildcardTail);

        // If the wildcardInstance didn't modify the request return it
        if ($modifiedRequest->path() === $request->path()) {
            $this->log($wildcardFQCN.' did not modified the request so proceed to the next resolver');

            return $next($request);
        }

        $this->log($wildcardFQCN.' Modified the request so that it\'s url became: '.$modifiedRequest->getUri());

        //Set the resolved key on the request to tell other route solving things that they don't need to resolve
        $modifiedRequest = $this->setRouteResolved($modifiedRequest);

        return $next($modifiedRequest);
    }

    /**
     * Use the request path (for example: /nl/producten/onderste-balk-plastic-aluminium) to find a wildcardRoute model
     * That matches most of the url. E.g: /nl/producten.
     * If it cannot be found, it will return null instead.
     *
     * @param Request $request
     * @return Route|null
     */
    private function getWildcardRoute(Request $request)
    {
        //request->segments() example value: [ 'nl', 'producten', 'onderste-balk-plastic-aluminium'] in an url of: http://localhost:8000/nl/producten/onderste-balk-plastic-aluminium
        $firstSegments = $request->segments();
        $wildcardRoutes = Route::where('route', 'not like', '%/%')->get(); //The "not like" leaves out the route records which contain forward slashes. These are alias routes.
        $wildcardRoute = null;
        //Pop the last element from the firstSegments array and put it in the currentSegment variable. Shortening $firstSegments by one. Use firstSegments array to find a wildcard route.
        while ($currentSegment = array_pop($firstSegments) && $wildcardRoute == null) {
            //First loop iteration example of value of firstSegments: ['nl', 'producten']
            $route = '/'.implode('/', $firstSegments); //First loop iteration example value of route: /nl/producten
            $this->log('Checking if there is a route with a route value of: "'.$route.'"');
            if ($route == '/') {
                continue;
            } // The route / never is a wildcard. So continue to a next iteration.

            //Check if the route can be found. If not and if we still have firstSegments, run the next loop iteration.
            $wildcardRoute = $wildcardRoutes->where('alias', '=', $route)->first(); //The "not like" leaves out the route records which contain forward slashes. These are alias routes.
        }
        if ($wildcardRoute) {
            $this->log('Wildcard Route found for route: "'.$wildcardRoute->route.'". Id: "'.$wildcardRoute->id.'".');
        } else {
            $this->log('No wildcard route found.');
        }

        return $wildcardRoute;
    }

    /**
     * Strips the wildcardRoute's route from the request. Whats left over is the tail.
     * and that's what is going to be returned.
     *
     * Example: Consider that the request path is: /nl/producten/onderste-balk-plastic-aluminium
     * And that the wildcardRoute's route is /nl/producten.
     * The tail part that is going to be returned will be onderste-balk-plastic-aluminium.
     *
     * @param Request $request
     * @param Route $wildcardRoute
     * @return string
     */
    private function getWildcardTail(Request $request, Route $wildcardRoute): string
    {
        return str_replace($wildcardRoute->alias.'/', '', '/'.$request->path());
    }

    /**
     * Gets the fully qualified class name from a wild card name.
     * For example when you pass 'Products' it will return 'App\Http\Wildcards\Products'
     *
     * @param string $wildcardClass
     * @return string
     */
    private function getWildcardFQCN(string $wildcardClass):string
    {
        $wildcardFQCN = static::$wildcardFileNamespace.ucfirst($wildcardClass);

        if (! self::wildcardExists($wildcardClass)) {
            throw new \InvalidArgumentException($wildcardFQCN." does not exist or it wasn't an implementation of ".WildcardInterface::class);
        }

        return $wildcardFQCN;
    }

    /**
     * Checks if a given name can be resolved to a FQCN in the PSR-4 wildcardFileNamespace path.
     * Returns true if it exist and implements the WildcardInterface. false if not.
     *
     * @param string $wildcardClass
     * @return bool
     */
    public static function wildcardExists(string $wildcardClass)
    {
        $wildcardFQCN = static::$wildcardFileNamespace.ucfirst($wildcardClass);

        if (! class_exists($wildcardFQCN) || ! is_a($wildcardFQCN, WildcardInterface::class, true)) {
            return false;
        }

        return true;
    }
}