Fixing Symlinks on Windows

“The symbolic link cannot be followed because it’s type is disabled.”

Quite an easy fix tbh, you can check status with this command:

mintty screen dump

fsutil behavior query SymlinkEvaluation
Local to local symbolic links are enabled.
Local to remote symbolic links are enabled.
Remote to local symbolic links are disabled.
Remote to remote symbolic links are disabled.

As you can see, network symlinks are disabled on this machine in work I’m on. To fix it, run the following:

mintty screen dump

fsutil behavior set SymlinkEvaluation R2R:1
fsutil behavior set SymlinkEvaluation R2L:1

That fixes remote to remote (R2R) and remote to local (R2L), obviously the other two types are L2R and L2L.

Fixed!

Middleware all the things

Image result for middleware psr 15

The middleware pattern is really awesome, you have layers of midlleware classes that take a request and return a reponse, but pass to a handler first, eventually reaching the original callable your request routed to.

My framework Bone MVC makes use of PSR-7 requests, so I’ve been refactoring for v3.0.0 to use league/route and it’s middleware stack, and I’ve just realised a great use case, so I’m about to refactor and create a middleware!

Take a look at this controller action:

/**
* @param ServerRequestInterface $request
* @param array $args
* @return ResponseInterface
* @throws \Doctrine\ORM\EntityNotFoundException
*/
public function viewAction(ServerRequestInterface $request, array $args): ResponseInterface
{
$dragon = $this->service->getRepository()->find($args['id']);
$server = $request->getServerParams();
$hal = [
'_links' => [
'self' => [
'href' => $server['REQUEST_SCHEME'] . '://' . $server['SERVER_NAME'] . '/api/dragon/' . $args['id']
]
],
];
$payload = array_merge($hal, $dragon->toArray());

return new JsonResponse($payload);
}

As well as returning the entity in array format to the JSON response, I’m also creating HAL content negotiation. I was about to do the same for the index listing the collection of entities, when i thought I could simplify my controller by taking HAL stuff out of it!

The middleware signature looks like this:

namespace Psr\Http\Server;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
 * Participant in processing a server request and response.
 *
 * An HTTP middleware component participates in processing an HTTP message:
 * by acting on the request, generating the response, or forwarding the
 * request to a subsequent middleware and possibly acting on its response.
 */
interface MiddlewareInterface
{
    /**
     * Process an incoming server request.
     *
     * Processes an incoming server request in order to produce a response.
     * If unable to produce the response itself, it may delegate to the provided
     * request handler to do so.
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;
}

So first up I’ll create my Middleware class and make it do nothing but pass stuff along as it was received

<?php

namespace Bone\Http\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class HalEntity implements MiddlewareInterface
{
    /**
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        return $handler->handle($request);
    }
}

Then register the middleware on your stack. For myself using league/router, you can add middleware to all routes, groups of routes, or individual routes, which is what I’ll do here:

$route->map('GET', '/dragon/{id:number}', [DragonApiController::class, 'viewAction'])
->middleware(new HalEntity());

A quick check, and yes, the page is still loading as per normal. So now to get the refactoring done!

First we strip out the HAL link stuff and the array merge, and move it to a class impolementing the PSR middleware interface, to make it look like this:

<?php

namespace Bone\Http\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class HalEntity implements MiddlewareInterface
{
/**
* @param ServerRequestInterface $request
* @param RequestHandlerInterface $handler
* @return ResponseInterface
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$uri = $request->getUri();

$hal = [
'_links' => [
'self' => [
'href' => $uri->getScheme() . '://' . $uri->getHost() . $uri->getPath(),
]
],
];

$response = $handler->handle($request);

$data = \json_decode($response->getBody()->getContents(), true);
$data = \array_merge($hal, $data);

$body = $response->getBody();
$body->rewind();
$body->write(\json_encode($data));

return $response->withBody($body);
}
}

And your controller action will look like this 🙂 :

/**
 * @param ServerRequestInterface $request
 * @param array $args
 * @return ResponseInterface
 * @throws \Doctrine\ORM\EntityNotFoundException
 */
public function viewAction(ServerRequestInterface $request, array $args): ResponseInterface
{
    $dragon = $this->service->getRepository()->find($args['id']);

    return new JsonResponse($dragon->toArray() );
}