Browse Category

Tutorial

How to setup phpMyAdmin in Homestead

Writing this for my own reference. Hope it helps someone too.

Install using Ubuntu repository:

This will install phpMyAdmin from Ubuntu’s repositories. Assuming that your projects live in /home/vagrant/Code:

  1. On your hosting machine, open a terminal, go to your homestead folder, after “vagrant up”, enter “vagrant ssh” to ssh to your virtual machine.
  2. Then enter “sudo apt-get install phpmyadmin” (Do not select apache2 nor lighttpd when prompted. Just hit tab and enter.)
  3. You will be prompted whether to set up a database, select “OK” and when prompted for password, enter “secret”. (This is the default password for Homestead’s MySQL.)
  4. Now enter “sudo ln -s /usr/share/phpmyadmin/ /home/vagrant/Code/phpmyadmin”
  5. Finally, enter “cd ~/Code && serve phpmyadmin.app /home/vagrant/Code/phpmyadmin”

For Mac/Linux users, follow the following step to add a nice URL for phpMyAdmin.

  1. On your hosting machine, edit the /etc/hosts file with the command “sudo nano /etc/hosts”. I like the nano editor, feel free to use any editor.
  2. Add the following (you can use your virtual machine’s IP address instead of 127.0.0.1):
    • 127.0.0.1 phpmyadmin.app
  3. If you’re using nano editor, press keys Control + o (letter o) to save the changes. Then press keys Control + x to exit the editor.
  4. Now open a browser.
  5. Go to http://phpmyadmin.app
  6. That’s it!

Reference:

http://stackoverflow.com/questions/23788096/how-to-setup-phpmyadmin-on-a-laravel-homestead-box

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.

Setting up Laravel 5 on shared hosting server

UPDATE (7 Jan 2016): Added a final step for pointing domain to subfolder.

UPDATE (4 Apr 2016): I’ve received a number of enquiries with this setup. Please test it on your local environment first. Use homestead to create a domain with the same folder structure. If it’s working on homestead, it’ll most likely work on your shared server.

UPDATE (15 Jun 2016): Added some common problems found from the lovely comments. Scroll to the bottom to see

In this tutorial, I’ll show you some guide to deploy your Laravel 5 application onto a shared hosting server.

By default, the Laravel folder structure assumed that the public folder is within the application itself. This is the high level folder structure:

your_app_name
|--app
|--bootstrap
|--config
|--database
|--public
  |--assets
  |--index.php  <--we need to point here
|--resources
|--storage
|--tests
|--vendor

In an ideal scenario, you can simply point the web domain to the public folder so that the URL loads public\index.php.

However, in a shared hosting server, you are limited to putting your web serving files in a folder probably named public_html or www which is publicly accessible via web domain. You may be tempted to do this (NOT recommended):

shared_hosting_root_NOT_recommended
|--other_folders (not accessible via web domain)
|--public_html
  |--your_app_name
    |--app
    |--bootstrap
    |--config
    |--database
    |--public
      |--assets
      |--index.php  <--we need to point here
    |--resources
    |--storage
    |--tests
    |--vendor

You can then point your web domain to the public folder.

The problem with this is that your application is now publicly accessible and that may expose vulnerability. You cannot be sure if someone somewhere is able to access your config folder and look at all your sensitive information such as database credentials.

Instead, put your application root into a folder outside of public_html, and place only the public folder within public_html.

This is the recommended folder structure:

shared_hosting_root_recommended
|--other_folders (not accessible via web domain)
|--applications  (not accessible via web domain)
  |--your_app_name
    |--app
      |--GoPublic.php <--we'll create this
    |--bootstrap
    |--config
    |--database
    |--public <--copy content to public_html
      |--assets
      |--index.php
    |--resources
    |--storage
    |--tests
    |--vendor
    |--deploy.sh <--we'll create this
|--public_html
  |--your_app_name
    |--assets
    |--index.php <-- we need to point here

In Laravel 4, you can easily tell your application that the public folder is now in another location by simply changing the file bootstrap/path.php. See point 9 of my Laravel 4 tutorial.

However, in Laravel 5, this file no longer exists. I’ll show you how.

1. Create a class to point to new location

Create a new file shared_hosting_root\applications\your_app_root\app\GoPublic.php

<?php namespace App;

class GoPublic extends \Illuminate\Foundation\Application
{
 /**
 * Get the path to the public / web directory.
 *
 * @return string
 */
 public function publicPath()
 {
 return $this->basePath.DIRECTORY_SEPARATOR.'../../public_html/your_app_name';
 }
}

We’re using relative path here so you don’t have to know the absolute path. But it is extremely crucial to follow the same recommended folder structure I’ve mentioned earlier.

Updated:

You may need to run the following command in your root folder to autoload the new class. Otherwise you will get an error saying the class cannot be found.

composer dump-autoload

2. Edit bootstrap\app.php

Now we need to tell our application the location of the new public folder. Open and edit your_app_name\bootstrap\app.php:

<?php

/* -- remove/comment this original code
$app = new Illuminate\Foundation\Application(
 realpath(__DIR__.'/../')
);
-- until here */

/* -- add this new code -- */
$app = new App\GoPublic(
 realpath(__DIR__.'/../')
);

As you can see above, we’re using the new class that we’ve created in step 1.

3. Edit public\index.php

You need to edit these 2 lines.

From line 21:

require __DIR__.'/../bootstrap/autoload.php';

to

require __DIR__.'/../../applications/your_app_name/bootstrap/autoload.php';

And from line 35:

$app = require_once __DIR__.'/../bootstrap/app.php';

to

$app = require_once __DIR__.'/../../applications/your_app_name/bootstrap/app.php';

4. Copy public to public_html

Now, copy the content inside applications\your_app_name\public into public_html\your_app_name.

To simplify the process, I would create a bash file to automatically copy the files to the new location.

Create a new file shared_hosting_root\applications\your_app_name\deploy.sh

#!/bin/bash
echo "Copy public folder to public_html/your_app_name"
rsync -rv ./public/ ../../public_html/your_app_name

Using rsync ensures that if you ever run this deploy.sh several times, only those that are newer will be copied to the new location.

When you’re ready to run it, in the terminal run:

?> cd applications\your_app_name
?> sh deploy.sh

Caution: You have to run deploy.sh within applications\your_app_name, otherwise it will fail.

5. Accessing your app

There are 2 ways of accessing your application from the hosting server. You need to follow either one of the following step depending on your setup.

5a) Using subdomain

The easier way of accessing your application is to set up a subdomain (e.g. your_app_name.example.com) and point it to your application folder (i.e. public_html/your_app_name). This should automagically work without much hassle.

5b) Using primary domain

The other (slightly more complex) way is to point your primary domain (e.g. example.com) to your application folder (i.e. public_html/your_app_name).

By default, the primary domain points to the folder public_html in most of the shared hosting environment.

To do that, you need to create (or edit if it’s already there) a .htaccess file inside the public_html folder.

# Do not change this line. 
RewriteEngine on 

# Change example.com to your domain name
RewriteCond %{HTTP_HOST} ^(www.)?example.com$ 

# Change your_app_name to the subfolder name
RewriteCond %{REQUEST_URI} !^/your_app_name/ 

# Don't change the following two lines. 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 

# Change your_app_name to the subfolder name
# Change example.com to your domain name
RewriteRule ^(.*)$ /your_app_name/$1 
RewriteCond %{HTTP_HOST} ^(www.)?example.com$ 
RewriteRule ^(/)?$ your_app_name/index.php [L]

6. Em…

And that’s it.

I would also recommend using the same folder structure during your development so that you can experience the whole process of deployment before you upload to your hosting server.

Hope this helps!

7. Common Problems

There were a few cases of the following that may cause your Laravel 5 to not work on your live server:

  1. Your PHP version is lower than 5.5.9. Laravel 5 requires PHP 5.5.9 and above.
  2. Your folder structure is different. Make sure your local test environment is exactly the same as your live server. Starting from your server’s root folder.
  3. Re-read the whole tutorial. I find that some of my codes were truncated, so make sure you copy and paste correctly. Try scrolling left and right to see the full code line. Sorry about that.

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.

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

Recently I realised I’ve been doing the wrong way to populate the array for Form::select().

In order to get Form::select() to work, the array you parse in must contain key => value. So in the past, I’ve been doing it this way:

$select_array = array();
foreach (Classname::all() as $model) {
    $select_array[$model->id] = $model->name;
}

It does the work, but there’s a built-in function in Laravel that can do this (probably faster, I think) in just 1 line:

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

It returns an array that will work with Form::select().

This function is mentioned in the Laravel Documentation to retrieve specific column from a model. But it wasn’t clear that it’s also useful to populate an array for Form::select().

Advanced level

What if the value you want to get is in another class that’s related to this class? Well, we can combine join() with select() and then list().

For example:

$select_array = ModelOne::join('modeltwos', 'modeltwos.id', '=', 'modelones.modeltwo_id')
 ->select('modeltwos.name', 'modelones.id')
 ->lists('name', 'id');

I hope this is useful. Do leave a comment if you have a better way of populating the array for Form::select().

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);
} 

}

jQuery using $.on to call newly added elements

More than a year ago, I had written a blog about how to bind events to newly added elements using jQuery.

The scenario can be found here: http://blog.kongnir.com/2012/02/08/jquery-function-not-binding-to-newly-added-dom-elements/

In my previous solution, I had used $.live() in place of $.change(). However, as noted by a commenter in that blog, as of time of writing, $.live() is deprecated.

Instead, we should now use $.on() if you need to capture events of newly added elements.

For example, in normal circumstance, we would do this:

$(".existing-button").click(function() {
    alert("This will work if button already exist on load");
});

However, if you add new elements to the document using AJAX, then the above will not work. That button doesn’t exist.

In both circumstances, this will work:

$(document).on("click",".new-button", function() {
    alert("This will work even if element is newly added");
});

If you notice, the syntax is quite different. The element to call on is the containing element, not the element that the event is called. So let’s say “.new-button” is contained within “#main”, then the following should work too.

$("#main").on("click",".new-button", function() {
    alert("This will work even if element is newly added"); 
});

Reference: http://api.jquery.com/on/

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