This is the most elegant way to do this would be to pass a closure into the groupBy() collection method. $posts_by_date = Post::all()->groupBy(function($date) { return Carbon::parse($date->created_at)->format('Y-m'); }); Then you can loop through it in your blade template similar to this: @foreach ($posts_by_date as $date => $posts) <h2>{{ $date }}</h2> @foreach ($posts as $post) <h3>{{ $post->title }}</h3> {{ $post->content }} @endforeach @endforeach shareimprove this answer answered Mar 18 '14 at 17:06 Very elegant ! One problem by default, the sort is asc ! Start to 2013, 2014 etc... How to to sort it in desc ? – kesm0 May 20 at 10:01 I find the solution : News::orderBy('created_at', 'desc')->get()->groupBy(function($date) – kesm0 May 20 at 10:08
Category Archives: Laravel
Generating archive list for a blog in Laravel
Then you can loop through it in your blade template similar to this:
|
||
Sortable index view tables with Laravel 4
In this article I would like to share how to make a sortable index view with Laravel 4.
Let’s assume you have an index view with a table. Like this example for a table that contains posts.
@extends('layouts.scaffold') @section('main') <h1>All Posts</h1> <div class="search"> {{ Form::model(null, array('route' => array('posts.search'))) }} {{ Form::text('query', null, array( 'placeholder' => 'Search query...' )) }} {{ Form::submit('Search') }} {{ Form::close() }} </div> <p>{{ link_to_route('posts.create', 'Add new post') }}</p> @if ($posts->count()) <table class="table table-striped table-bordered"> <thead> <tr> <th>Title</th> <th>Body</th> </tr> </thead> <tbody> @foreach ($posts as $post) <tr> <td>{{{ $post->title }}}</td> <td>{{ $post->body }}</td> <td>{{ link_to_route('posts.edit', 'Edit', array($post->id), array('class' => 'btn btn-info')) }}</td> <td> {{ Form::open(array('method' => 'DELETE', 'route' => array('posts.destroy', $post->id))) }} {{ Form::submit('Delete', array('class' => 'btn btn-danger')) }} {{ Form::close() }} </td> </tr> @endforeach </tbody> </table> @else There are no posts @endif @stop
And your index action looks like this:
public function index() { $posts = $this->post->all(); return View::make('posts.index', compact('posts')); }
Now if we want to make our index view sortable by clicking on the column header, we should modify our controller to look like this
public function index() { $sortby = Input::get('sortby'); $order = Input::get('order'); if ($sortby && $order) { $posts = $this->post->orderBy($sortby, $order)->get(); } else { $posts = $this->post->get(); } return View::make('posts.index', compact('posts', 'sortby', 'order')); }
This will retrieve two GET variables: sortby and order.
The sortby variable will contain which field to sort by. The order variable will dontain the direction (ASC or DESC)
Next, we need to modify our view:
@extends('layouts.scaffold') @section('main')
All Posts
{{ Form::model(null, array('route' => array('posts.search'))) }} {{ Form::text('query', null, array( 'placeholder' => 'Search query...' )) }} {{ Form::submit('Search') }} {{ Form::close() }}{{ link_to_route('posts.create', 'Add new post') }} @if ($posts->count()) Body @foreach ($posts as $post) {{ $post->body }}{{ link_to_route('posts.edit', 'Edit', array($post->id), array('class' => 'btn btn-info')) }} {{ Form::open(array('method' => 'DELETE', 'route' => array('posts.destroy', $post->id))) }} {{ Form::submit('Delete', array('class' => 'btn btn-danger')) }} {{ Form::close() }} @endforeach
@if ($sortby == 'title' && $order == 'asc') {{ link_to_action( 'PostsController@index', 'Title', array( 'sortby' => 'title', 'order' => 'desc' ) ) }} @else {{ link_to_action( 'PostsController@index', 'Title', array( 'sortby' => 'title', 'order' => 'asc' ) ) }} @endif |
---|
{{{ $post->title }}} |
We added an if-statement to check if any sorting has been done to generate a clickable table header link. In this example we made the title sortable. You can add the same code to make the other headers sortable too.
Clicking once on the header will sort the posts by title with direction ASC, clicking again will sort by DESC order. (Ascending and Descending)
laravel multicheck
Controller $roles_list = Role::lists('name', 'id'); View {{ Form::select('roles[]', $roles_list, null, array( 'multiple' => true, 'class' => 'form-control' )); }}
Laravel flash message with modal
Step 1
Lets say we’ve got a web application which has various pages users can access, one of these pages “archive” requires users to be logged in to access it. I won’t go into the details of how to do that authorization here, since it’s package/project dependent. However for this example, we’ll be using a custom filter called require_login
, which we will create.
Lets go ahead and open our routes.php
file in laravel/app/
, and add the following example route for our archive page:
1
|
Route::get( 'archive' , array ( 'before' => 'require_login' , 'uses' => 'HomeController@archive' )); |
A very simple route; if the user goes to access http://mysite.com/archive, then they’ll first be passed to the require_login
filter where any arguments within there will be run. The arguments for this filter will be checking whether they are logged in or not. Lets go ahead and create our filter
Step 2
So open up your filters.php
file in laravel/app/
. We’ll add our own custom filter using the Route
class and it’s filter
methods. So go ahead and add the following into that file (doesn’t really matter where, just keep it tidy for yourself):
1
|
Route::filter( 'require_login' , function (){}); |
Now, every time we access the archive page we’ll be passed through this filter. As promised, this will do our authorization checks. However since I’m not really covering that here, I’ll just use pseudo code. If you want to know more about user authentication & authorization, check out Security in the Laravel Docs, or you could use a 3rd party package like Sentry. So add the following:
1
2
3
4
5
6
|
Route::filter( 'require_login' , function (){ // If: User is not logged in: return Redirect::to( '/' ) ->with( "modal_message_error" , "You must be logged in to view this page." ); // End If }); |
Lets assume you’ve added your code to check whether the user is logged in, and we’re in the argument where the user has tried to access our archive page and they are not logged in. What we can do here is redirect the user back to the homepage (or wherever you want) using the Redirect
class and it’s to
method (again, you can use whatever you want). However with this, we will pass a Flash Data session with our with
method (which is specifically designed to pass flash data).
Our key for this session will be modal_message_error
and the value of the session being: You must be logged in to view this page.
.
Right, so our user has just been redirected to the home page and they have a flash session stored, now lets use it.
Step 3
For simplicity sake, lets assume the root of your site points towards hello.php
view in laravel/app/views/
, as is default in the installation. First we need to rename this file to hello.blade.php
, so we can use the features of Blade. So now when we try to access http://mysite.com/archive, we get passed through our filter, and redirected back to the root since we are not logged in, and the route for our sites root loads the hello view.
I’ll go over this part quickly since I’m assuming you have Twitter Bootstrap already loaded in your project:
- Make sure jQuery is loaded (since Twitter Bootstrap requires it).
- Make sure your Bootstrap files (JavaScript, CSS and the images are loaded within your CSS file) are being loaded after jQuery. Just drop them into
laravel/public/assets/
.
Now lets get started… Within your elements of the hello view (preferably at the end) add in the following:
1
2
3
4
5
6
7
|
@ if ( Session::has( 'modal_message_error' )) <script type= "text/javascript" > $(document).ready( function () { $( '#popupmodal' ).modal(); }); </script> @ endif |
This means every time our hello view loads we’ll check whether a Session called ‘modal_message’ is set. If it isn’t then do nothing, but if it is, execute the following JavaScript/Jquery. Since we have Bootstrap loaded, the modal()
function will be recognized and called, using the #popupmodal
divs elements. Check out here if you have no idea what I’m on about.
So we can also add our #popupmodal
div inside this if argument, as follows:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
@ if ( Session::has( 'modal_message_error' )) <script type= "text/javascript" > $(document).ready( function () { $( '#popupmodal' ).modal(); }); </script> <div id= "popupmodal" class = "modal hide fade" tabindex= "-1" role= "dialog" aria-labelledby= "myModalLabel" aria-hidden= "true" > <div class = "modal-header" > <button type= "button" class = "close" data-dismiss= "modal" aria-hidden= "true" >×</button> <h3>Notification: Please read</h3> </div> <div class = "modal-body" > <p> {{ Session::get( 'modal_message_error' ) }} </p> </div> <div class = "modal-footer" > <button class = "btn" data-dismiss= "modal" aria-hidden= "true" >Close</button> </div> </div> @ endif |
This way the extra HTML isn’t getting loaded if we don’t need it.
You’ll notice that I’m using {{ Session::get('modal_message_error') }}
to get the sessions value, meaning we have our own text in our modal popup.
So if we now try to access http://mysite.com/archive, this view will be loaded with a Flash Data session. The if argument detects that the session is active an d loads the script with the div element. This will cause the Twitter Bootstrap Modal to load and it’s content will be our sessions value! Something like:
However since this is a Flash Data session, when we refresh the page it wont be active and thus no popup! Quite a handy trick to deal with all sorts of messages. Also since the argument is using nothing distinctly, we can generate different popup messages without duplicating the code… for example another redirect could be:
1
2
|
return Redirect::to( 'error-page' ) ->with( "modal_message_error" , "This is another popup, with some different content!" ); |
Step 4 – Use with popovers
Modal messages by nature are quite intrusive and interrupt the users experience so they have to read it. This is good, but if the notification isn’t really that important it can be pretty annoying – for example you wouldn’t want it for every new notification you get on Facebook.
Popovers in Twitter Bootstrap can also be used in exactly the same way as Modals.
Simply rename your session, with some different text and you’re good to go. However since you need to specify which element will have the popover appearing from it, you do have to do something slightly different. For example in one of my projects, I do the following:
1
2
3
4
5
6
7
8
|
... @ if (Session::has( 'user_logged_in' )) <li id= "popOverLogin" rel= "popover" data-placement= "bottom" data-original-title= "Notification!" @ if (Session::has( 'popoverlogin' )) data-content= "{{ Session::get('popoverlogin') }}" @ endif > ... |
So if the user logs in, I set a permanent session which loads the list item above (on every page load), however if the user has just logged in I set a flash session (popoverlogin
) with the value “Thanks for logging in $name!”. Then at the bottom of my main file (just like the modal), I’d have the following:
01
02
03
04
05
06
07
08
09
10
|
@ if (Session::has( 'popoverlogin' )) <script type= "text/javascript" > $(document).ready( function () { $( '#popOverLogin' ).popover( 'show' ); setTimeout( function () { $( '#popOverLogin' ).popover( 'hide' ); }, 6000); }); </script> @ endif |
If the popoverlogin
session is active, load the following script which creates a popup and then hides it after 6 seconds. This looks slick and effective. Here’s an example from a project I’m working on:
Conclusion
There we have it… It’s pretty long winded but I didn’t want to skip parts out that lead up to getting the final result. This stuff really is simple, and with a bit of thought you can use any of Twitter Bootstraps (and other front-end frameworks) components and create awesome effects.
laravel sort tables
VIEW
<table class=”table table-striped table-bordered”>
<thead>
<tr>
<td>ID</td>
<td>name</td>
<td>email</td>
<!–<td>{{ link_to_route(‘reviews.index’, ‘rating’, [‘sort’ => ‘rating’,’direction’=>$direction]) }}</td>–>
<td>{{sortableColumn(‘reviews.index’, ‘rating’, ‘rating’, $direction)}}</td>
<td>{{sortableColumn(‘reviews.index’, ‘section’, ‘section’, $direction)}}</td>
<td>comments</td>
<td></td>
<td>actions</td>
</tr>
</thead>
———————————————————————–
CONTROLLER
public function index() {
$sort = null !==(Input::get(‘sort’))? Input::get(‘sort’) : ‘id’ ;
$direction = null !==(Input::get(‘direction’))? Input::get(‘direction’) : ‘DESC’ ;
$reviews = Review::orderBy($sort, $direction)->paginate(10);
$direction = $direction==’DESC’? ‘ASC’: ‘DESC’ ;
return View::make(‘reviews.index’, compact(‘reviews’,’direction’));
}
Laravel export to excel specific fields
FIRST INSTALL
https://github.com/Maatwebsite/Laravel-Excel
Controller
public function getCsv() {
Excel::create(‘Filename’, function($excel) {
$excel->sheet(‘Sheetname’, function($sheet) {
$data = Post::get(array(‘title’,’content’));
$sheet->fromModel($data);
});
//FOR EXCEL 2007 or export(‘xls’) for latest versions
})->export(‘xlsx’);
ROUTE
Route::get(‘csv’, array(‘as’ => ‘csv’, ‘uses’ => ‘PostController@getCsv’));
VIEW
{{HTML::link(‘csv’,’EXPORT TO CSV’)}}
Laravel image upload
MORE INFOS:: http://clivern.com/how-to-create-file-upload-with-laravel/
MODEL
<?php
class Myform extends \Eloquent {
// Add your validation rules here
public static $rules = [
// ‘title’ => ‘required’
];
public $timestamps = false;
// Don’t forget to fill this array
protected $fillable = [];
}
——————————————-
Controller
<?php
class MyformController extends \BaseController {
/**
* Display a listing of offers
*
* @return Response
*/
public function index() {
//$offers = Offer::all();
return View::make(‘myform’);
}
public function FormSubmit() {
$data = Input::all();
//Form::create(Input::all()); // which does work, miraculously
// var_dump($data);
$file = Input::file(‘file1’);
$destinationPath = ‘/storage/’;
$filename = $file->getClientOriginalName();
$uploadSuccess = $file->move($destinationPath, $filename);
$form = new Myform;
$form->name = Input::get(‘name’);
$form->email = Input::get(’email’);
$form->image = $destinationPath . $filename;
// return Input::file(‘file’)->move(__DIR__.’/storage/’,Input::file(‘file’)->getClientOriginalName());
$form->save();
}
}
——————————————–
VIEW
@extends(‘master’)
@section(‘content’)
<h2>This is the FORM</h2>
{{ Form::open(array(‘url’=>’form-submit’,’files’=>true)) }}
{{ Form:: label (‘name’, ‘Name’ )}}
{{ Form:: text (‘name’, ” )}}
{{ Form:: label (’email’, ‘E-mail Address*’) }}
{{ Form:: email (’email’, ”, array(‘placeholder’ => ‘me@example.com’)) }}
{{ Form::label(‘file’,’File’,array(‘id’=>”,’class’=>”)) }}
{{ Form::file(‘file1’,”,array(‘id’=>”,’class’=>”)) }}
<br/>
<!– submit buttons –>
{{ Form::submit(‘Save’) }}
<!– reset buttons –>
{{ Form::reset(‘Reset’) }}
{{ Form::close() }}
@stop
——————————————–
MYSQL TABLE
CREATE TABLE IF NOT EXISTS `myforms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`image` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;
—
— GRGR `myforms`
—
INSERT INTO `myforms` (`id`, `name`, `email`, `image`) VALUES
(1, ‘fsdgsdfg’, ‘info@ariser2.com’, ‘C:\\wamp\\www\\lara_users\\app\\controllers/storage\\ticket.jpg’);
Laravel export table to csv with columns names
Controller function
public function getCsv() {
$table = Post::all();
$filename = “posts.csv”;
$handle = fopen($filename, ‘w+’);
// titloi stilwn
fputcsv($handle, array(‘id’, ‘title’, ‘content’));
//pedia
foreach($table as $row) {
fputcsv($handle, array($row[‘id’], $row[‘title’], $row[‘content’]));
}
fclose($handle);
$headers = array(
‘Content-Encoding: UTF-8’
‘Content-Type’ => ‘text/csv’,
);
return Response::download($filename, ‘posts.csv’, $headers);
}
ROUTE
Route::get(‘csv’, array(‘as’ => ‘csv’, ‘uses’ => ‘PostController@getCsv’));
VIEW
{{HTML::link(‘csv’,’EXPORT TO CSV’)}}
Populate dropdown list from database with Laravel
First, create a model named “Country.php” (you can use artisan, excellent Laravel 4 generators or create it manually. Keep in mind that the model name is singular (Country) and the database table is plural (Countries).
In your controller add:
1
|
$country_options = Country::lists( 'short_name' , 'id' ); |
Simple isn’t it? This will return an array of values like “[1] => Afghanistan [2] => Aland Islands”… (We are assuming that database field name containing country names is “short_name”).
Note: Personally I like Eloquent but in case you do not want to use Eloquent or/and do not want to have an empty Country.php model lying there just so you can populate drop-down then you can use Laravel’s Fluent Database Query Builder:
1
|
$country_options = DB::table( 'countries' )->orderBy( 'short_name' , 'asc' )->lists( 'short_name' , 'id' ); |
Ok, now let’s send this to view with ->with
:
1
|
return View::make( 'admin/customers/create' )->with( 'country_options' , $country_options ); |
In above case I am sending $country_options
to admin view that is used to create customers.
In the view you display it like this:
1
|
{{ Form::select( 'country' , $country_options , Input::old( 'country' )) }} |
That is all it takes to have a functioning drop-down select box. As you can see we are using Laravel Blade template engine and Form class. With Input::old('country'))
we re-populate it with old values (for example after the form is submitted and there are some errors)
How to combine more fields with concat
In another case (for “customers”) I needed to combine two table fields into one and then populate the drop down with it: customers “first_name” + “last_name” should be “first_name last_name”. You can do this by combining Fluent Query Builder with Eloquent:
1
|
$customer_options = Customer::select(DB::raw( 'concat (first_name," ",last_name) as full_name,id' ))->lists( 'full_name' , 'id' ); |
As you can see we are mixing Eloquent and DB:raw method.
Note: If you only want to use Laravel’s Database Query Builder then you can do this:
1
|
$customer_options = DB::table( 'customers' )->select(DB::raw( 'concat (first_name," ",last_name) as full_name,id' ))->lists( 'full_name' , 'id' ); |
How to add default option to dropdown list
Sometimes we want to have some default value that gives us some instructions what to do (“Please select a country,…”) with the dropdown or maybe even some default “non-value” (in case user doesn’t want to select anything). The easiest way to do this is to add array('' => 'Select One') +
so our code looks like this (few examples with the code in this post):
1
2
3
4
|
$country_options = array ( '' => 'Please Select Your Country' ) + Country::lists( 'short_name' , 'id' ); //or $customer_options = array ( '' => 'Select Customer' ) + Customer::select(DB::raw( 'concat (first_name," ",last_name) as full_name,id' ))->lists( 'full_name' , 'id' ); //and so on.. |
Keep in mind that you will have to add some validation (jQuery, Laravel’s own validation etc) in case user leaves the default option (in example above we leave the value as empty but you can set it to anything you want).