Skip to content

Instantly share code, notes, and snippets.

@Bunix
Forked from cjthomp/50 Laravel Tricks.md
Created October 10, 2018 08:21
Show Gist options
  • Save Bunix/1d1257de5b43b427bbfa10dca2daea5a to your computer and use it in GitHub Desktop.
Save Bunix/1d1257de5b43b427bbfa10dca2daea5a to your computer and use it in GitHub Desktop.
50 Laravel Tricks

Reference

  1. https://speakerdeck.com/willroth/50-laravel-tricks-in-50-minutes
  2. https://www.reddit.com/r/laravel/comments/3to60i/50_laravel_tricks/

ELOQUENT

1. Automatic Model Validation

class Post extends Eloquent
{
	public staic $autoValidates = true;

	protected static $rules = [];

	protected static function boot()
	{
		parent::boot();

		// or static::creating, or static::updating
		static::saving(function($model)
		{
			if ($model::$autoValidates) {
				return $model->validate();
			}
		});
	}

	public function validate()
	{

	}
}

2. Prevent updating

class Post extends Eloquent
{
	protected static function boot()
	{
		parent::boot();

		static::updating(function($model)
		{
			return false;
		});
	}
}

3. Conditional Relationships

class myModel extends Model
{
	public function category()
	{
		return $this->belongsTo('myCategoryModel', 'categories_id')
			->where('users_id', Auth::user()->id);
	}
}

4. Expressive "Where" Syntax

$products = Product::where('category', '=', 3)->get();

$products = Product::where('category', 3)->get();

$products = Product::whereCategory(3)->get();

5. Query Builder: Having Raw

SELECT *, COUNT(*) FROM products GROUP BY category_id HAVING count(*) > 1;

DB::table('products')
	->select('*', DB::raw('COUNT(*) as products_count'))
	->groupBy('category_id')
	->having('products_count', '>', 1)
	->get();

6. Simple Date Filtering

$q->whereDate('created_at', date('Y-m-d'));

$q->whereDay('created_at', date('d'));

$q->whereMonth('created_at', date('m'));

$q->whereYear('created_at', date('Y'));

7. Save Options

// src/Illuminate/Database/Eloquent/Model.php
public function save(array $options = [])

// src/Illuminate/Database/Eloquent/Model.php
protected function performUpdate(Builder $query, array $options=[])
{
	if ($this->timestamps && array_get($options, 'timestamps', true))
	{
		$this->updateTimestamps();
	}
}

$product = Product::find($id);
$product->updated_at = '2015-01-01 00:00:00';
$product->save(['timestamps'=>false]);

8. Multilanguage Support

// TODO

9. Retrieve Random Rows

$questions = Question::orderByRaw('RAND()')->take(10)->get();

10. UUID Model Primary Key

use Ramsey\Uuid\Uuid;

trait UUIDModel
{
	public $incrementing = false;

	protected static function boot()
	{
		parent::boot();

		static::creating(function ($model)
		{
			$key = $model->getKeyName();

			if (empty($model->{$key})) {
				$model->{$key} = (string) $model->generateNewId();
			}
		});
	}

	public function generateNewUuid()
	{
		return Uuid::uuid4();
	}
}

11. Ordered Relationships

class Category extends Model
{
	public function products()
	{
		return $this->hasMany('App\Product')->orderBy('name');
	}
}

12. Simple Incrementing & Decrementing

$customer = Customer::find($customer_id);
$loyalty_points = $customer->loyalty_points + 50;
$customer->update(['loyalty_points' => $loyalty_points]);

// adds one loyalty point
Customer::find($customer_id)->increment('loyalty_points', 50);

// subtracts one loyalty point
Customer::find($customer_id)->decrement('loyalty_points', 50);

13. Lists with Mutations

// TODO

14. Appending Mutated Properties

// TODO

15. Filter only rows with child rows

class Category extends Model
{
	public function products()
	{
		return $this->hasMany('App\Product');
	}
}

public function getIndex()
{
	$categories = Category::with('products')->has('products')->get();
	return view('categories.index', compact('categories'));
}

16. Return relations on model save

public function store()
{
	$post = new Post;
	$post->fill(Input::all());
	$post->user_id = Auth::user()->user_id;

	$post->user;

	return $post->save();
}

Blade

17. Dynamic With

// eloquent
Post::whereSlug('slug')->get();

// instead of
View::make('posts.index')->with('posts', $posts);

// do this
View::make('posts.index')->withPosts($posts);

18. First/Last Array Element

// hide all but the first item
@foreach ($menu as $item)
	<div @if ($item != reset($menu)) class="hidden" @endif>
		<h2>{{ $item->title }}</h2>
	</div>
@endforeach

// apply CSS to last item only
@foreach ($menu as $item)
	<div @if ($item == end($menu)) class="no_margin" @endif>
		<h2>{{ $item->title }}</h2>
	</div>
@endforeach

Collections

19. Arrays as Collections

$devs = [
	['name' => 'Anouar Abdessalam', 'email' => '[email protected]'],
	['name' => 'Bilal Ararou', 'email' => '[email protected]'],
];

$devs = new \Illuminate\Support\Collection($devs);

20. Collection Filters

Keeps the item only if the closure returns true

$customers = Customer::all();

$us_customers = $customers->filter(function($customer)
{
	return $customer->country == 'United States';
});

21. find()

// returns a single row as a collection
$collection = Person::find([1]);

// returns multiple rows as a collection
$collection = Person::find([1, 2, 3]);

22. where()

$collection = Person::all();

$programmers = $collection->where('type', 'programmer');

23. implode()

$collection = Person::all();

$names = $collection->implode('first_name', ',');

24. where() & list()

// returns a collection of first names
$collection = Person::all()->where('type', 'engineer')->lists('first_name');

// returns all meta records for user 1
$collection = WP_Meta::whereUserId(1)->get();

// returns first name meta values
$first_name = $collection->where('meta_key', 'first_name')->lists('value')[0];

25. Order belongsToMany by Pivot Table value

class Link extends Model
{
	public function users()
	{
		return $this->belongsToMany('Phpleaks\User')->withTimestamps();
	}
}

@if ($link->users->count() > 0)
	<strong>Recently Favorited By</strong>
	@foreach ($link->users()->orderBy('link_user.created_at', 'desc')->take(15)->get() as $user)
		...
	@endforeach
@endif

26. Sorting with closures

$sorted = $collection->sortBy(function($product, $key)
{
	return array_search($product['name'], [1=>'Bookcase', 2=>'Desk', 3=>'Chair']);
});

27. Keying arrays

Defines the 'key' for an array-as-collection (for use with e.g. ->contains)

$library = $books->keyBy('title');

28. Grouped Collections

$collection = Person::all();

$grouped = $collection->groupBy('type');

29. Collection Unions

// the point is to actually combine results from different models
$collection = new Collection;

$all = $collection->merge($programmers)->merge($critics)->merge($engineers);

30. Collection Lookaheads

$collection = collect([1=>11, 5=>13, 12=>14, 21=>15])->getCachingIterator();

foreach ($collection as $key=>$value)
{
	dump ($collection->current() . ':' . $collection->getInnerIterator()->current());
}

Routing

31. Nested Route Groups

Route::group(['prefix'=> => 'account', 'as' => 'account.'], function()
{
	Route::get('login', ['as' => 'login', 'uses' => AccountController::Class.'@getLogin']);
});

<a href="{{ route('account.login') }}">Login</a>

32. Catch-all View Route

// app/Http/routes.php
Route::group(['middleware' => 'auth'], function()
{
	Route::get('{view}', function($view)
	{
		try {
			return view($view);
		} catch (\Exception $e) {
			abort(404);
		}
	})->where('view', '.*');
});

33. Internal Dispatch

// api controller
public funciton show(Car $car)
{
	if (Input::has('fields')) {
		// do something
	}
}

// internal request to api - fields are lost
$request = Request::create('/api/cars/' . $id . '?fields=id,color', 'GET');
$response = json_decode(Route::dispatch($request)->getContent());

// internal request to api - with fields
$originalInput = Request::input();
$request = Request::create('/api/cars' . $id . '?fields=id,color', 'GET');
Request::replace($request->input());
$response = json_decode(Route::dispatch($request)->getContent());
Request::replace($originalInput);

Testing

34. Environmental Variables

// phpunit.xml
<php
	<env name="APP_ENV" value="testing" />
</php>

// .env.test - add to .gitignore
TWILIO_ACCOUNT_SID=blank

// within createApplication() method of TestCase.php
if (file_exists(dirname(__DIR__) . '/.env.test')) {
	Dotenv::load(dirname(__DIR__), '.env.test');
}

35. Run tests automatically

// gulpfile.js
var elixir = require('laravel-elixir');

mix.phpUnit();

$ gulp tdd

Miscellaneous

36. Share Cookies Between Domains

// app/Http/Middleware/EncryptCookies.php
protected $except = [
	'shared_cookie',
];

Cookie::queue('shared_cookie', 'my_shared_value', 10080, null, '.example.com');

37. Easy Model & Migration Stubs

$ artisan make:model Books -m

38. Add Spark to an Existing Project

Notes: Do not run spark:install, backup /resources/views/home.blade.php before running

$ composer require genealabs/laravel-sparkinstaller --dev

$ php artisan spark:upgrade

$ php artisan vendor:publish --tag=spark-full
// config/app.php
Laravel\Spark\Providers\SparkServiceProvider::class,
GeneaLabs\LaravelSparkInstaller\Providers\LaravelSparkInstallerServiceProvider::class,

39. Customize the Default Error Page

<?php namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\Debug\ExceptionHandler as SymfonyDisplayer;

class Handler extends ExceptionHandler
{
	protected function convertExceptionToResponse(Exception $e)
	{
		$debug = config('app.debug', false);
		
		return $debug
			? (new SymfonyDisplayer($debug))->createResponse($e)
			: response()->view('errors.default', ['exception' => $e], 500);
	}
}

40. Conditional Service Providers

// app/Providers/AppServiceProvider.php
public function register()
{
	$this->app->bind(
		\Illuminate\Contracts\Auth\Registrar::class,
		\App\Services\Registrar::class
	);

	if ($this->app->environment('production')) {
		$this->app->register(\App\Providers\ProductionErrorHandlerServiceProvider::class);
	}
	else {
		$this->app->register(\App\Providers\VerboseErrorHandlerServiceProvider::class);
	}
}

41. Change a Column Name in Migration

$ composer require doctrine/dbal

public function up()
{
	Schema::table('users', function ($table)
	{
		$table->string('name', 50)->change();
	});
}

42. Checking if a View Exists

if (view()->exists("emails.{$template}")) {
	// ...sending an email to the customer
}

43. Extending the Application

// bootstrap/app.php
// replace this:
$app = new \Illuminate\Foundation\Application( realpath(__DIR__.'/../'));

// with this:
$app = new \Fantabulous\Application( realpath(__DIR__.'/../'));

// and add
<?php namespace Fantabulous;

class Application extends \Illuminate\Foundation\Application
{
	public function storagePath()
	{
		return $this->basePath.'/FantabulousStorage';
	}
}

44. Simple Caching Microservice

class fakeApiCaller
{
	public function getResultsForPath($path)
	{
		return [
			'status' => 200,
			'body' => json_encode([
				'title' => "Results for path [$path]"
			]),
			'headers' => [
				"Content-Type" => "application/json",
			]
		];
	}
}

$app->get('{path?}', function($path)
{
	$result = Cache::remember($path, 60, function() use ($path)
	{
		return (new fakeApiCaller)->getResultsForPath($path);
	});

	return response($result['body'], $result['status'], array_only(
		$result['headers'], ['Content-Type', 'X-Pagination']
	));
})->where('path', '.*');

45. Use Bleeding Edge Version

$ composer create-project laravel/laravel your-project-name dev-develop

// composer.json
{
	"require": {
		"php": ">=5.5.9",
		"laravel/framework": "5.2.*"
	},
	"minimum-stability": "dev"
}

46. Capture Queries

Event::listen('illuminate.query', function($query)
{
	var_dump($query);
});

\DB::listen(function($query, $bindings, $time)
{
	var_dump( $query, $bindings, $time);

});

47. Authorization Without Models

// TODO

48. Efficient File Transfers with Streams

$disk = Storage::disk('s3');
$disk->put($targetFile, file_get_contents($sourceFile));

$disk = Storage::disk('s3');
$disk->put($targetFile, fopen($sourceFile, 'r+'));

$disk = Storage::disk('s3');
$stream = $disk->getDriver()->readStream($sourceFileOnS3);
file_put_contents($targetFile, stream_get_contents($stream), FILE_APPEND);

$stream = Storage::disk('s3')->getDriver()->readStream($sourceFile);
Storage::disk('sftp')->put($targetFile, $stream);

49. Avoid Overflowing Log Files

$schedule->call(function()
{
	Storage::delete($logfile);
})->weekly();

50. Pipeline

$result = (new \Illuminate\Pipeline\Pipeline($container))
	->send($something)
	->through('ClassOne', 'ClassTwo', 'ClassThree')
	->then(function ($something)
	{
		return 'foo';
	});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment