Browse Tag

laravel

Laravel tip: enqueue script to end of body

UPDATE (7 Jan 2016): Correction to the blade @append. It doesn’t always work if you have more than a few templates appending to the section.

And so I’ve a partial blade template that contains a custom selection form, which will then be used by multiple other (page layout) templates. This allows me to change the design of the custom selection form at any time in a single location rather than going through multiple templates.

The problem is that I’ve written some JavaScript to manipulate the custom selection form on load and on click. Naturally (or lazily), the script depends on jQuery, which will only be loaded at the end of the body.

I don’t want to separate the script from my partial blade template just to insert it into the page layout templates.

Therefore, I need the custom script to be enqueued to the end, after the jQuery has loaded. I thought I could write a class that does something like WordPress’ wp_enqueue_script.

To my horror… er… surprise, Laravel’s Blade template has already catered to this kind of work using:

@section('script')
    @parent
    {{-- something --}}
@endsection

This may sound complicated, but I have 3 hierarchy of blade templates:

  • Master layout template
    • (Page layout) Single column template
      • Partial Form template
    • (Page layout) Two columns template
      • Partial Form template
  1. Master layout template
    • First I create a general master layout that defines 2 main sections: content and script.
    • <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Laravel 101 Template</title>
          							<link href="css/style.min.css" rel="stylesheet">
        </head>
        <body>
          @yield('content')
      
          <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
          @section('script')
          @show
        </body>
      </html>
  2. Page layout templates
    • Then I create various page layout templates that inherit from Master layout template.
    • It uses the partial form template to collect user input.
    • @extends('layouts.master')
      
      @section('content')
      
          @include('partials.selection-form')
      
      @stop
  3. Partial form template
    • In the partial form, I can easily append my script to the end of the Master layout template like this:
    • <div class="custom-form">
          <h3>A title</h3>
          <input value="0">
          <ul>
              <li><a href="1">Selection 1</a></li>
              <li><a href="2">Selection 2</a></li>
          </ul>
      </div>
      
      @section('script')
          @parent
          <script>
              $('.custom-form').each(function(){
                  doSomething();
              });
          </script>
      @endsection

That’s it! So simple. Love Laravel.

 

Other consideration which failed to work for me.

window.onload

I’ve tried using JavaScript’s window.onload to wait for all the resources to finish downloading before executing my script. However, due to the multiple partial templates I use within a page layout, the result varies from time to time. It seems that only the first window.onload runs properly. I cannot risk that some users may see what other users may not. It’s probably not designed to work like that.

Redmin Series Part 1: Building a Blog with RedminPortal

redminportal_logo_v2_smIn a series of tutorial, I’ll be showing you the steps of building a blog, a Podcast membership site, and an online shop for selling products, using the backend CMS RedminPortal.

RedminPortal is a Laravel 5 package as a flexible content management system for developers.

 

Prerequisite: This tutorial requires knowledge of HTML, PHP, Twitter Bootstrap and Laravel framework. It is meant for developers working on front end site. We’ll use Laravel 5.1 as the foundation due to its LTS support.

All the source codes will be uploaded to github project https://github.com/redooor/redminstore which will, by the end of this series, be a full front-end store system with RedminPortal. You can then use it as a base to build your own application.

In this first tutorial, we’ll be building a simple blog system (something like WordPress) as a Laravel package, using RedminPortal as the backend CMS.

You’ll learn how to:

  1. Build a Laravel package from scratch
  2. Create controller in Laravel
  3. Use Laravel’s Blade templating engine
  4. Use Laravel’s Localization
  5. Use RedminPortal to generate pages and posts
  6. Create dynamic routes to pages and posts
  7. Catch and show error messages such as HTTP 404

Installation

Laravel 5.1

You need to install a full Laravel 5.1 application. Follow the steps in this link and make sure you have a working local environment before proceeding. You should at least be able to access the home page of the application.

RedminPortal

Next, follow the steps in this link to install RedminPortal to your Laravel application. Take note that some features may not be available in version 0.3 yet. To use the latest (but unstable) version, change this line in composer.json:

"require": {
 "laravel/framework": "5.1.*",
 "redooor/redminportal": "0.3.*"
},

To

"require": {
 "laravel/framework": "5.1.*",
 "redooor/redminportal": "dev-develop"
},

Once you’ve installed, follow the migration and publishing steps to create the admin account. Make sure you can access the admin page and log in using the default admin account.

Laravel Package Creation

Folder Structure

Assuming you have your Laravel application installed inside a folder named “laravelapp”, let’s create a folder structure like this:

laravelapp
|- app
|- bootstrap
|- config
  /* other laravel folders omitted for brevity */
  /* create the following folder and its subfolders */
|- packages
  |- redooor
    |- redminstore
      |- src
        |- App
          |- Http
            |- Controllers
          |- Models
            |- UI
        |- facades
        |- resources
          |- lang
          |- views

Noticed that I have named the folders redooor/redminstore. We’ll be calling this package “Redminstore”. If you decide to rename it to something else, do take note that you need to change all references of “Redminstore” to your new name.

Also, because we’ll be using PSR-4 autoloading in our package, all folders inside folder “src” must stay the same. Otherwise the package will fail to work. Take note of the letter casing too. In Linux (most hosting providers use Linux) and Mac OS, the letter casing will affect autoloading.

I’ve left out the steps for setting up PHPUnit tests. If you’re interested, you may visit the github project to study how I did it.

From this point onwards, when I mention <package>, I’m referring to the path “laravelapp/packages/redooor/redminstore”.

Service Provider

Create a new file inside “<package>/src” folder, name it “RedminstoreServiceProvider.php” with this content:

<?php namespace Redooor\Redminstore;

use Illuminate\Support\ServiceProvider;

class RedminstoreServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        // Get routes
        include __DIR__.'/App/Http/routes.php';
        
        // Get views
        $this->loadViewsFrom(__DIR__.'/resources/views', 'redminstore');
        
        // Establish Translator Namespace
        $this->loadTranslationsFrom(__DIR__.'/resources/lang', 'redminstore');
        
        // Allow end users to publish and modify views
        $this->publishes([
            __DIR__.'/resources/views' => base_path('resources/views/vendor/redooor/redminstore'),
        ]);
        
        // Allow end users to publish and modify public assets
        $this->publishes([
            __DIR__.'/public' => public_path('vendor/redooor/redminstore'),
        ], 'public');
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        // Load autoload for package development environment only
        $autoloader = __DIR__ . '/../vendor/autoload.php';
        if (file_exists($autoloader)) {
            require_once $autoloader;
        }
        
        $this->app->register('Orchestra\Imagine\ImagineServiceProvider');
        
        $this->app->booting(function() {
            $loader = \Illuminate\Foundation\AliasLoader::getInstance();
            $loader->alias('Redminstore', 'Redooor\Redminstore\Facades\Redminstore');
            $loader->alias('Redminportal', 'Redooor\Redminportal\Facades\Redminportal');
            $loader->alias('Imagine', 'Orchestra\Imagine\Facade');
        });
    }
}

Package Facade

Create a new file inside “<package>/src/facades” folder, name it “Redminstore.php” with this content:

<?php namespace Redooor\Redminstore\Facades;

use Illuminate\Support\Facades\Facade;

class Redminstore extends Facade {

    /**
    * Get the registered name of the component.
    *
    * @return string
    */
    protected static function getFacadeAccessor() { return 'redminstore'; }

}

Routes

Create a new file inside “<package>/src/App/Http” folder, name it “routes.php” with blank content for now.

Base Controller

Create a new file inside “<package>/src/App/Http/Controllers” folder, name it “Controller.php” with this content:

<?php namespace Redooor\Redminstore\App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesCommands;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;

abstract class Controller extends BaseController {

	use DispatchesCommands, ValidatesRequests;

}

Package.json

This file contains the information of our package. It’s used when using with Composer and package repository such as Packagist.org.

Create a new file inside “<package>” folder and name it “package.json” with this content:

{
  "name": "redminstore",
  "version": "0.1.0",
  "description": "RedminStore is a frontend theme for Ecommerce sites using RedminPortal as backend.",
  "keywords": [
    "package",
    "laravel",
    "redooor",
    "redmin",
    "portal",
    "ecommerce",
    "frontend",
    "store"
  ],
  "repository": "https://github.com/redooor/redminstore",
  "homepage": "https://github.com/redooor/redminstore",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Redooor LLP",
  "license": "MIT",
  "engines": {
    "node": ">= 0.10.1"
  },
  "devDependencies": {
    "bower": "^1.7.1",
    "grunt": "^0.4.5",
    "grunt-autoprefixer": "^2.2.0",
    "grunt-banner": "^0.2.3",
    "grunt-contrib-clean": "^0.6.0",
    "grunt-contrib-concat": "^0.5.0",
    "grunt-contrib-connect": "^0.9.0",
    "grunt-contrib-copy": "^0.7.0",
    "grunt-contrib-cssmin": "^0.10.0",
    "grunt-contrib-less": "^0.12.0",
    "grunt-contrib-uglify": "^0.6.0",
    "grunt-contrib-watch": "^0.6.1",
    "grunt-exec": "^0.4.6"
  }
}

You may ignore those lines within devDependencies for now. They are meant for the full package development and not required in this tutorial.

Composer Setup

Create a new file inside “<package>” folder and name it “composer.json” with this content:

{
    "name": "redooor/redminstore",
    "description": "RedminStore is a frontend theme for Ecommerce sites using RedminPortal as backend.",
    "keywords": ["package", "laravel", "redooor", "redmin", "portal", "ecommerce", "frontend", "store"],
    "license": "MIT",
    "authors": [
        {
            "name": "Redooor LLP",
            "email": "support@redooor.com",
            "homepage": "http://www.redooor.com"
        }
    ],
    "require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.1.*",
		"illuminate/html": "~5.0",
        "doctrine/dbal": "~2.4",
        "orchestra/imagine": "3.1.*",
        "phansys/getid3": "2.1.*@dev",
        "redooor/redminportal": "dev-develop"
    },
    "require-dev": {
        "phpunit/phpunit": "~4.0",
		"mockery/mockery": "0.9.*",
        "orchestra/testbench": "3.1.*"
	},
    "autoload": {
        "classmap": [
            "tests/bases",
            "tests/RedminTestCase.php"
        ],
        "psr-4": {
            "Redooor\\Redminstore\\": "src/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable" : true
}

Once you’ve the composer.json ready, you will need to run composer to install all the dependencies.

Open a Terminal and run the commands:

cd laravelapp/packages/redooor/redminstore
composer install --prefer-dist -vvv --profile

–prefer-dist tells the installer to use distribution source if available.

-vvv is verbose mode, telling the installer to print its actions.

–profile tells the installer to save a cache in the system so next time you run it will be faster.

Visit https://getcomposer.org/ to learn more about Composer.

Root’s Composer.json

Now we need to tell the main application about the location of our newly created package.

Go to “laravelapp/composer.json” and add 1 more line to “autoload” -> “psr-4” section, like this (line 8):

"autoload": {
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\\": "app/",
        "Redooor\\Redminportal\\": "packages/redooor/redminportal/src",
        "Redooor\\Redminstore\\": "packages/redooor/redminstore/src"
    }
},

Root’s Config App.php

Next, go to “laravelapp/config/app.php” and add 1 more line under “providers” section, like this (line 18):

'providers' => [

    /*
     * Laravel Framework Service Providers...
     */
    Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
    /* omitted for brevity */

    /*
     * Application Service Providers...
     */
    App\Providers\AppServiceProvider::class,
    App\Providers\AuthServiceProvider::class,
    App\Providers\EventServiceProvider::class,
    App\Providers\RouteServiceProvider::class,

    Redooor\Redminportal\RedminportalServiceProvider::class,
    Redooor\Redminstore\RedminstoreServiceProvider::class,

],

Run Composer Update

Open a Terminal and run the command inside the root laravalapp folder:

composer update --prefer-dist -vvv --profile

Master Template

Now, we’re almost ready to get into business. Let’s begin with the master template for the entire User Interface of our site. This template will contain the header and footer of the HTML layout, so we don’t have to repeat them in the rest of the pages we create. It will also define the top navigation bar for the site here.

Create a file inside “<package>/src/resources/views/layouts” folder and name it “master.blade.php” with this content:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
        <!--[if lt IE 9]>
        <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
        @section('head')
        <title>RedminStore by Redooor</title>
        @show
    </head>
    <body>
        <header id="header">
            <div class="navbar navbar-default">
                <div class="container">
                    <div class="navbar-header">
                        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                        </button>
                        <a href="{{ URL::to('/') }}" class="navbar-brand">{{ trans('redminstore::menus.brandname') }}</a>
                    </div>
                    <div class="navbar-collapse collapse">
                        <?php $menu_pages = Redooor\Redminstore\App\Models\UI\Menu::getPages(); ?>
                        @if (count($menu_pages) > 0)
                        <ul class="nav navbar-nav">
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ trans('redminstore::menus.pages') }} <span class="caret"></span></a>
                                <ul class="dropdown-menu">
                                    @foreach ($menu_pages as $menu_page)
                                    <li><a href="{{ URL::to('page/' . $menu_page->slug) }}">{{ $menu_page->title }}</a></li>
                                    @endforeach
                                </ul>
                            </li>
                        </ul>
                        @endif
                        <ul class="nav navbar-nav navbar-right">
                            <li><a href="{{ url('/admin') }}">{{ trans('redminstore::menus.adminlogin') }}</a></li>
                        </ul>
                    </div><!--/.nav-collapse -->

                </div>
            </div>
        </header>

        <div id="main">
            <div class="container">
                @yield('content')
            </div>
        </div><!--End main-->
        
        <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

        @section('footer')
        @show
    </body>
</html>

If you’re new to Laravel’s Blade template, take special attention to all the code beginning with an @ sign. Read here to study more about Blade template.

The HTML is a bare minimum site to get things working with Bootstrap. You may have a different HTML template altogether. But do take note of the following lines.

Line 10 to 12: I’ve created a section “head” that can be overwritten by any child template that inherits from this master template. You will see this in action soon when we create a child template.

Line 27: I’m calling a static function to grab all the public pages from RedminPortal, and then use the returned list of pages to generate the dropdown menu in lines 28 to 39. We don’t have that static function Menu::getPages() yet. Let’s create it soon under section “Create UI Menu”.

Line 28 to 39: This dropdown menu is generated with an if-else statement and a returned list of public pages from static function Menu::getPages(). If the function returns a null, the dropdown menu will not be created. So you will not see this dropdown menu until you create at least 1 page with “Private” option unchecked in RedminPortal.

Line 24 and 41: The curly brackets {{}} is Laravel’s equivalent of PHP’s echo. So whatever is within the curly brackets will be printed on the page. I’m using the helper function trans() here to print the localization text. Let’s create the localization file soon under section “Localization”. Read more here about Laravel’s Localization.

Line 51: This is where the child template gets its content printed. We will see it in action soon when we create child template.

Line 58 to 59: This is another section where child template can insert its own footer into master template. This is useful if you have specific JavaScript that is used in 1 child template only and doesn’t make sense to put it in master template.

Create UI Menu

As mentioned previously, we need to create a static function to retrieve all public pages to return to the master template.

Create a file inside “<package>/src/App/Models/UI” folder and name it “Menu.php” with this content:

<?php namespace Redooor\Redminstore\App\Models\UI;

use Redooor\Redminportal\App\Models\Page;

class Menu
{
    /**
    /* Get all pages.
    /*
    /* @param bool $private To retrieve private or public pages, default public.
    /* @return array(Page) or null if nothing found
     */
    public static function getPages($private = false)
    {
        $pages = Page::where('private', $private)->get();
        
        return $pages;
    }
}

We’re using eloquent model Redooor\Redminportal\App\Models\Page from the CMS RedminPortal. Only those pages with flag “private” marked as false will be returned. To study more about Eloquent model in Laravel, read here.

Localization

All localization files must be stored in the folder “<package>/src/resources/lang”. The language are denoted by the subfolder with “en” as the default. For example, if you want to localize to Simplified Chinese, simply add a subfolder name “sc”. Learn more about Laravel’s Localization here.

Now, let’s create a file inside “<package>/src/resources/lang/en” folder and name it “menus.php” with this content:

<?php

return array(
    'brandname' => 'RedminStore',
    'adminlogin' => 'Admin Login',
    'pages' => 'Pages'
);

In this tutorial, we’ve only created 3 items for “brandname”, “adminlogin” and “pages”.

To use them in any template, simply call the helper function trans() like this:

{{ trans('redminstore::menus.brandname') }}
{{ trans('redminstore::menus.adminlogin') }}
{{ trans('redminstore::menus.pages') }}

The convention for our tutorial will be:

trans('redminstore::menus.<key>')

Why do we use localization in this simple tutorial? Well, I just wanted to show you how you can use localization. But most importantly, if you decide to use RedminStore as the base to build your product, you can always overwrite the localization file without changing the Master Template. Just go to your root laravelapp folder, and add that edited “menus.php” file to the folder “laravelapp/resources/lang/packages/en/redminstore/” and you’re good to go.

Child Templates

Let’s create our first child templates to test our setup.

404 Template

We’ll start with a simple 404 page to tell users that the page they are trying to view cannot be found. This is useful for returning non-existence page later on.

Create a new file inside “<package>/src/resources/views/general” folder and name it “404.blade.php” with this content:

@extends('redminstore::layouts.master')

@section('content')
    <div class='row'>
        <div class='col-md-12'>
            <div class="jumbotron">
                <h1>Oops! 404, Page Not Found.</h1>
                <p>Unfortunately, we're not able to find that URL.</p>
            </div>
        </div>
    </div>
@stop

This is a much shorter template than our master template because we’re extending all layout from layouts.master template.

Line 1: This template extends the content from views/layouts/master.blade.php.

Line 3 and 12: We can now insert our child template’s content into master within this section “content”.

Home Template

This template will be used as the landing page for our site. So when user goes to the root site (e.g. laravelapp.app), we will show this page to them.

Create a new file inside “<package>/src/resources/views/pages” folder and name it “home.blade.php” with this content:

@extends('redminstore::layouts.master')

@section('content')
    <div class='row'>
        <div class='col-md-8'>
            <div class="panel panel-default">
                <div class="panel-body">
                    <h1>RedminStore <small>by Redooor</small></h1>
                    <p>This is a demo template to help you get started with RedminPortal CMS.</p>
                    <p>Try adding a few pages in RedminPortal and watch the page being generated automatically.</p>
                </div>
            </div>
        </div>
        <div class='col-md-4'>
            <div class="well well-sm shadow-depth-1">
                <img src="{{ URL::to('vendor/redooor/redminstore/img/redminportal_logo.png') }}" title="ReminPortal" class="img-responsive pull-right">
                <h3>Contribution</h3>
                <p>Source code at <a href="https://github.com/redooor/redminstore">Github</a></p>
                <h3>Maintenance</h3>
                <p>Maintained by the core team with the help of our contributors.</p>
                <h3>License</h3>
                <p>RedminPortal is open-sourced software licensed under the <a href="http://opensource.org/licenses/MIT">MIT license</a>.</p>
            </div>
        </div>
    </div>
@stop

Our First Routes

In previous section, we’ve created 2 templates but there’s no way to see these pages yet. Do view these pages, we need to set up some routes.

If you go to your root site now (e.g. laravelapp.app), you will see the default page with a big Laravel text. That default page comes with every new Laravel installation.

Removing Default Routes

Let’s remove all the default routes from new Laravel installation by deleting the content in “laravalapp/app/Http/routes.php” file.

When you’re done deleting the content, go to your root site again (e.g. laravelapp.app) and you should see an error message saying the route does not exist.

Inserting Our Package Routes

If you look at previously created file RedminstoreServiceProvider.php (Line 15), you would notice that we are loading our routes.php file on boot. This ensures that our package’s routes come after the application’s routes. With that in place, we can save as many routes in our package’s routes.php as we want without changing the root laravelapp’s routes.php.

Custom Routes

That said, we can now edit our package’s routes at “<package>/src/App/Http/routes.php” with this content:

<?php

/*
|--------------------------------------------------------------------------
| Package Routes
|--------------------------------------------------------------------------
*/

Route::group(['namespace' => 'Redooor\Redminstore\App\Http\Controllers'], function () {
    Route::get('/', 'PageController@showHome');
    Route::get('page', 'PageController@show404');
    Route::get('page/{slug}', 'PageController@loadPage');
});

Line 10: This line replaces the root path (e.g. laravelapp.app) which we had previously deleted from the root’s routes.php. It’s loading PageController’s function showHome().

Line 11: This line points to a new route with “/page” appended after the site path (e.g. laravelapp.app/page). This page serves as an error page when no slug is given. It’s loading PageController’s function show404().

Line 12: This line points to any route with “/page/<slug>” appended after the site path (e.g. laravelapp.app/page/<slug>). This page shows the content of RedminPortal::Page model that matches the given slug. It’s loading PageController’s function loadPage().

These routes will not work yet. We need the PageController to provide the content of the page to the router.

Next, let’s create the PageController.

PageController

This PageController is responsible of returning the content of the page to the router. I’ve introduced 3 functions in the previous section. They are:

  • showHome()
  • show404()
  • loadPage($slug)

Create a new file in “<package>/src/App/Http/Controllers” folder and name it “PageController.php” with this content:

<?php namespace Redooor\Redminstore\App\Http\Controllers;

use Validator;
use Redooor\Redminportal\App\Models\Page;

class PageController extends Controller
{
    public function showHome()
    {
        return view('redminstore::pages.home');
    }
    
    public function show404()
    {
        return view('redminstore::general.404');
    }
    
    public function loadPage($slug)
    {
        $inputs = array('slug' => $slug);
        $rules = array('slug' => 'required|alpha_dash');
        $validation = Validator::make($inputs, $rules);
        
        if ($validation->passes()) {
            $page = Page::where('slug', $slug)->where('private', false)->first();
            
            if ($page) {
                return view('redminstore::pages.view')
                    ->with('page', $page);
            }
        }
        
        return view('redminstore::general.404');
    }
}

Return View

showHome() and show404() simply return the templates we had created earlier on. showHome() return the view from pages.home while show404() return the view from general.404. In these templates, the content are static and we’re not expect any variable inside.

Notice the naming convention we’re using here.

view('redminstore::pages.home')

The package’s name must be included before the folder.file name convention. Without the package’s name, Laravel will attempt to load the files from the root laravelapp resources/views folder instead.

So in Laravel, this

return view('pages.home');
>>> result folder: laravelapp/resources/views/pages/home.blade.php

is different from this

return view('redminstore::pages.home');
>>> result folder: laravelapp/packages/redooor/redminstore/src/resources/views/pages/home.blade.php

Now, try loading the root site (e.g. laravelapp.app) and ‘/page’ site (e.g. laravelapp.app/page). You should see the respective page. If not, revisit all the steps above to ensure all files and folders are in place.

If you try loading the ‘/page/<slug>’ site (e.g. laravelapp.app/page/test-page’), you should see an error message. This is because we have not created the template for pages.view yet.

Create Dynamic Page View

PageController::loadPage($slug) function searches all non-private (i.e. public) pages that have slug matches the given $slug, and then pass the RedminPortal::Page model to the template before returning the view.

The passing of data into the template is this line:

return view('redminstore::pages.view')->with('page', $page);

And now, create a new file in “<package>/src/resources/views/pages” folder and name it “view.blade.php” with this content:

@extends('redminstore::layouts.master')

@section('head')
<title>Redminstore: {{ $page->title }}</title>
@stop

@section('content')
    {!! $page->content !!}
@stop

As you can see, it is a very simple template that extends from layouts.master.

Line 4: Overwrites the <title> of the page with the Page’s title.

Line 8: Outputs the content of the returned Page result. We want the full content (except the navigation bar) to be whatever the blogger has written.

Catching non-existence page

If no Page is found for the given slug, the loadPage($slug) function will return the 404 page to the router.

You can try it by passing any non-existence slug to the site path (e.g. laravelapp.app/page/no-such-page-exist).

Create Page in RedminPortal

Finally, to see our work in action, login to RedminPortal CMS via “/admin” site (e.g. laravelapp.app/admin) with the default credential (if you’re lost, refer to RedminPortal installation guide).

In the menu, go to “Pages” under “Content Management”. Create a few pages with the “Private” flag unchecked.

Then go to root site (e.g. laravelapp.app) and you should see the “Pages” dropdown menu. Open it to select the pages you have created. It should be (almost) What-You-See-Is-What-You-Get.

End of Part 1

“What? How about Post? I thought you said we will learn how to create posts as well?”

Ah, well, in a way, I lied. :p

However, the steps for generating Post is exactly the same as generating Page. It’s just a matter of duplicating and changing the name.

Give it a try and see if you can create your own PostController, view and route.

I’ve uploaded my code in github. If you really can’t get it, study my code in github or drop me a comment below. I’ll try as much as possible to answer your questions.

RedminPortal Developer Guide: How to use Coupon?

In this tutorial, I’ll show you how to apply coupon to your products and calculate the discounted price.

Note: This tutorial refers to the latest develop branch which features may not be in the master branch yet. These features will eventually be ported to develop-v0.2 branch, which supports PHP 5.4.

Overview of RedminPortal

redminportal_logo_v2_sm

RedminPortal is a content management system for developers. It only offers backend system for end users and leave the front end solely to the developer. Hence, in many cases, it is up to the developers to design their business logic for their front end.

Let’s Begin

In this tutorial, I’ll be showing you one way of using the coupon. However, it is up to your imagination and creativity to come up with many other ways. Treat this as a guiding ground but keeping in mind that this is not the only way.

Product creation

From the portal, create as many products as you see fit.Redminportal products created

Coupon Creation

Next, create coupons that are “restricted to” these products. You can either restrict the coupons to Categories, Products, Module/Membership or Bundles.Redminportal coupons created

How to create a new order?

Let’s assume we want to have a Cart class that creates a new order and add products into it. Here’s the code:

use Auth;
use Redooor\Redminportal\App\Models\Order;

class Cart
{
  public $order;

  function __construct()
  {
    $user = Auth::user();

    $this->order = new Order;
    $this->order->user_id = $user->id;
    $this->order->paid = 0;
    $this->order->transaction_id = date('Ymd') . '_order_' . $user->id;
    $this->order->payment_status = 'Pending';
    $this->order->options = ''; //Optional
    $this->order->save();
  }
}

Now, to create a new cart in your code, simply do:

$cart = new Cart;

How to add products to an order?

Most (if not all) of the models in Redminportal use Eloquent relationships. To add any product into an order, you just need to save the Product object into Order object. I’ll create a new function in Cart class for adding product.

class Cart
{
  public $order;
  
  function __construct()
  {
    /* omitted */
  }

  public function addProduct($product_id)
  {
    $product = Product::find($product_id);
    
    if ($product) {
      $this->order->products()->save($product);
    }
    
    return $product; // return null if no product found
  }
}

Notice in line 15 we’re using relationship insertion to add product into order.

How to get the total price of an order?

There’s a method in Order class for you to get the total sum of all the product prices. It’s located at <redminportal>/src/App/Models/Order.php.

In our example, if you want to get the total sum of all the prices in a cart, do this:

$totalprice = $cart->order->getTotalprice();

NOTE: This total price does not include discounted value from coupon. It is purely the summation of the prices of all products/pricelists/bundles.

How to apply a coupon to an order?

Using the same relationship insertion, you can add any coupon into an order like this:

$coupon = Coupon::find($coupon_id);

if ($coupon) {
  $cart->order->coupons()->save($coupon);
}

 

This insertion doesn’t check if the coupon is applicable to any product within the order. It merely adds the coupon to the order.

To add a coupon and making sure that it checks the “multiple_coupons” flag, you can use this method addCoupon():

$coupon = Coupon::find($coupon_id);

if ($coupon) {
  $cart->order->addCoupon($coupon);
}

All other checks are up to you, the developers.

How to get the total discounts in an order?

You can use the method getDiscounts() to get a list of all the products with applicable coupons. And then calculate the discount from there.

Note: the value of each discount is stored in the record key “value”.

I will add this function to the Cart class.

public function getTotaldiscount()
{
  $all_discounts = $this->order->getDiscounts();

  $totalDiscount = 0;

  foreach ($all_discounts as $discount) {
    $totalDiscount += $discount['value'];
  }

  return $totalDiscount;
}

// Alternative, shorter code with Laravel's collection
public function getTotaldiscount()
{
  return collect($order->getDiscounts())->sum('value');
}

You can then calculate the total payable amount like this:

$totalpayable = $cart->order->getTotalprice() - $cart->getTotaldiscount();
Update 14 Dec 2015:

Using the latest develop branch, you can now retrieve the total discount from an order like this:

$cart->order->getTotaldiscount();
Caution:

Take note that getDiscounts() saves all the discount information in the $order->options[‘discounts’] array. This is to reduce recalculation whenever you call this method.

However, when you add or remove any coupon or product from the order, you need to call setDiscounts() method to recalculate the new value. Like this:

/* after adding some products */
/* and then add/remove some coupons */

$cart->order->setDiscounts();

$new_totalpayable = $cart->order->getTotalprice() - $cart->getTotaldiscount();

 

That’s it. Do leave a comment if there’s any mistake and I’ll update the post.

Laravel migration error Cannot add foreign key contraint

If you’re getting this error message when executing migration on an existing table, you’re probably having the same issue as I was.

[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `pages` add constraint pages_category_id_foreign foreign key (`category_id`) references `categories` (`id`))
[PDOException]                                                          
  SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint

The problem is because my ‘categories’ table was created as MyISAM type, which doesn’t support foreign key.

The solution is surprisingly very simple: Convert the table to InnoDB type.

So before I create the new table ‘pages’ which reference to the existing table ‘categories’ with a foreign key, I inserted a line to convert the table to InnoDB type.

We can do that easily with Laravel’s DB::statement.

Like this:

// Default type MyISAM doesn't support foreign key
// Convert table to InnoDB
if (Schema::hasTable('categories')) {
    DB::statement('ALTER TABLE categories ENGINE = InnoDB');
}

if (! Schema::hasTable('pages')) {
    Schema::create('pages', function(Blueprint $table)
    {
        $table->increments('id');
        $table->timestamps();
        $table->string('title', 255);
        ... omitted ...
        $table->integer('category_id')->nullable()->unsigned();
        $table->foreign('category_id')->references('id')->on('categories');
    });
}

I was stuck at this for almost half a day trying to figure out why the migration keeps giving me error (although the tables were created nevertheless).

Hope this helps.

Getting Laravel to return a View as RSS or XML

I was having problem getting Chrome to recognize a page as RSS or XML feed. Although Firefox has no problem recognizing it, I’m quite sure I’m missing something here.

After some searches, it became clear that the page was returned as a text document. So Chrome simply display the page as HTML. Firefox is smart enough to check the content first before deciding what type of document it is.

In normal PHP circumstances, we would insert header(‘Content-Type’,’text/xml’) before displaying the view. But with Laravel’s blade, that doesn’t work.

The solution was written in Laravel’s documentation, though not obvious.

To return a page as XML, use

return Response::make($content, '200')->header('Content-Type', 'text/xml');

But how to return a view with the header?

Just set the $content to your view. Full code like this:

$content = View::make('home')->with('somevar', $somevar);

return Response::make($content, '200')->header('Content-Type', 'text/xml');

Updated (8 Dec 2015):

I’m still getting an error on some server saying that:

syntax error, unexpected 'version' (T_STRING)

Blade will throw an error on line #1 because of the XML opening tag, so use PHP print instead.

<?php print '<?xml version="1.0" encoding="UTF-8" ?>'; ?>

Laravel: “Allowed memory size exhausted” error during unit tests

I’ve been using in-memory testing for my projects based on Laravel every since I found this great  tutorial: http://net.tutsplus.com/tutorials/php/testing-like-a-boss-in-laravel-models/

It was working very well as my test cases increases, to a point when I’m starting to get this error message:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 16 bytes) in /Applications/AMPPS/www/project/vendor/symfony/console/Sym
fony/Component/Console/Command/Command.php on line 57

I couldn’t find the proper solution, but managed to get it working with a workaround here: http://forums.laravel.io/viewtopic.php?id=11723

We can temporarily increase the memory limit using this function:

// Temporarily increase memory limit to 256MB
ini_set('memory_limit','256M');

In my case, I needed more than 128MB of memory, so I conveniently increased it to 256MB. It depends on your usage and your hardware. Choose accordingly.

Since this is only required during my test (I follow the TDD approach, so testing comes regularly), I had added it in the TestCase class, inside method createApplication().

This is the full code in TestCase.php.

<?php

class TestCase extends Illuminate\Foundation\Testing\TestCase {

public function createApplication()
{
    // Temporarily increase memory limit to 256MB
    ini_set('memory_limit','256M');

    $unitTesting = true;
    $testEnvironment = 'testing';

    return require __DIR__.'/../../bootstrap/start.php';
}    

/**
 * Default preparation for each test
 */
public function setUp()
{
    parent::setUp();
    $this->prepareForTests();
}

/**
 * Migrates the database and set the mailer to 'pretend'.
 * This will cause the tests to run quickly.
 */
private function prepareForTests()
{
    Artisan::call('migrate');
    Mail::pretend(true);
} 

}

Laravel 4: things to note when creating Package

NOTE: This tutorial was written for Laravel version 4.0. I’ve added some notes for version 4.1 but they’re not tested yet. Do let me know if you see any problem.

When I first started using Laravel 4, I had been creating all my models, controllers and views in the root app folder. While things can get too comfortable and convenient here, it may not be a good idea to dump everything at the top. That’s when Package (or Bundle) comes in.

According to Laravel’s documentation:

“Packages are the primary way of adding functionality to Laravel.”

I found 2 great tutorials on creating your own Laravel 4 Package:

  1. http://culttt.com/2013/06/24/creating-a-laravel-4-package/
  2. http://jasonlewis.me/article/laravel-4-develop-packages-using-the-workbench

The following are some of the problems I’ve encountered and it took me quite some time to look for the solutions. Hope this will help someone else too.

1. Define your dependencies

A Package is like a sandbox module where it should contain its own dependencies (or vendors Packages). So you need to add your dependencies to your Package’s composer.json file.

As an example, I needed to include Cartalyst Sentry and Twitter Bootstrap to my Package, this is what I did under “require”:

"require": {
        "php": ">=5.3.0",
        "illuminate/support": "4.0.x",
        "cartalyst/sentry": "2.0.*",
        "twbs/bootstrap": "3.0.*"
},

 NOTE on Sentry:

After writing this blog, I’ve decided to move Sentry out of my package. Firstly, it will be cleaner and allow people using my package to choose their own authentication vendor. Secondly, I was getting so much trouble trying to get it to work properly. So it’s advisable to just put it on the Laravel app root instead.

Remember to run the following command line at your Package’s root folder:

php composer.phar update
php composer.phar dump-autoload

Note: On your first install, run “php composer.phar install”. Although using update will do the same thing too.

For dump-autoload, on the official documentation, they are using artisan instead of composer. I’m still not sure what’s the difference, but both seem to work.

php artisan dump-autoload

2. Extending Controller

When you download the Laravel 4 master, you will get a BaseController.php under the app\controllers folder. It looks something like this:

<?php

class BaseController extends Controller {

    /**
    * Setup the layout used by the controller.
    *
    * @return void
    */
    protected function setupLayout()
    {
        if ( ! is_null($this->layout))
        {
            $this->layout = View::make($this->layout);
        }
    }
}

And then all your custom controllers will extend this BaseController like this:

class CustomController extends BaseController {}

If you copy and paste this BaseController to your Package, it will not work. The Package will try to find “Controller” in your namespace Vendor\Package.

So to make it work, you must first define BaseController under your namespace, and then let Package knows that it needs to find the correct Controller.

In short, use this:

<?php namespace YourVendor\YourPackage;

use \Illuminate\Routing\Controllers\Controller;

class BaseController extends Controller {

     /**
     * Setup the layout used by the controller.
     *
     * @return void
     */
    protected function setupLayout()
    {
        if ( ! is_null($this->layout))
        {
            $this->layout = View::make($this->layout);
        }
    } 
}

Note for Laravel 4.1:

In Laravel 4.1, the Controller path has been moved. See http://laravel.com/docs/upgrade

Use this instead:

<?php namespace YourVendor\YourPackage;

use \Illuminate\Routing\Controller;

class BaseController extends Controller {

     // Your code
}

3. Using Sentry in your Package

Just to be clear, as some readers mistaken “Sentry” as my Package’s name. It’s a third party Package created by Cartalyst: “Sentry is a simple, powerful and easy to use authorisation and authentication package.” I wanted to include this third party Package in my custom Package to add authorisation and authentication capability.

But once Sentry is downloaded and installed to my Package, I still couldn’t get it to recognise the alias “Sentry”. So the following code produces an error:

Sentry::logout();

The FatalErrorException message was:

Class ‘Vendor\Package\Sentry’ not found

That’s right, the Package has mistakenly treated Sentry under my Package’s namespace.

If you remember from Laravel’s basic documentation, while in the app’s root folder, we can define aliases such as “Sentry” in the \app\config\app.php file. But there doesn’t seem to have any way to register that in my Package.

So what I did, as a workaround, is to include the namespace at the top of my file. Like this:

<?php namespace YourVendor\YourPackage;

use Cartalyst\Sentry\Facades\Laravel\Sentry;

class CustomController extends BaseController {
    public function logOut()
    {
        Sentry::logout();
    }
}

Works like charm! But if you know of a shorter and better way, please leave me a message!

Better solution (edited)

Thanks to hardik dangar, there’s actually a shorter way to do this. Simply add a backslash before Sentry so that php doesn’t search Sentry within my namespace.

<?php namespace YourVendor\YourPackage;

class CustomController extends BaseController {
    public function logOut()
    {
        \Sentry::logout();
    }
}

4. Using Illuminate Facades

Just as you thought everything is well and ready to code, you found yourself stuck at this line!

return View::make('vendorpackage::users/view');

And the FatalErrorException message is:

Class ‘Vendor\Package\View’ not found

What the?!

The same goes to Redirect, Input and Validator.

Base on my previous experience with Sentry, I got just the right idea.

Simply add the following to the top of your code:

<?php namespace YourVendor\YourPackage;

use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\View;

class CustomController extends BaseController {

Tada!!

Better solution (edited)

Thanks to hardik dangar, there’s actually a shorter way to do this. Simply add a backslash before View so that php doesn’t search View within my namespace.

return \View::make('vendorpackage::users/view');

5. Using Views in your Package

That right, you didn’t see it wrongly. This is how you call your Package’s view.

For example, we want view “users\view”, add your Package’s name to the front like this:

View::make('vendorpackage::users/view');

Then how about using master layout? Same logic, like this:

@extends('vendorpackage::layouts.master')

Where the directory is:

workbench\yourvendor\yourpackage\src\views\layouts\master.blade.php

6. Extending Eloquet in your own model

Laravel documentation taught us this:

class User extends Eloquent {}

This won’t work in a Package. Instead, you should do this:

<?php namespace YourVendor\YourPackage;

use Illuminate\Database\Eloquent\Model;

class User extends Model {}

7. Using Controller in your Package

This used to work:

{{ Form::open(array('action' => 'UserController@postStore')) }}

But to use your Package’s Controller, you need to add your Vendor\Package namespace to the Controller like this:

{{ Form::open(array('action' => 'YourVendor\YourPackage\UserController@postStore')) }}

8. Loading Package Config file

If you want to create a separate database for your package, you can define your database configuration within your package directory:

workspace\vendor\packagename\src\config\database.php

Then add this to the package service provider boot() method:

public function boot()
{
    $this->package('vendor/package');
    include __DIR__."/routes.php";

    // Add my database configurations to the default set of configurations                        
    $this->app['config']['database.connections'] = array_merge(
        $this->app['config']['database.connections']
       ,Config::get('package::database.connections')
    );
}

Source: http://stackoverflow.com/questions/15304722/eloquent-laravel-4-package-database-configuration-format

9. Loading external package within Providers and Aliases

In normal circumstances, when we add a new package to a Laravel installation, we would edit the config/app.php by adding the package namespace within the “Providers” and “Aliases” arrays.

However, when we need to add another external package that is a requirement within our own custom package, we wouldn’t want our users to edit a long lists of Providers and Aliases. Ideally, they should only include our custom package.

I’ve been searching for awhile and finally found a solution from this forum.

Solution:

In this example, we want to add an external package call “Markdown”.

In the file myLaravelProject/workbench/my-vendor/my-package/src/MyVendor/MyPackage/MyPackageServiceProvider,

put this in the boot() method:

$this->app->register('SomeExternalPackage\Markdown\MarkdownServiceProvider');

and this in the register() method:

$this->app->booting(function()
{
    $loader = \Illuminate\Foundation\AliasLoader::getInstance();
    $loader->alias('MyPackage', 'MyVendor\MyPackage\Facades\MyPackage');
    $loader->alias('Markdown', 'SomeExternalPackage\Markdown\Facades\Markdown');
});

10. Override config files of package

If you want to be able to allow the users who use your package to publish and modify the package’s config files, following this tutorial:

How to override config files of Laravel 4 package

Missing notes for Laravel 4

Tutorial: Missing notes for Laravel 4

Note: This is an on-going blog. I’ll be updating it whenever I have new findings for Laravel 4.

I had been learning CodeIgniter and CakePHP for some time now when I chanced upon this new(er) framework called Laravel (http://laravel.com) via Twitter.

I’m not going to tell you how wonderful it is, but here’re some references:

There’s an official documentation and another one which is almost recommended everywhere I googled.

The thing is, the official documentation isn’t very complete. It covers most of the basics, but when you want to dig deeper, you’ll get lost. The other recommended tutorial site is almost outdated. I couldn’t find some of the things when I’m comparing it to the official documentation.

So I’m taking notes on the things that I’ve found out (either through googling or the official API documentation). Here we go:

1. Form::open_for_files() is outdated

If you’re trying to create a form for uploading files, the old way was to open the form with Form::open_for_files().

It isn’t clear in the official documentation or the API that we should now use the same Form::open() but now with an additional argument ‘file’ => true.

{{ Form::open(array('action' => 'UploadController@postImage','files'=>true)) }}

2. Using Input::file()

You must always set ‘files’ => true in the Form::open() otherwise Input::file() will never work.

3. Getting filename from Input::file()

There were many tutorials saying that the following will return the filename of the upload file. But it didn’t work for me.

$filename_neverwork_forme = Input::file('image.name');

Instead, use this to get the filename of the upload file.

$filename_worked = Input::file('image')->getClientOriginalName();

Of course, using the filename directly without verification is dangerous. But that’s up to you to decide.

4. Redirect with validation error message and inputs

I realize most methods with underscores are outdated.

So this is wrong:

return Redirect::to('form/create')->with_errors($validation)->with_input();

This is the correct method:

return Redirect::to('form/create')->withErrors($validation)->withInput();

5. Getting URL of a location using URL::to()

To get the full URL of any location or route, simply use URL::to().

For example, if you need the URL of the route ‘about’

{{ URL::to('about') }}

Note: Remember to set your route.php correctly. This function depends on that.

6. Checking current location with Request::is()

I needed to track the current location so that I can mark the corresponding navigation button as active. In this case, you can use Request::is().

Example

@if ( Request::is('about') )
    <li class='active'>
@else
    <li>
@endif
        <a href='{{ URL::to("about") }}'>About</a>
    </li>

 7. Get distinct values from a table column

I had a list of string from a table column that can be repeated. So I needed to query the database to give me an array of string which are distinct.

This is how you can do it:

DB::table('tableName')->select('columnName')->distinct()->get()

 8. Using Mail::send()

This is quite frustrating because the official documentation didn’t describe how to use the $data parameter which is required when using Mail::send().

Found this very good tutorial:

http://maxoffsky.com/code-blog/sending-e-mail-with-laravel-4-using-mail/

 9. Deploying your Laravel project to a shared hosting

Reference: http://stackoverflow.com/questions/16683046/how-to-install-laravel-4-to-a-web-host-subfolder-without-publicly-exposing-app

9.1 Look for your root or home directory

If you’re not sure where is your root or home directory, login to your shared hosting’s cpanel (control panel) and look for the Home Directory. It’s usually something like “/home/domainname”.

9.2 Create a new folder to host the protected Laravel files

We need to create a new folder in the root directory so that they’re not accessible to public. Under the root directory (e.g. /home/domainname/ or example.com), create a folder “applications”.

Under “applications”, create a folder with your project name (e.g. project_name) and place all your Laravel files (except the “public” folder) into this folder.

9.3 Public folder

Put all your files inside Laravel’s public folder into /home/domainname/public_html/project_name.

9.4 Final folder structure

The end result of the folder structure will look like this:

- /home/domainname
    - applications
        - project_name
            - app
            - bootstrap
            - vendor
            - artisan
            - composer.json
            - phpunit.xml
            - server.php
    - public_html
        - project_name

9.5 Edit Laravel’s /bootstrap/paths.php

I was very lost how many “../” I need to add in order to get to the correct path. So we won’t use __DIR__ at all. We’re going to define the full path base on the root directory so that there’s no confusion.

So change from this:

return array(
    'app'     => __DIR__.'/../app', 
    'public'  => __DIR__.'/../public',
    'base'    => __DIR__.'/..',
    'storage' => __DIR__.'/../app/storage',
);

To this:

return array(
    'app'     => '/home/domainname/applications/project_name/app', 
    'public'  => '/home/domainname/public_html/project_name',
    'base'    => '/home/domainname/applications/project_name',
    'storage' => '/home/domainname/applications/project_name/app/storage',
);

9.6 Edit Laravel’s /public/index.php

Same as the point above, we’re not going to use __DIR__. Let’s change all the path to full path.

From this:

require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/start.php';

To this:

require '/home/domainname/applications/project_name/bootstrap/autoload.php'; 
$app = require_once '/home/domainname/applications/project_name/bootstrap/start.php';

9.7 Edit .htaccess

If your shared hosting’s default PHP version is < 5.3.7 but they support higher versions, you can edit the .htaccess file inside the “public” folder.

For Mac users, you can access it via the Terminal.

Use this command to go to the folder

cd your/laravel/path/public

Then list hidden files with this command

ls -a

You should see .htaccess there. By default, this file is protected. In order to change it, you need to open it using super user like this:

sudo open -e .htaccess

Note: -e means open with text editor.

Then append this line to the bottom and save it.

AddHandler application/x-httpd-php53 .php

Or if you want version 5.4

AddHandler application/x-httpd-php54 .php

Upload the updated .htaccess to the public_html/project_name folder and you’re done!

10. Returning view with Error message

When you need to return to a page with error messages (especially if you use validation), you can pass the error messages back to a view with this:

return Redirect::to('form')->withErrors($validation)->withInput();

However, if you need to return an error that is not captured in Laravel’s validation, for example, I needed to check if the reCAPTCHA returns a matching input, you can create a new MessageBag and return that error messages instead.

$errors = new IlluminateSupportMessageBag;
$errors->add('customError', "The reCAPTCHA wasn't entered correctly.");
return Redirect::to('form')->withErrors($errors)->withInput();

But what if you have both validation and custom message? This is how I’ll do it: first, check that validation has passed, if not, return with validation error messages. Then, check that, in my case, reCAPTCHA is matching, if not return that error message.

Example:

if( !$validation->passes() )
{
    return Redirect::to('form')->withErrors($validation)->withInput();
}

// CAPTCHA was entered incorrectly
if (!$reCaptcha->is_valid) {
    $errors = new IlluminateSupportMessageBag;
    $errors->add('reCaptcha', "The reCAPTCHA wasn't entered correctly.");
    return Redirect::to('form')->withErrors($errors)->withInput();
}

11.Creating a Package

Reference:

Important commands:

  1. To generate the class map of package:
    composer dump-autoload
  2. To move package’s assets into public/packages:
    php artisan asset:publish --bench="vendor/package"

12. Laravel requires Mcrypt PHP extension

If you’re using Mac like me, the default PHP installed on the Mac doesn’t insclude Mcrypt extension. I’m using MAMP for development and testing, so I followed this method and it worked for me.

Reference: http://stackoverflow.com/questions/16830405/laravel-requires-the-mcrypt-php-extension

Enter “which php” in terminal to see which PHP you are using.

which php

By default, Mac uses PHP from this path:

/usr/bin/php

If it’s not the PHP version from MAMP, you should edit or add .bash_profile under user root document (cd ~).

In .bash_profile, add following line (your MAMP version may be different, so does your PHP version. Check it up on the folder /Applications/MAMP/bin/php/):

export PATH=/Applications/MAMP/bin/php/php5.4.4/bin:$PATH

And restart Terminal to see which PHP you are using now. And it’ll be working by now.

13. Using lists for Form::select()

The shorter way to populate an array to be used in Form::select() is using query builder ‘lists’ to retrieve just the id column and a value column.

For example:

$select_array = Classname::lists('name', 'id');

Read the link below for more tips about this trick.

Laravel 4: Using query builder lists for Form::select