Permalink
Browse files

Initial commit (cloned from movor/laravel-custom-casts v0.2.1)

  • Loading branch information...
vkovic committed Dec 5, 2018
0 parents commit dad19fc606bcbee0441688b4d72370c0dd27a043
@@ -0,0 +1,25 @@
#
# OS generated files and junk
#

.DS_Store
.DS_Store?
._*
Thumbs.db
Icon?
.Trashes
ehthumbs.db
*.log

#
# PhpStorm
#

.idea

#
# Project
#

vendor
composer.lock
@@ -0,0 +1,14 @@
language: php

php:
- 7.0
- 7.1
- 7.2

before_script:
- composer self-update
- composer install --prefer-source --no-interaction
- composer dump-autoload

script:
- vendor/bin/phpunit
21 LICENCE
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2018 Vladimir Ković

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
166 README.md
@@ -0,0 +1,166 @@
# Laravel Custom Casts

[![Build](https://api.travis-ci.org/vkovic/laravel-custom-casts.svg?branch=master)](https://travis-ci.org/vkovic/laravel-custom-casts)
[![Downloads](https://poser.pugx.org/vkovic/laravel-custom-casts/downloads)](https://packagist.org/packages/vkovic/laravel-custom-casts)
[![Stable](https://poser.pugx.org/vkovic/laravel-custom-casts/v/stable)](https://packagist.org/packages/vkovic/laravel-custom-casts)
[![License](https://poser.pugx.org/vkovic/laravel-custom-casts/license)](https://packagist.org/packages/vkovic/laravel-custom-casts)

### Make your own custom cast type for Laravel model attributes

By default, from version 5 Laravel supports attribute casting. If we define `$cast` property on our model, Laravel will
help us convert defined attributes to common data types. Currently supported cast types (Laravel 5.6) are: `integer`,
`real`, `float`, `double`, `string`, `boolean`, `object`, `array`, `collection`, `date`, `datetime` and `timestamp`.

If those default cast types are not enough and you want to make your own, you'r on the right track.

---

## Compatibility

The package is compatible with Laravel versions `>= 5.1`

## Installation

Install the package via composer:

```bash
composer require vkovic/laravel-custom-casts
```

## Example: Casting User Image

When saving an image, there is two things that needs to be done:
1. Save image name (sometimes with path) into corresponding database field
2. Save image physically on the disk

As a guidance for this example we'll use default Laravel user model found in `app/User.php`.

Beside basic, predefined fields: `name`, `email` and `password`, we also want to allow user to upload his avatar. Assume
that we already have `users` table with `image` field (you should create seeder for this).

To utilize custom casts, we'll need to add trait to user model, and via `$casts` property link it to the cast class.

```php
// File: app/User.php
namespace App;
use App\CustomCasts\ImageCast;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Vkovic\LaravelCustomCasts\HasCustomCasts;
class User extends Authenticatable
{
use Notifiable, HasCustomCasts;
protected $fillable = [
'name', 'email', 'password', 'image'
];
protected $hidden = [
'password', 'remember_token'
];
protected $casts = [
'image' => ImageCast::class
];
}
// ...
```

Next step is to create class that'll handle casting. It must implement `setAttribute` method which will take care of
saving the image (from UploadedFile object, via form upload in this case) and generating image name with path - to be preserved in database.

```php
// File: app/CustomCasts/ImageCast.php
namespace App\CustomCasts;
use Vkovic\LaravelCustomCasts\CustomCastBase;
use Illuminate\Http\UploadedFile;
class ImageCast extends CustomCastBase
{
public function setAttribute($file)
{
// Define storage folder
// (relative to "storage/app" folder in Laravel project)
// Don't forget to create it !!!
$storageDir = 'images';
// Generate random image name
$filename = str_random() . '.' . $file->extension();
// Save image to predefined folder
$file->storeAs($storageDir, $filename);
// This will be stored in db field: "image"
return $storageDir . '/' . $filename;
}
}
```

Let's jump to user creation example. This will trigger our custom cast logic.

Assume that we have user controller which will handle user creation. You should create this on your
own.

> Code below is just a simple example and should be used as guidance only.
```php
// File: app/Http/Controllers/UserController.php
// ...
protected function create(Request $request)
{
User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password),
// Past the whole Illuminate\Http\UploadedFile object,
// we'll handle it in our ImageCast class
'image' => $request->file('image')
]);
}
// ...
```

Visit corresponding route input basic details and attach the image. After that, we'll have our user created and image
stored.

But we should also handle deleting image when user is deleted. This can be accomplished by utilizing underlying eloquent
events handling. Each time eloquent event is fired, logic will look up for public method with the same name in our custom
cast class.

Possible method names are:
`retrieved`, `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring` and
`restored`.

```php
// File: app/CustomCasts/ImageCast.php
// Add at the top
use Storage;
// ...
// This method will be triggered after model has been deleted
public function deleted()
{
// We can access underlying model with $this->model
// and attribute name that is being casted with $this->attribute
// Retrieve image path and delete it from the disk
$imagePath = $this->model->image;
Storage::delete($imagePath);
}
// ...
```

This should cover basics usage of custom casts.
@@ -0,0 +1,41 @@
{
"name": "vkovic/laravel-custom-casts",
"description": "Make your own custom cast type for Laravel model attributes",
"keywords": [
"laravel",
"model",
"casts",
"cast",
"datatype"
],
"license": "MIT",
"authors": [
{
"name": "Vladimir Ković",
"email": "vlada.kovic@gmail.com"
}
],
"autoload": {
"psr-4": {
"Vkovic\\LaravelCustomCasts\\": "src/package"
}
},
"autoload-dev": {
"psr-4": {
"Vkovic\\LaravelCustomCasts\\Test\\": "tests"
}
},
"require": {
"php": "^7.0",
"laravel/framework": "5.5.*|5.6.*|5.7.*"
},
"require-dev": {
"orchestra/testbench": "3.5.*|3.6.*|3.7.*",
"orchestra/database": "3.5.*|3.6.*|3.7.*",
"phpunit/phpunit": "^6.3|^7.0"
},
"scripts": {
"test": "vendor/bin/phpunit"
},
"minimum-stability": "dev"
}
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="LaravelCustomCasts Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
</phpunit>
@@ -0,0 +1,53 @@
<?php
namespace Vkovic\LaravelCustomCasts;
use Illuminate\Database\Eloquent\Model;
abstract class CustomCastBase
{
/**
* Model
*
* @var Model
*/
protected $model;
/**
* Corresponding db field (model attribute name)
*
* @var string
*/
protected $attribute;
public function __construct(Model $model, $attribute)
{
$this->model = $model;
$this->attribute = $attribute;
}
/**
* Enforce implementation in child classes
*
* Intercept value passed to model under specified field ($attribute)
* and change it to our will, and/or add some logic, before it's going
* to be saved to database
*
* @param mixed $value Default value passed to model attribute
*
* @return mixed
*/
abstract public function setAttribute($value);
/**
* Cast attribute (from db value to our custom format)
*
* @param mixed $value Value from database field
*
* @return mixed|null Our customized value
*/
public function castAttribute($value)
{
return $value;
}
}
Oops, something went wrong.

0 comments on commit dad19fc

Please sign in to comment.