diff --git a/readme.md b/readme.md
index 4ee9091..face561 100644
--- a/readme.md
+++ b/readme.md
@@ -4,9 +4,9 @@
Imagic is a Laravel Nova field package that allows for image manipulation capabilities, such as cropping, resizing, quality adjustment, and WebP conversion. It utilizes the powerful Intervention Image class for image manipulation. The purpose of this package is to optimize images for web usage by converting them to the WebP format, which provides superior compression and faster load times.
Advanced Image Manipulation Made Easy with Images Magic
-
✅ Multiple Uploads
✅ Cropping
✅ Resizing
+
✅ Single/Multiple Uploads
✅ Cropping
✅ Resizing
✅ Fitting
✅ Quality Control
✅ WebP Conversion
-
✅ Watermarking
+
✅ Watermarking
✅ Custom Directories
[![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-Donate-yellow?style=for-the-badge&logo=buymeacoffee)](https://www.buymeacoffee.com/ayvazyan403)
@@ -48,6 +48,7 @@ Imagic::make('Image')
->resize($width, $height)
->fit($width, $height)
->quality($quality)
+ ->directory($path)
->convert($convert = true)
->watermark($path, $position = 'bottom-right', $x = 0, $y = 0);
````
@@ -91,6 +92,29 @@ Remember to import the Imagic class at the top of your Nova resource file:
``` php
Imagic::make('Image')->watermark('/path/to/watermark.png', 'bottom-right', 15, 15),
```
+#### - Directory Customization
+BY DEFAULT - Imagic uses this structure: /storage/imagic/year/month/day/image_name.webp
+
+The Imagic class includes a directory() method that allows you to specify a custom directory path for your image uploads. This allows for more flexibility in managing the location of your image files.
+
+To use this feature, call the directory() method when creating an Imagic field and provide it with your custom directory path as an argument. This path should be a string, and should not start or end with a /.
+
+Here is an example of how to use it:
+``` php
+Imagic::make('Image')->directory('your/custom/directory')
+```
+In this example, any images uploaded through this field will be saved in your/custom/directory.
+
+Caution:
+The provided directory path should not start or end with a /. If it does, an InvalidArgumentException will be thrown. Make sure your directory path is correctly formatted when using this feature.
+
+For example, the following code would throw an exception:
+``` php
+// This will throw an exception because the directory path starts with a '/'
+// Directory structure should not start or end with a slash. Only in the middle.
+Imagic::make('Image')
+ ->directory('/invalid/directory/path')
+```
## Contributing
diff --git a/src/Imagic.php b/src/Imagic.php
index baa7643..a07dffa 100644
--- a/src/Imagic.php
+++ b/src/Imagic.php
@@ -3,6 +3,9 @@
namespace Ayvazyan10\Imagic;
use Carbon\Carbon;
+use Exception;
+use Illuminate\Support\Str;
+use InvalidArgumentException;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Http\Requests\NovaRequest;
use Intervention\Image\ImageManagerStatic as Image;
@@ -16,6 +19,13 @@ class Imagic extends Field
*/
public $component = 'imagic';
+ /**
+ * Optional custom upload directory.
+ *
+ * @var string|null
+ */
+ public string|null $customUploadDirectory = null;
+
/**
* A boolean flag indicating whether the field should allow multiple image
*
@@ -79,19 +89,38 @@ class Imagic extends Field
*
* @var int
*/
- public $quality = 90;
+ public int $quality = 90;
/**
* The Intervention Image driver, default: gd, alternative: imagick
*
- * @var int
+ * @var string|int
*/
- public $driver = 'gd';
+ public string|int $driver = 'gd';
/**
* The Intervention Image instance used for magic image manipulations.
*/
public $image;
+ protected $directory;
+
+ /**
+ * Allow the user to set a custom upload directory.
+ *
+ * @param string $path
+ * @return $this
+ * @throws InvalidArgumentException
+ */
+ public function directory(string $path): static
+ {
+ if (Str::startsWith($path, '/') || Str::endsWith($path, '/')) {
+ throw new InvalidArgumentException('Directory structure should not start or end with a slash. Only in the middle.');
+ }
+
+ $this->customUploadDirectory = $path;
+
+ return $this;
+ }
/**
* Enable watermarking and specify the watermark image path.
@@ -167,7 +196,7 @@ public function crop(int $width = null, int $height = null, int $left = 0, int $
* @param int|null $height
* @return $this
*/
- public function resize($width = null, $height = null): static
+ public function resize(int $width = null, int $height = null): static
{
$this->resizeWidth = $width;
$this->resizeHeight = $height;
@@ -179,9 +208,14 @@ public function resize($width = null, $height = null): static
* Set whether the field should allow multiple image uploads.
*
* @return $this
+ * @throws Exception
*/
public function quality(int $quality): static
{
+ if ($quality < 0 || $quality > 100) {
+ throw new Exception('The quality must ranges from 0 to 100.');
+ }
+
$this->quality = $quality;
return $this;
@@ -191,9 +225,14 @@ public function quality(int $quality): static
* Set whether the field should allow multiple image uploads.
*
* @return $this
+ * @throws Exception
*/
public function driver(string $driver): static
{
+ if (!in_array($driver, ['gd', 'imagick'])) {
+ throw new Exception("The driver \"$driver\" is not a valid Intervention driver.");
+ }
+
$this->driver = $driver;
return $this;
@@ -229,9 +268,6 @@ public function __construct($name, $attribute = null)
'day' => Carbon::now()->format('d')
];
- // configure with favored image driver (gd by default)
- Image::configure(['driver' => $this->driver]);
-
$this->directory = (object)$directory;
}
@@ -278,7 +314,7 @@ protected function fillAttribute(NovaRequest $request, $requestAttribute, $model
*/
protected function imageMagic($requestAttribute): string|array
{
- $destinationPath = public_path('storage/imagic/' . $this->directory->year . '/' . $this->directory->month . '/' . $this->directory->day . '/');
+ $destinationPath = public_path(empty($this->customUploadDirectory) ? 'storage/imagic/' . $this->directory->year . '/' . $this->directory->month . '/' . $this->directory->day . '/' : $this->customUploadDirectory . '/');
if (!is_dir($destinationPath)) {
mkdir($destinationPath, 0775, true);
@@ -300,6 +336,8 @@ protected function imageMagic($requestAttribute): string|array
public function imageManipulations($image, $destinationPath): string
{
+ // configure with favored image driver (gd by default)
+ Image::configure(['driver' => $this->driver]);
$this->image = Image::make($image->getRealPath());
@@ -328,7 +366,11 @@ public function imageManipulations($image, $destinationPath): string
$this->resizeMagic();
}
- $image_url = '/storage/imagic/' . $this->directory->year . '/' . $this->directory->month . '/' . $this->directory->day . '/' . $imageName;
+ if (!empty($this->customUploadDirectory)) {
+ $image_url = '/' . $this->customUploadDirectory . '/' . $imageName;
+ } else {
+ $image_url = '/storage/imagic/' . $this->directory->year . '/' . $this->directory->month . '/' . $this->directory->day . '/' . $imageName;
+ }
$this->image->save($destinationPath . $imageName, $this->quality, $this->convert === false ? null : 'webp');
$this->image->destroy();