Windows version of Linux’s $(pwd)

Advertisements

Tonight, I played around with Docker in Windows, and I wanted to use Node to install my packages to my local environment. Then I found a command on Chris Fidao’s Laravel Vessel website which looked like…

docker run --rm -it -v $(pwd):/opt -w /opt shippingdocker/php-composer:latest composer create-project laravel/laravel my-app

I modified it for use with npm to…

docker run --rm -it -v $(pwd):/opt -w /opt michaelbrooks/node:latest npm i vuepress

I ran the command and got the following…

docker: Error response from daemon: create $(pwd): "$(pwd)" includes invalid characters for a local volume name, only 
"[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path. See 'docker run
--help'.

A quick search and I found I could replace $(pwd) with %cd% which looked exactly like this…

docker run --rm -it -v %cd%:/opt -w /opt michaelbrooks/node npm i vuepress

Subscribe to email updates

Laravel Development with Vessel (Docker)

Advertisements

Getting started with Vessel

I have started using Vessel for my local development as it makes starting and developing a project so much easier. It seems more lightweight than Homestead and the start-up time is much quicker than Homestead.

No PHP or Composer? No problem

If you don’t have PHP7 or Composer installed on your machine, you can follow these instructions to help get you started. It will install PHP7 and Composer environments with Docker and allowing you to create a Laravel project and install Vessel as a package.

I also add /docker folder into my .gitignore as vessel will create this upon initialisation. You could also ignore the vessel and docker-compose.yml files as well, but I enjoy keeping it within my projects.

Bash Commands

Vessel is a bash file and allows you to run any artisan, yarn or npm command of your choosing which makes it easier rather than ssh’ing into a homestead box or running the exec command.

Only for development environments

It has fantastic documentation and should allow you to get running within 10 minutes. The only downside to Vessel is that it’s only for development work and not production. So don’t expect Lets Encrypt certificates or deployment strategies with this.

If you enjoyed this article, please follow for more.

Using View Composers in Laravel 5.2

Advertisements

I have started using Laravel’s View Composers which come in handy when you have a navigation bar that constantly needs certain data. For example, you have an e-commerce store and you need to poll how many items a user has in their basket on pretty much every page they move onto. Or, you need a login/register button when a user isn’t logged in and then a profile options button when they are.

You could be really lazy and add the same code/query into every single controller, which yes, that will work, but then that’s not DRY (Don’t Repeat Yourself). To fix this, we can complete a couple of simple steps and have one bit of code which will constantly be in use every time a certain partial is called.

If you currently have a layout/template view which has the navigation menu already written in, then you will need to move this out into a partial. Within your “resources > views” directory, you will need to create a new directory called “partials”. Once done, you will need to create a “nav.blade.php” file and paste in your navigation code. It should look something like this…

<nav class="navbar navbar-default">
  <div class="container-fluid navbar-header">
  <button class="navbar-toggle collapsed" type="button" data-toggle="collapse"
  data-target="#bs-example-navbar-collapse-1" aria-expanded="false" class="sr-only">
    Toggle navigation
    <br />
    <br />
    <br />
    <br />
    </button><br />
    <a class="navbar-brand" href="#">Brand</a><br />
  </div>
  <p><!-- Collect the nav links, forms, and other content for toggling --><br /></p>
  <div id="bs-example-navbar-collapse-1" class="collapse navbar-collapse">
    <ul class="nav navbar-nav">
      <li style="list-style-type: none;">
        <ul class="nav navbar-nav">
          <li class="active">
            <a href="#">Link <span class="sr-only">(current)</span></a>
          </li>
        </ul>
      </li>
    </ul>
    <ul class="nav navbar-nav">
      <li style="list-style-type: none;">
        <ul class="nav navbar-nav">
          <li><a href="#">Link</a></li>
        </ul>
      </li>
    </ul>
    <ul class="nav navbar-nav">
      <li style="list-style-type: none;">
        <ul class="nav navbar-nav">
          <li class="dropdown">dropdown
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">o</ul>
              </li>
            </ul>
            <p> </p>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li><a href="#">Action</a></li>
                </ul>
              </li>
            </ul>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li><a href="#">Another action</a></li>
                </ul>
              </li>
            </ul>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li><a href="#">Something else here</a></li>
                </ul>
              </li>
            </ul>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li class="divider" role="separator"> </li>
                </ul>
              </li>
            </ul>
            <p></p>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li><a href="#">Separated link</a></li>
                </ul>
              </li>
            </ul>
            <p></p>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li class="divider" role="separator"> </li>
                </ul>
              </li>
            </ul>
            <p></p>
            <ul class="dropdown-menu">
              <li style="list-style-type: none;">
                <ul class="dropdown-menu">
                  <li><a href="#">One more separated link</a></li>
                </ul>
              </li>
            </ul>
            <p></p>
            <p></p>
          </li>
        </ul>
      </li>
    </ul>
    <p></p>
    <p></p>
    <form class="navbar-form navbar-left" role="search">
      <div class="form-group">
        <input class="form-control" type="text" placeholder="Search" />
        <br />
      </div>
      <p>
        <button class="btn btn-default" type="submit">Submit</button>
        <br />
      </p>
    </form>
    <p></p>
    <ul class="nav navbar-nav navbar-right">
      <li style="list-style-type: none;">
        <ul class="nav navbar-nav navbar-right">
          <li>
            <button class="btn btn-primary navbar-btn" type="button">
              Basket
              <span class="badge"></span>
            </button>
        </li>
        </ul>
      </li>
    </ul>
    <p></p>
    <p></p>
  </div>
  <p><!-- /.navbar-collapse --><br /></p>
  <p><!-- /.container-fluid --></p>
</nav>

Including it in your Blade template

Next, in your layout or template blade, you can add…

<?php
require('partials.nav');

This will include your navigation file.

Now for setting up the View Composer, firstly we need to set up a ServiceProvider (for the sake of this tutorial I will show an example for counting a basket)…

<?php
...
public function boot() {
    view->composer(
      'partials.nav',
      'App\Http\ViewComposers\BasketComposer'
    );
}

The service provider will run whenever you use the nav partial and in the next attribute, it will use your BasketComposer which should look something like this…

<?php
class BasketComposer
{
  public function __construct()
  {
    $cart = Cart::Contents();
  }

  /**
   * Bind data to the view.
   *
   * @param View $view
   * @return void
   */
  public function compose(View $view)
  {
    $view->with('cart', $this->cart['result']['total_items']);
  }
}

Obviously, depending on your API or personal use, your code may vary here, but you should get an idea of how this is working. Every time you need the nav partial, the view will render with your given items. You can also pass this to many views at once which makes it work really well. I also believe you can pass many different constant data sets into a single view, so you could in theory also add a user constant for login and edit profile data.

For more information, feel free to visit Laravel’s documentation on View Composers and this nice Laracasts video which helped me figure out how to use it correctly.

If you have a unique use case, please let me know and we can discuss as a community just how useful these View Composers are.

Laravel user Registration and Login

Advertisements

Using Laravel packages to help us

This will be a fairly simple tutorial as I’m not re-creating the wheel here. I started by developing a login/registration system by myself until I start talking to people in Laravel’s IRC. There is a package which did everything I needed it to do which was as follows…

  • Register a user with the following credentials; Username, Email, Password and of course Confirm Password.
  • The user then gets sent an email to confirm registration.
  • The user confirms registration and can now use the website by logging in.
  • The link in case the user forgets the password, which then creates a link to confirm so the user can then change his/her password.
  • Remember me functionality.
  • Logging out
  • Completely customisable in terms of layout and functionality.

Some people had spoken about a Laravel package which does all of this called Zicaco/confide. This package is absolutely brilliant and does everything I could ask for whilst still maintaining the simplicity of migrating it into something you have already developed.

We need to start off by installing this package, place “zizaco/confide”: “~4.0@dev” into your Composer’s require key. You then place ZizacoConfideServiceProvider’, inside Laravel’s provider’s array. Finally, add this into Laravel’s aliases array ‘Confide’ => ‘ZizacoConfideFacade’, .

(PLEASE NOTE: I am currently using version 3.2.* of this package and I currently haven’t upgraded. I am sure that the experience will be similar, but if you have any queries then feel free to email me).

Once you have installed your package successfully, you can run these commands to get everything up and running… php artisan confide:controllerphp artisan confide:routescomposer dump-autoload. And as the docs say, you are good to go.

You can test it out by going to localhost/users/create to see what it has made for you. Of course, you can go on and change the layout, the control and anything else which you find you need to change.

If you need any help, then please let me know and I will try to help you out. I will also be trying to upgrade to the latest version and will release a step by step guide on how to do this.

Laravel Dynamic Menu Tutorial (Best for Admin packages)

Advertisements

Learn more Laravel

Creating a dynamic menu

Thanks to this very Laravel topic over at Laravel.io and Josh Benham. I managed to find out how to make my very own dynamic menu. In this tutorial, I will show you exactly how it’s done. Hopefully, you will now be able to make amazing admin packages for Laravel.

For those that just want the package then you can download it the Laravel dynamic navigation package. Otherwise, continue below.

First off, I am doing this in my very own package. My directory structure will look pretty much like anyone else file structure which will be within the src/Package/Admin. Hopefully, you should be able to follow this along just fine. However, if you have any problems or even any suggestions for improvements then feel free to let me know.

Within my Admin folder, I create a new folder called services and create a file called ‘Menu.php’. This is the code you should type within this file…

services/Menu.php

<?php

namespace PackageAdminServices;

use Illuminate\Support\Facades\HTML;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\URL;

class Menu { 
    protected $items;
    protected $current;
    protected $currentKey;
    
    public function __construct() {
        $this->current = Request::url();
    }

    /** Shortcut method for create a menu with a callback.
     * This will allow you to do things like fire an even on creation.
     * @param callable $callback Callback to use after the menu creation 
     * @return object
     */ 
    public static function create($callback) {
        $menu = new Menu(); $callback($menu);
        $menu->sortItems(); return $menu;
    }
    
    /** Add a menu item to the item stack
     * @param string $key Dot separated hierarchy 
     * @param string $name Text for the anchor 
     * @param string $url URL for the anchor 
     * @param integer $sort Sorting index for the items 
     * @param string $icon URL to use for the icon 
     */
    public function add($key, $name, $url, $sort = 0, $icon = null) { 
        $item = array(
            'key' => $key,
            'name' => $name,
            'url' => $url,
            'sort' => $sort,
            'icon' => $icon,
            'children' => array()
            );
        $children = str_replace('.', '.children.', $key);
        array_set($this->items, $children, $item);
        if ($url == $this->current) {
            $this->currentKey = $key; }
    }
    
    /** Recursive function to loop through items and create a menu 
     * @param array $items List of items that need to be rendered 
     * @param boolean $level Which level you are currently rendering 
     * @return string
     */
    public function render($items = null, $level = 1) { 
        $items = $items ?: $this->items;
        $attr = array( 'class' => 1 === $level ? 'menu level-1' : 'level-' . $level );
        $menu = '<ul' . HTML::attributes($attr) . '>'; foreach($items as $item) {
            $classes = array('menu__item');
            $classes[] = $this->getActive($item);
            $has_children = sizeof($item['children']);
            
            if ($has_children) {
                $classes[] = 'parent';
            }
            $menu .= '<li' . HTML::attributes(array('class' => implode(' ', $classes))) . '>';
            $menu .= $this->createAnchor($item);
            $menu .= ($has_children) ? $this->render($item['children'], ++$level) : '';
            $menu .= '</li>'; }
            $menu .= '</ul>';
        return $menu;
    }
    
    /** Method to render an anchor 
     * @param array $item Item that needs to be turned into a link 
     * @return string 
     */
    private function createAnchor($item) {
        $output = '<a class="menu__item" href="' . $item['url'] . '">';
        $output .= $this->createIcon($item);
        $output .= $item['name'];
        $output .= '</a>';
        return $output;
    }
    
    /** Method to render an icon 
     * @param array $item Item that needs to be turned into a icon
     * @return string
     */
    private function createIcon($item) {
        $output = ''; if($item['icon']) {
            $output .= sprintf('<i class="glyphicon glyphicon-%s"></i>', $item['icon']);
        } return $output;
    }
    
    /** Method to sort through the menu items and put them in order 
     * @return void 
     */
    private function sortItems() { 
        usort($this->items, function($a, $b) {
            if($a['sort'] == $b['sort']) {
                return 0;
            }
            return ($a['sort'] < $b['sort'] ? -1 : 1);
        });
    }
    
    /** Method to find the active links 
     * @param array $item Item that needs to be checked if active 
     * @return string 
     */
    private function getActive($item) {
        $url = trim($item['url'], '/');
        if ($this->current === $url) {
            return 'active current';
        }
        
        if(strpos($this->currentKey, $item['key']) === 0) {
            return 'active';
        }
        
        return '';
    }
}

Get all that?

This code will set you up for all the behind-the-scenes stuff. Hopefully, most of it is pretty self-explanatory (like most of Laravel). The code should be well commented to give you a grasp on what is going on.

Next, we will make our navigation which will be within the views folder. I created an inc folder within my views to keep things tidy called ‘navigation.blade.php’. And my code goes a little like this…

<?php use PackageAdminServicesMenu; ?>

{{ Menu::create(function($menu) {
    Event::fire('admin.menu.build', $menu); })
    ->render(); }}

This will display your navigation, but the only trouble is that we haven’t actually built it. Here we have the code to build our dynamic navigation menu. Inside your AdminServiceProvider.php you need to add this line into your public function boot()

include __DIR__ . '/../../events.php';

This will tell your package where to find the events page which will build up your navigation. Your events.php needs to be in the same place as your routes and filters. This should be in the src folder…

<?php
Event::listen('admin.menu.build', function($menu){
    $menu->add('index', 'Index', URL::route('Admin::index.index'), 1, 'dashboard');
    $menu->add('users', 'Users', URL::route('Admin::users.index'), 100, 'users'); });

Here we use the event listen method used in Laravel to build our menu. The first part of our add method gives a key which enables a check to see if it’s the current page or not. The second part adds text to your link, URL::route will be the route name which you use in your routes.php. We then have these numbers which says where they should be displayed on the nav and users or dashboard is a font awesome icon.

Phew, that was a lot to take in…

Hopefully, this is enough to get anyone started on a dynamic nav, if you need to use it on more packages then just add the code to the service provider, add another event .php and then create similar code to that above which will build up your navigation even more.

I would also like to thank Josh Benham for his help and support. Check out the discussion at laravel.io.

If you would like to pull in the package I created then take a look at my next post. Laravel dynamic navigation package.

Feel free to add your own feedback in the comments below

Subscribe to email updates

Composer Private Repository Problems

Advertisements

Cross development can be a pain…

Recently I have been finding out the slight differences between Windows and Linux for use with Laravel and Composer. One difference is Windows isn’t picky about the way you set out Composer’s packages which can be a major problem. Here’s the issue I had and what I had to do to get it going…

{
    "name"
}: 
"laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"repositories": [
    {
        "type": "vcs",
        "url": "git@bitbucket.org:mbrookspulse8/admin.git",
        "url": "git@bitbucket.org:pulse8/haulfryn-admin-sliders.git",
        "url": "git@bitbucket.org:pulse8/haulfryn-admin-parks.git",
        "branches-path": false,
        "tags-path": false
    }
],
"require": {
    "laravel/framework": "4.1.*",
    "cartalyst/sentry": "2.1.*",
    "imagine/Imagine": "0.5.0",
    "edvinaskrucas/notification": "2.*",
    "way/generators": "dev-master",
    "pulse8/admin": "dev-master",
    "pulse8/sliders": "dev-master",
    "pulse8/parks": "dev-master",
    "geedmo/yamm3": "dev-master"
},
"autoload": {
    "classmap":
    [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php"
    ]
},
"scripts": {
    "post-install-cmd"
}:
[ "php artisan clear-compiled", "php artisan optimize" ],
"post-update-cmd": [ "php artisan clear-compiled", "php artisan optimize" ],
"post-create-project-cmd": [ key:generate" ] },
"config": {
    "preferred-install": "dist"
},
"minimum-stability": "stable"
}

As you can see, I placed all of my private VPS URLs into one JSON object. On Windows, everything was fine and dandy, nothing was overwritten and everything could be found easily. However, when I placed it all on the server, this is where I ran into problems. Linux is more strict on standards (which is definitely not a bad thing) and caused a lot of aches and pains for me as I wasn’t coding to these standards. It took me and my team a whole day to suss out what was wrong, but this was our finished code for the private VPS URLs…

"repositories": 
[
    { 
        "type": "vcs",
        "url": "git@bitbucket.org:mbrookspulse8/admin.git",
        "branches-path": false,
        "tags-path": false
    },
    {
        "type": "vcs",
        "url": "git@bitbucket.org:pulse8/haulfryn-admin-sliders.git",
        "branches-path": false,
        "tags-path": false
    },
    {
        "type": "vcs",
        "url": "git@bitbucket.org:pulse8/haulfryn-admin-parks.git",
        "branches-path": false, "tags-path": false
    }
],

They have been separated into their own object and now runs perfectly fine on Windows and Linux. Had similar issues? If so then please feel free to share and let me know how you overcame them.