Laravel routes – Generating a CSV

We’re currently building out an API at Basanty, and I was looking for a way to generate a simple Excel/CSV file.  Using the `artisan routes` command, you can print out a nice table in the console, or even save it by appending `> routes.txt`. The problem is the Symfony table formatter doesn’t translate well to a document.

So I created a simple route that loops through the routes, and saves them to a csv file.  This could quite easily be abstracted to a custom artisan command. Also, after generating the file, you should probably remove it immediately.

/**
 * Generate a CSV of all the routes
 */
Route::get('r', function()
{
    header('Content-Type: application/excel');
    header('Content-Disposition: attachment; filename="routes.csv"');

    $routes = Route::getRoutes();
    $fp = fopen('php://output', 'w');
    fputcsv($fp, ['METHOD', 'URI', 'NAME', 'ACTION']);
    foreach ($routes as $route) {
        fputcsv($fp, [head($route->methods()) , $route->uri(), $route->getName(), $route->getActionName()]);
    }
    fclose($fp);
});

How I use Bower and Grunt with my Laravel projects

I just ran across an excellent article on how to use Grunt with Laravel, and I thought I’d share my process. First things first… install node, npm, bower, grunt, and all that. Google it if this is new to you.

With Laravel installed, I actually use the Laravel-Assetic package for all my concatenation and minimization. That way, cacheing is taken care of automatically. Here’s my composer,json file with all the needed filters

"require": {
		"laravel/framework": "4.0.*",
		"slushie/laravel-assetic": "dev-master",
		"leafo/lessphp": "dev-master",
		"lmammino/jsmin4assetic": "1.0.*",
		"natxet/CssMin": "dev-master"
},

Next, I use Bower for all my asset dependencies. To specify where the files are saved, I needed to add a .bowerrc file in my app’s root, and added this

{
	"directory": "assets/bower"
}

I add the files to use in my bower.json file

{
  "name": "Matula",
  "version": "0.0.0",
  "homepage": "https://terrymatula.com",
  "authors": [
    "Matula <terrymatula@gmail.com>"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "underscore": "~1.4.4",
    "Eventable": "~1.0.1",
    "jquery": "~2.0.3",
    "bootstrap": "jasny/bootstrap#~3.0.1-p7",
    "sir-trevor-js": "~0.3.0",
    "jquery-ui": "~1.10.3",
    "angular": "~1.2.2"
  },
  "resolutions": {
    "jquery": "~2.0.3"
  }
}

In the command line, run `bower install` and all those files are added to the ‘assets/bower’ directory. Then (after following the Laravel-Assetic install instructions) we need to add the files to use in the Laravel-Assetic config file. Here’s an example of my config:

<?php
/**
 * Configure laravel-assetic options in this file.
 *
 * @package slushie/laravel-assetic
 */

return array(
  'groups' => array(
    // Javascripts
    'script' => array(
      'filters' => array(
        'js_min'
      ),
      'assets' => array(
        'underscore',
        'eventable',
        'jquery',
        'jqueryui',
        'redactorjs',
        'bootstrapjs',
        'sirtrevorjs',
        'sirtrevorcustomjs',
        'customjs'
      ),
      'output' => 'js/matula.js'
    ),

    // CSS
    'style' => array(
      'filters' => array(
        'css_min'
      ),
      'assets' => array(
        'bootstrapcss',
        'sirtrevoricons',
        'sirtrevorcss',
        'redactorcss',
        'customcss'
      ),
      'output' => 'css/matula.css'
    ),

    // LESS files
    'less' => array(
      // Convert LESS to css
      'filters' => array(
        'less',
        'css_min'
      ),
      'assets' => array(
        public_path('less/style.less'),
      ),
      'output' => 'css/less.css'
    ),
  ),

  'filters' => array(
    // Filters
    'js_min'  => 'Assetic\Filter\JsMinFilter',
    'css_min' => 'Assetic\Filter\CssMinFilter',
    'less'    => 'Assetic\Filter\LessphpFilter'
  ),

  // List of Assets to Use
  'assets' => array(
    // Add name to assets
    'jquery'            => public_path('bower/jquery/jquery.js'),
    'angular'           => public_path('bower/angular/angular.js'),
    'bootstrapjs'       => public_path('bower/bootstrap/dist/js/bootstrap.js'),
    'eventable'         => public_path('bower/Eventable/eventable.js'),
    'jqueryui'          => public_path('bower/jquery-ui/ui/jquery-ui.js'),
    'jqueryfileapi'     => public_path('bower/jquery.fileapi/jquery.fileapi.js'),
    'sirtrevorjs'       => public_path('bower/sir-trevor-js/sir-trevor.js'),
    'underscore'        => public_path('bower/underscore/underscore.js'),
    'sirtrevorcustomjs' => public_path('js/custom/sir-trevor-custom-blocks.js'),
    'redactorjs'        => public_path('js/custom/redactor.js'),
    'customjs'          => public_path('js/custom/bs.js'),

    'bootstrapcss'      => public_path('bower/bootstrap/dist/css/bootstrap.css'),
    'sirtrevoricons'    => public_path('bower/sir-trevor-js/sir-trevor-icons.css'),
    'sirtrevorcss'      => public_path('bower/sir-trevor-js/sir-trevor.css'),
    'redactorcss'       => public_path('css/custom/redactor.css'),
    'customcss'         => public_path('css/custom/custom.css'),
    'customless'        => public_path('less/*')
  )
);

Some explanation: Starting at the bottom, we have our ‘assets’ array, where we assign a name to each asset and point it to the file we want to use. Then, we have our ‘filters’ array where we give a name to each filter we’re using. The composer file loaded in the filters we’re using. Before that, we create our ‘groups’ array. Each group is basically the filters we want to use, the files we want to filter, and then the output file to create. The order of the files is important, since this will affect any dependent files (eg, jquery needs to be before jquery-ui).

Now, we can run `php artisan asset:warm’ and all our files will be created. The one issue I had during development was that I was doing lots of quick updates to the css/js, and it would take time for the asset cache to clear. So I had to ‘warm’ them often. This was a time waste, so I’m using grunt to take care of that for me, ad live-reload it as well.

The only 2 grunt packages we need are ‘grunt-contrib-watch’ and ‘grunt-exec’. This is how my Gruntfile.js file looks:

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    exec: {
      warmscript: {
        cmd: 'php artisan asset:warm script'
      },
      warmstyle: {
        cmd: 'php artisan asset:warm style'
      },
      warmless: {
        cmd: 'php artisan asset:warm less'
      }
    },
    watch: {
      options: {
        livereload: true
      },
      less: {
        files: ['assets/less/*.less'],
        tasks: ['exec:warmless']
      },
      css: {
        files: ['assets/css/custom/*.css'],
        tasks: ['exec:warmstyle']
      },
      js: {
        files: ['assets/js/custom/*.js'],
        tasks: ['exec:warmscript']
      },
      html: {
        files: ['app/views/*.php', 'app/views/**/*.php']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-exec');

  grunt.registerTask('default', ['exec', 'watch']);

};

I open a dedicated command line tab, run `grunt` and it will warm everything on start. Then, anytime I make a change to one of the files, it’s automatically warmed and the page is reloaded. The ‘html’ part will reload it when my views are changed.

One word of warning… the way I have it set up, it loads every js/css into every view. While it’s handy to only have 2 (or 3 in my case) minimized files that need to be loaded, we’ll only need Redactor on the pages with forms.  It might be best to create our groups dynamically, and only use the assets we need for each view.

Laravel Application Development Cookbook

Hey look! I wrote a book about Laravel: http://bit.ly/laravelcookbook

Some of the fun and exciting things you’ll learn…

  • Setting Up and Installing Laravel
  • Using Forms and Gathering Input
  • Authenticating Your Application
  • Storing Data
  • Using Controllers and Routes for URLs and APIs
  • Displaying Your Views
  • Creating and Using Composer Packages
  • Using Ajax and jQuery
  • Using Security and Sessions Effectively
  • Testing and Debugging Your App
  • Deploying and Integrating Third Party Libraries

 

Some Packagist API “hacks”

In a previous post, I was trying to parse out the most popular Composer packages, and wasn’t able to find a way to get the information through any kind of API. I ended up doing a simple scrape, but then I started searching through the Packagist code ,  and I found some interesting gems.

First, is a list of ALL the packages: https://packagist.org/packages/list.json . It produces a simple list of all 7002 (at the moment) packages in json.

{
    "packageNames": [
        "illuminate/auth",
        "illuminate/cache",
        "illuminate/config",
        "illuminate/console",
        "illuminate/container",
        "illuminate/cookie",
        "illuminate/database",
        "illuminate/encryption",
        "illuminate/events",
        "illuminate/exception",
        "illuminate/filesystem",
        "illuminate/foundation",
        "illuminate/hashing",
        "illuminate/http",
        "illuminate/log",
        "illuminate/mail",
        "illuminate/pagination",
        "illuminate/queue",
        "illuminate/redis",
        "illuminate/routing",
        "illuminate/session",
        "illuminate/socialite",
        "illuminate/support",
        "illuminate/translation",
        "illuminate/validation",
        "illuminate/view",
        "illuminate/workbench",
    ]
}


With that list, you could easily get the specifics about each package at https://packagist.org/p/{package-name}.json. For example: https://packagist.org/p/illuminate/database.json . But what about searching? The Packagist website UI isn’t the most intuitive, but there a couple of queries that make the search fairly powerful. First, is just a regular search like : https://packagist.org/search.json?q=laravel This is fine. It mirrors the site’s search and it’s nice that it includes the ‘downloads’ and ‘favers’

{
    "results": [
        {
            "name": "laravel/framework",
            "description": "The Laravel Framework.",
            "url": "https://packagist.org/packages/laravel/framework",
            "downloads": 6493,
            "favers": 4
        },
        {
            "name": "laravel/curl",
            "description": "Laravel Curl Helper Library inspired by Phil",
            "url": "https://packagist.org/packages/laravel/curl",
            "downloads": 87,
            "favers": 0
        },
    ],
    "total": 77,
    "next": "https://packagist.org/search.json?q=laravel&page=2"
}

But we can get even fancier and search the tags as well: https://packagist.org/search.json?tags=laravel

{
    "results": [
        {
            "name": "laravel/framework",
            "description": "The Laravel Framework.",
            "url": "https://packagist.org/packages/laravel/framework",
            "downloads": 6493,
            "favers": 4
        },
        {
            "name": "composer/installers",
            "description": "A multi-framework Composer library installer",
            "url": "https://packagist.org/packages/composer/installers",
            "downloads": 5562,
            "favers": 2
        },
        {
            "name": "cartalyst/sentry",
            "description": "PHP 5.3+ fully-featured authentication & authorization system",
            "url": "https://packagist.org/packages/cartalyst/sentry",
            "downloads": 731,
            "favers": 2
        },
        {
            "name": "illuminate/database",
            "description": "An elegant database abstraction library.",
            "url": "https://packagist.org/packages/illuminate/database",
            "downloads": 10787,
            "favers": 1
        }
    ],
    "total": 60,
    "next": "https://packagist.org/search.json?page=2&tags%5B0%5D=laravel"
}


Let’s say we only want packages that are tagged with “laravel” AND “database”. That’s possible, too: https://packagist.org/search.json?tags[]=laravel&tags[]=database

{
    "results": [
        {
            "name": "illuminate/database",
            "description": "An elegant database abstraction library.",
            "url": "https://packagist.org/packages/illuminate/database",
            "downloads": 10787,
            "favers": 1
        },
        {
            "name": "laravelbook/ardent",
            "description": "Self-validating smart models for Laravel 4's Eloquent O/RM",
            "url": "https://packagist.org/packages/laravelbook/ardent",
            "downloads": 69,
            "favers": 1
        },
        {
            "name": "jtgrimes/laravelodbc",
            "description": "Adds an ODBC driver to Laravel4",
            "url": "https://packagist.org/packages/jtgrimes/laravelodbc",
            "downloads": 5,
            "favers": 0
        },
        {
            "name": "dhorrigan/capsule",
            "description": "A simple wrapper class for the Laravel Database package.  This is only to be used outside of a Laravel application.",
            "url": "https://packagist.org/packages/dhorrigan/capsule",
            "downloads": 79,
            "favers": 0
        },
        {
            "name": "iyoworks/elegant",
            "description": "",
            "url": "https://packagist.org/packages/iyoworks/elegant",
            "downloads": 12,
            "favers": 0
        }
    ],
    "total": 5
}


You can also search for a “type”, like https://packagist.org/search.json?type=symfony-module or even mix the queries like so: https://packagist.org/search.json/?q=laravel&tags[]=orm&tags[]=database

Other interesting ways to view the data can be found at: https://packagist.org/packages.json … so if you wanted to view packages only released in January of 2013, you can use: https://packagist.org/p/packages-2013-01.json

My favorite “hack”, is searching with an empty value like so: https://packagist.org/search.json?page=1&q= … which returns all the records (15 on a page), ordered by popularity.

One of these days, if someone else doesn’t beat me to it, I’ll make a review/upvote/downvote site so that the best packages can be found a bit easier. Also, there are some excellent packages that have almost no documentation… so having comments that explain some use-cases would be nice.

Autoloading Organized Routes in Laravel

This is an excellent tip from Jesse O’Brien about breaking up your Laravel routes file.  I’ve actually done something similar for a while now, and kind of forgot that Laravel doesn’t come preconfigured this way.

First, in the application directory, I create another directory called “routes”.

In that directory, I have a “filters.php” and “events.php” and some other files to hold my GET and POST routes.

Then in the start.php, I drop on this bit of code:

foreach (scandir(path('app') . 'routes') as $filename) {
	$path = path('app') . 'routes/' . $filename;
	if (is_file($path)) {
		require($path);
	}
}

This way, you can add as many routes as you want, and they’ll all load.

I’ve toyed with the idea of scanning for directories in the routes folder, and including those as well… but if you’re at that point, you should probably just use controllers.

Laravel and Redactor

I’ve been working on this book thing, and the bit I wrote about using Laravel with Redactor is quite nice.. if I do say so myself.  Here’s a bit…

First, WYSIWYG text editor javascript libraries are pretty hit and miss. But Redactor is brilliant. It looks good, it’s coded well, and it just works. Using it with Laravel is a PHP dev’s dream.  So to start, we need to make sure we have a copy of Redactor and have Laravel all set up.

In our routes.php file, we create a route to hold our form with the Redactor field

Route::get('redactor', function()
{
    return View::make('redactor');
});

 

Then create a view named redactor.php.  I’m using straight PHP for the form, but Blade would work just as well.

<!DOCTYPE html>
<html>
   <head>     
         <title>Laravel and Redactor</title>
         <meta charset="utf-8">
         <link rel="stylesheet" href="css/redactor.css" />
         <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
         <script src="js/redactor/redactor.min.js"></script>
   </head>
   <body>
         <?php echo Form::open() ?>
         <?php echo Form::label('mytext', 'My Text') ?>
         <br>
         <?php echo Form::textarea('mytext', '', array('id' => 'mytext')) ?>
         <br>
         <?php echo Form::submit('Send it!') ?>
         <?php echo Form::close() ?>
         <script type="text/javascript">
               $(function() {
                     $('#mytext').redactor({
                           imageUpload: 'redactorupload'
                     });
               });
         </script>
   </body>
</html>

So we created a textarea with the name ‘mytext’, and make the id of that field the same as the name.  So to target it, and add Redactor to it, just use

$('#mytext').redactor();

In the imageUpload parameter, we pass the URL path where we post the image. In this case, it’s routing to ‘redactorupload’.  So let’s create that route.

Route::post('redactorupload', function()
{
   $rules = array(
         'file' => 'image|max:10000'
   );

   $validation = Validator::make(Input::all(), $rules);
   $file = Input::file('file');
   if ($validation->fails())
    {
        return FALSE;
    }
    else
    {
         if (Input::upload('file', 'public/images', $file['name']))
         {
            return Response::json(array('filelink' => 'images/' . $file['name']));
         }
         return FALSE;
    }
});

The image will automatically POST here. So we want to make sure it’s actually an image and is less than 10 megabytes… so we run those validations. If everything validates, we move it to its permanent location, and send out a json response.  Redactor expects the json key to be ‘filelink’ and the value to be the path to the image.  If everything worked, when you add the image, it will display in your Redactor textarea.

We can check what the code output looks like by creating a route to accept the Redactor data.

Route::post('redactor', function()
{
    return dd(Input::all());
});

File uploads through redactor are done pretty much the same way, except with the fileUpload parameter… and the json output should also include a ‘filename’ key.

Postmark – Laravel bundle

I did a Laravel bundle for the Postmark API.  It’s really just a simple wrapper for the API, and I needed it for a non-Laravel project I worked on, and noticed there wasn’t a bundle already. Probably the one update that would be most useful is getting attachments working.  Right now, you have to parse the content and mime-type before attaching… and I should probably update it to just accept the file and do all the parsing in the method. Maybe one day.