I am using Laravel 5's Command Bus and I am unclear how to implement a validator class
Asked Answered
N

2

9

I am using Laravel 5's Command Bus and I am unclear how to implement a validator class.

I would like to create a ResizeImageCommandValidator class that checks that the image is actually an image before attempting to resize the image.

The code I'd like to pull out is here from the ResizeImageCommandHandler resize method.

if (!($image instanceof Image))
{
    throw new ImageInvalidException('ResizeImageCommandHandler');
}

The idea came from Laracasts Commands and Domain Events, but Jeffrey doesn't use the Laravel 5 architecture.

Here's the code.

ResizeImageCommandHandler.php

<?php namespace App\Handlers\Commands;

use App\Commands\ResizeImageCommand;

use App\Exceptions\ImageInvalidException;
use Illuminate\Queue\InteractsWithQueue;
use Intervention\Image\Image;

class ResizeImageCommandHandler {

    /**
     * Create the command handler.
     */
    public function __construct()
    {
    }
    /**
     * Handle the command.
     *
     * @param  ResizeImageCommand  $command
     * @return void
     */
    public function handle($command)
    {
        $this->resizeImage($command->image, $command->dimension);
    }
    /**
     * Resize the image by width, designed for square image only
     * @param Image $image Image to resize
     * @param $dimension
     * @throws ImageInvalidException
     */
    private function resizeImage(&$image, $dimension)
    {
        if (!($image instanceof Image))
        {
            throw new ImageInvalidException('ResizeImageCommandHandler');
        }
        $image->resize($dimension, null, $this->constrainAspectRatio());
    }
    /**
     * @return callable
     */
    private function constrainAspectRatio()
    {
        return function ($constraint) {
            $constraint->aspectRatio();
        };
    }


}      

ResizeImageCommand.php

<?php namespace App\Commands;

use App\Commands\Command;

use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use Image;

class ResizeImageCommand extends Command {
    use InteractsWithQueue, SerializesModels;

    public $image;
    public $savePath;
    public $dimension;

    /**
     * Create a new command instance.
     * @param Image $image
     * @param string $savePath
     * @param int $dimension
     * @param int $pose_id
     * @param int $state_id
     */
    public function __construct(&$image, $savePath, $dimension)
    {
        $this->image = $image;
        $this->savePath = $savePath;
        $this->dimension = $dimension;
    }

}
Nunes answered 30/4, 2015 at 0:32 Comment(4)
just questioning, I'm not sure as well. Why not use a Request using mime in rule ? laravel.com/docs/5.0/validation#rule-mimesBitch
@Bitch I am passing in an instance of Image by reference so I can resize it. I need to validate that the object that I am sending is of that type so I can call the image resize on it. At this point it doesn't have a mime type because it is a native php resource.Nunes
In that case why not using Type Hinting on $image?Bitch
That would work if it was the only thing I wanted to check, but I'd like to eventually have a finer level of control then just is an Image object which will require a validator. My example has been simplified, but it could also check to make sure the image to be resized is of a certain dimension and type. This code works as is, I just want to clean it up.Nunes
M
4

In an attempt to answer your question, I suggest don't get too hung up on the Command part of it. In Laravel 5.1 that folder is being renamed to "Jobs" - refer to;

https://laravel-news.com/2015/04/laravel-5-1/

This is precisely because Taylor felt folks were getting too stuck on the word "Command."

See also http://www.laravelpodcast.com/episodes/6823-episode-21-commands-pipelines-and-packages and https://laracasts.com/lessons/laravel-5-commands

The validator classes in the Illuminate packages are pretty great, http://laravel.com/api/5.0/Illuminate/Validation/Validator.html - I'm not sure what the issue is with that, I guess.

I'd say that unless you have a compelling reason to use a Command class for this, don't. also see: http://www.laravelpodcast.com/episodes/9313-episode-23-new-beginnings-envoyer-laravel-5-1

I humbly suggest you may have asked the wrong question, and maybe you don't need to use a Command to handle this.

This is probably the answer you're looking for: https://mattstauffer.co/blog/laravel-5.0-validateswhenresolved

use Illuminate\Contracts\Validation\ValidatesWhenResolved;

and if that doesn't work, sign up for Larachat, http://larachat.co/ - a Slack channel for just this sort of thing. Best place ever for Laravel help. (except Stack Overflow, of course)

Here's a little class I use for checking the format of an image, also, thought you might find it useful.

<?php
Class FileUploadFormat
{
public function is_image($image_path)
  {
      if (!$f = fopen($image_path, 'rb'))
      {
          return false;
      }

      $data = fread($f, 8);
      fclose($f);

      // signature checking
      $unpacked = unpack("H12", $data);
      if (array_pop($unpacked) == '474946383961' || array_pop($unpacked) == '474946383761') return "gif";
      $unpacked = unpack("H4", $data);
      if (array_pop($unpacked) == 'ffd8') return "jpg";
      $unpacked = unpack("H16", $data);
      if (array_pop($unpacked) == '89504e470d0a1a0a') return "png";
      return false;
  }
}
Millsap answered 12/5, 2015 at 18:10 Comment(3)
Also; as far as an image-manipulation package, I'd highly recommend: packagist.org/packages/league/glideMillsap
Thanks for the answer. Regardless of the name (Command or Job) I am looking for the best way to validate the data sent over in this command. After writing this I realized that an Image might not be the case study. I will check out Matt's post and see how it works.Nunes
I think this: mattstauffer.co/blog/… - is the bit you want.Millsap
I
2

You could use Laravel 5's FormRequest class to capture your request before it is even sent to the Command Bus:

public function postResizeImage(ResizeImageRequest $request) {
    // Send request to the Command Bus
}

Then in your ResizeImageRequest class, put in the rules, you might need custom validation for validating whether the uploaded file is in fact an image.

You could use https://packagist.org/packages/intervention/image to work with image files. Or you could use this https://github.com/cviebrock/image-validator

Ask me if you need further help on this

Intervene answered 11/5, 2015 at 7:10 Comment(3)
I believe there is a decorator pattern, but I am unclear on how it is implemented. I don't really want to use a package for something that is built in.Nunes
You can learn Decorator Pattern the easy way here: laracasts.com/lessons/the-decorator-patternIntervene
@Nunes it is not a Decorator. It is a simple Method Injection. It injects Form Request object into your controller method that will automatically validate your request right before it is processed by your controller code laravel.com/docs/master/validation#form-request-validationJentoft

© 2022 - 2024 — McMap. All rights reserved.