DEV Community

Daniel Leinweber
Daniel Leinweber

Posted on

Laravel development on macOS

In this article I want to give you a guide on how to setup your development environment on macOS and start developing PHP applications with Laravel.

Contents

Setup Valet

Valet is a light-weight Laravel development environment for macOS, that comes with Nginx. It provides proxies to point all requests on a configured domain to point to installed sites on your local machine.

Install components with Homebrew

Go to Homebrew and copy the installation command and run it in your terminal.

# Update homebrew
brew update

# Install PHP
brew install php

# Install composer
brew install composer
Enter fullscreen mode Exit fullscreen mode

Run the following command and see if it says "composer" anywhere:

echo $PATH
Enter fullscreen mode Exit fullscreen mode

If not, you have to add composer to your path. Add the following line to your shell configuration. I use zsh as my shell, so I can add it to ~/.zshrc

export PATH=$PATH:$HOME/.composer/vendor/bin
Enter fullscreen mode Exit fullscreen mode

Refresh your shells configuration:

# Refresh zsh configuration
source ~/.zshrc
Enter fullscreen mode Exit fullscreen mode

Install Valet

# Actually install valet with composer
composer global require laravel/valet
valet install
composer global require laravel/installer
Enter fullscreen mode Exit fullscreen mode

Create a Project

Make sure to navigate to the project folder, where you want to create the Laravel project.

# Create new project
laravel new PROJECT_NAME
Enter fullscreen mode Exit fullscreen mode

Use Valet

Tell Valet to use the current folder as a Laravel project.

valet park
Enter fullscreen mode Exit fullscreen mode

You can now open your project in your IDE of choice and browse to your projects URL (e.g. http://PROJECT_FOLDER.test)

If you want to see all "parked" projects execute the following.

valet parked
Enter fullscreen mode Exit fullscreen mode

Laravel Project Structure

Laravel is organized in the Model-View-Controller structure.

MVC

Models are found under /app/Models. These are the data models that might be generated with the help of the Laravel CLI tools.

Views are found under /resources/views. The views are usually .blade.php templates, but they don't have to.

Controllers are found under /app/Http/Controllers. The controllers are used to handle the business logic and to get the right data with the help of the models, to pass that down to the requested view.

Routes

Laravel can configure routes for "normal" web applications as well as for an API.

"Normal" routes are configured under /routes/web.php and API routes are configured under /routes/api.php.

Route configuration

Routes can be configured with absolute paths or with dynamic parameters (wildcards) as follows.

// Get all
Route::get('/', function() {
    return view('listings', [
        'heading' => 'Latest Listings',
        'listings' => Listing::all()
    ]);
});

// Get by id
Route::get('/listings/{id}', function($id) {
    return view('listing', [
        'listing' => Listing::find($id)
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Query string parameters might be read with the help of the Illuminate\Http\Request class.

use Illuminate\Http\Request;

// Get query string parameters
Route::get('/search', function(Request $request) {
    return view('search', [
        'name' => $request->name,
        'city' => $request->city
    ]);
});
Enter fullscreen mode Exit fullscreen mode

It is also possible to add constraints to the route, to only allow specific values.

// Get by id -> id has to be a number
Route::get('/posts/{id}', function($id) {
    return view('post', [
        'post' => Post::find($id)
    ]);
})->where('id', '[0-9]+');
Enter fullscreen mode Exit fullscreen mode

In order to return a json from an API route you might do the following.

Route::get('/posts', function() {
    return response()->json([
        'posts' => [
            [
                'title' => 'Post One'
            ]
        ]
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Calling a controller action from a route

If you want to call a controller action in a route you first need to create a controller.

php artisan make:controller ListingController
Enter fullscreen mode Exit fullscreen mode

In the controller you can create public functions for all your actions.

// Show all listings
public function index() {
    return view('listings', [
        'listings' => Listing::all()
    ]);
}

// Show single listing
public function show(Listing $listing) {
    return view('listing', [
        'listing' => $listing
    ]);
}
Enter fullscreen mode Exit fullscreen mode

The route definition can than be changed as follows, where we pass in the controller class and the action/function name.

// Get all
Route::get('/', [ListingController::class, 'index']);

// Get by id
Route::get('/listings/{listing}', [ListingController::class, 'show']);
Enter fullscreen mode Exit fullscreen mode

Route action naming conventions

Common Resource Routes in Laravel are as follows.

index - Show all items
show - Show a single item
create - Show a form to create a new item
store - Store a new item
edit - Show a form to edit an existing item
update - Update an existing item
destroy - Delete an existing item

Configuration

The different system configuration files can be found under /config.

Database

In the /config/database.php file you can configure what type of database should be used (e.g. mysql or sqlite, etc.).

To configure the database connection you can edit the .env file in the projects root folder.

Blade Templates

Blade is a simple templating engine that is already included in Laravel. Blade templates are compiled into plain PHP code.

Passing data to views

Blade views (templates) may be returned from routes or controllers using the global view helper.

Route::get('/', function() {
    return view('greeting', ['name' => 'Finn']);
});
Enter fullscreen mode Exit fullscreen mode

Displaying data in views

The name variable can be displayed in the blade template as follows.

Hello, {{ $name }}
Enter fullscreen mode Exit fullscreen mode

Blade directives

Blade directives are escaped by the @ symbol. These directives function identically to their PHP counterparts. A detailed documentation may be found under https://laravel.com/docs/9.x/blade

@if (count($records) === 1)

    <p>I have one record!</p>

@elseif (count($records) > 1)

    <p>I have multiple records!</p>

@else

    <p>I dont have any records!</p>

@endif

<h1>{{ $heading }}</h1>

@if(count($listings) == 0)

    <p>No listings found</p>

@endif


@foreach($listings as $listing)

    <h2>    
        <a href="/listings/{{$listing['id']}}">{{$listing['title']}}</a>    
    </h2>

    <p>{{$listing['description']}}</p>

@endforeach
Enter fullscreen mode Exit fullscreen mode

An alternative to check for the existance of items is the @unless directive.

@unless(count($listings) == 0)
    @foreach($listings as $listing)
        <h2>{{$listing['title']}}</h2>
        <p>
            {{$listing['description']}}
        </p>
    @endforeach
@else
    <p>No listings found</p>
@endunless
Enter fullscreen mode Exit fullscreen mode

Database Handling

Laravel support different database systems like MySQL, SQLite and others.

MySQL

# Start MySQL server
mysql.server start

# Login with root
mysql -u root -p

# Stop MySQL server
mysql.server stop
Enter fullscreen mode Exit fullscreen mode

1. You should create a dedicated MySQL user for your project

CREATE USER 'someuser'@'localhost' IDENTIFIED BY 'somepassword';
Enter fullscreen mode Exit fullscreen mode

2. Create a database

CREATE DATABASE somedatabasename;
Enter fullscreen mode Exit fullscreen mode

3. Grant the newly created user access to the database

GRANT ALL PRIVILEGES ON somedatabasename.* TO 'someuser'@'localhost';
FLUSH PRIVILEGES;
Enter fullscreen mode Exit fullscreen mode

4. Update the .env file in the project root with the database settings

Migrations

The database schema / structure is managed with database migrations. The migrations can be found under /database/migrations.

Create a new migration

To create a new migration to create a table named listings execute the following command.

php artisan make:migration create_listings_table
Enter fullscreen mode Exit fullscreen mode

Add table columns in migration

Open the newly created migration file (something like 2023_02_17_101605_create_listings_table.php) and add the missing columns in the up method.

public function up()
{
    Schema::create('listings', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->string('tags');
        $table->string('company');
        $table->string('location');
        $table->string('email');
        $table->string('website');
        $table->longText('description');
        $table->timestamps();
    });
}
Enter fullscreen mode Exit fullscreen mode

Run migrations

In order to apply the migrations to the database, execute the following command.

php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Seed database

To generate "dummy" data in your database you can update the run method found in the /database/seeders/DatabaseSeeder.php file. Here you can call a factory method.

To actually execute the database seed, execute the following command.

php artisan db:seed
Enter fullscreen mode Exit fullscreen mode

Refresh / Wipe database

To refresh / wipe the database you can execute the following command. This will re-run the migrations and re-create all the tables. Attention: This will delete the table data

php artisan migrate:refresh
Enter fullscreen mode Exit fullscreen mode

If you want to refresh the database, but also want to execute the database seeding you can do the following.

php artisan migrate:refresh --seed
Enter fullscreen mode Exit fullscreen mode

Creating models

Laravel uses Eloquent as a default ORM. To create an Eloquent model you can execute the following command.

php artisan make:model ModelName
Enter fullscreen mode Exit fullscreen mode

Creating factories

Factories are stored under /database/factories and can be created as follows.

php artisan make:factory FactoryName
Enter fullscreen mode Exit fullscreen mode

In the definition function you can create the objects with the help of faker.

public function definition()
{
    return [
        'title' => $this->faker->sentence(),
        'tags' => 'laravel, api, backend',
        'company' => $this->faker->company(),
        'email' => $this->faker->companyEmail(),
        'website' => $this->faker->url(),
        'location' => $this->faker->city(),
        'description' => $this->faker->paragraph(5),
    ];
}
Enter fullscreen mode Exit fullscreen mode

Shared elements

It is possible to extend a view in Laravel. By doing so it is possible to define a general page layout in one file and extend this layout by side specific content.

You may create a _layout.blade.php file under /resources/views/. Add the following to it, where you want to include the side specific content.

@yield('content')
Enter fullscreen mode Exit fullscreen mode

When creating the actual side layout you can extend the general page layout as follows.

@extends('_layout')

@section('content')

<h2>{{$listing['title']}}</h2>
<p>{{$listing['description']}}</p>

@endsection
Enter fullscreen mode Exit fullscreen mode

Partials

Sometimes you want to re-use a UI element on multiple pages. For this you can include a partial into your side.

Create the folder /resources/views/partials and add for example a file called _search.blade.php and add your layout (etc.) to it. Then you can include it in the different pages, where you want it to appear as follows.

@include('partials/_search')
Enter fullscreen mode Exit fullscreen mode

Components

Components are similar to partials with the difference that you are able to provide data (e.g. a Model) to a component.

Create the folder /resources/views/components and add for example a file called listing-card.blade.php and add your layout (etc.) to it. In order to receive data that was passed to the component add the following.

@props(['listing'])

<h3>
    <a href="/listings/{{$listing->id}}">{{$listing->title}}</a>
</h3>
Enter fullscreen mode Exit fullscreen mode

In order to use a component and pass data to it call it as follows.

@foreach($listings as $listing)
    <x-listing-card :listing="$listing"/>
@enddoreach
Enter fullscreen mode Exit fullscreen mode

Enclosing component

If you want to use a component to enclose something else like if you would create a card component with a specific background and border, you can do the following.

Add a new component and insert a slot for the positioning of the content to be enclosed. In order to define default css classes you can use the $attributes->merge function.

<div {{$attributes->merge(['class' => 'bg-gray-50 border border-gray-200 rounded p-6'])}}>

    {{$slot}}

</div>
Enter fullscreen mode Exit fullscreen mode

And use it like a "normal" HTML tag. The provided css class will be added to the default classes that are defined in the component itself.

<x-card class="p-10">
    <p>Something in the card component</p>
</x-card>
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
leslieeeee profile image
Leslie

Have you tried ServBay.dev?
It's a much easier tool for PHP developers, providing a user-friendly experience, especially for beginners. It supports all versions of PHP, MariaDB, PostgreSQL, as well as Redis and Memcached. You can run multiple PHP instances simultaneously and switch between them effortlessly. It also offers easy updates without the need to configure environment variables. This tool has greatly simplified my PHP development and is definitely worth trying!