9 Hot Tips to Enhance Your Spark Experience

Christopher Pitt
Christopher Pitt
Share

A while ago, I wrote about a product I wanted to build, to allow easy remote backups for Pagekit sites. I’ve been working on it (periodically) since then, and have come across a few interesting bits of advice.

I decided to use Laravel Spark as the foundation for the product, and I thought it would be helpful to share the advice. Whether you’re just starting your Spark app, or are in maintenance mode, I think you’ll find some of these tips useful!

Laravel Spark Website Splash Screen

1. You Don’t Have to Keep All the Base Files

You may be worried about removing too many of the base files from the standard Spark installation. When I first started, I thought it vital not to change the auth controllers (in app/Http/Controllers/Auth), for fear that it’d break the registration and login system.

Turns out, these files aren’t used by Spark. In fact, if you add routes to them, and you try to register/log in, you’ll probably just encounter problems. These default auth controllers share the same auth guard (session driver), so logging in through one will make you authenticated through the other.

If, however, you try to register through the non-Spark controllers, your user and team accounts will be missing vital Spark information. It’s cleaner and simpler to just delete these auxiliary auth controllers.

If you’re unsure, make a full backup. Then you can roll back in case your tests pick up any regressions.

2. Use Simple Repositories

Spark includes a few simple repositories. These are like static config lists (for countries and other mostly-static data), but they can be loaded through the IoC container. They look like this:

namespace Laravel\Spark\Repositories\Geography;

use Laravel\Spark\Contracts\Repositories\↩
    Geography\CountryRepository as Contract;

class CountryRepository implements Contract
{
    /**
     * {@inheritdoc}
     */
    public function all()
    {
        return [
            'AF' => 'Afghanistan',
            'AX' => 'Åland Islands',
            'AL' => 'Albania',
            // ...snip
            'YE' => 'Yemen',
            'ZM' => 'Zambia',
            'ZW' => 'Zimbabwe',
        ];
    }
}

This is from vendor/bin/laravel/spark/src/Repositories/Geography/CountryRepository.php

We can see instances of this being used in some of the registration views:

<select class="form-control" v-model="registerForm.country"
    lazy>
    @foreach (app(Laravel\Spark\Repositories\↩
        Geography\CountryRepository::class)->all()↩
        as $key => $country)
        <option value="{{ $key }}">{{ $country }}</option>
    @endforeach
</select>

This is from resources/views/vendor/spark/auth/register-address.blade.php

I highly recommend you use these repositories for country and state data. I also recommend you use this repository style for your own lists:

namespace App\Repositories;

use DateTimeZone;

class TimezoneRepository
{
    /**
     * @return array
     */
    public function get()
    {
        $identifiers = DateTimeZone::listIdentifiers(DateTimeZone::ALL);

        return array_combine(
            $identifiers,
            array_map(function ($identifier) {
                return str_replace("_", " ", $identifier);
            }, $identifiers)
        );
    }
}

You don’t have to make an interface for each repository. In fact, I think that’s a bit of an overkill. But I think these tiny repositories are much cleaner and easier to use than the alternatives.

In addition, you can alias these in an application service provider:

namespace App\Providers;

use App\Repositories\CountryRepository;
use App\Repositories\TimezoneRepository;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * @inheritdoc
     */
    public function register()
    {
        $this->app->singleton("timezones", function () {
            return new TimezoneRepository();
        });
    }
}

This is from app/Providers/AppServiceProvider.php

This makes them super easy to use in views:

<select class="form-control" v-model="registerForm.timezone"
    lazy>
    @foreach (app("timezones")->get() as $key => $timezone)
        <option value="{{ $key }}">{{ $timezone }}</option>
    @endforeach
</select>

In general, you should try to use existing lists of data. When you absolutely have to maintain your own, I’ve found this strategy works well.

3. Don’t use caret (^) Laravel dependencies

Laravel evolves rapidly. That’s great for keeping developers interested, but it has maintenance drawbacks. Do yourself a favor and replace any ^x.x dependency version numbers with ~x.x.x version numbers.

Spark 1.x is built with Laravel 5.2.x. If you’re not careful (read: using ^5.2), a call to composer update will upgrade Laravel to 5.3.x, which introduces many breaking changes.

Laravel does not claim to follow Semver, so there’s no reason to assume minor version bumps will be safe. That said, Taylor is quite reasonable when it comes to the difficulty involved in upgrading minor versions. If the breaking changes introduced take too long to mitigate, they’ll be held back until the next major version.

Spark 2.x is based on Laravel 5.3.x, so start there if you can. Then you’ll have access to all the shiny new features in 5.3.x from the get-go. It’s much easier to start a new Spark application than it is to upgrade an existing one. Trust me on that…

Once again, you’re better off making a full backup before running composer update. You’re building a product. You’ve paid money to use Spark. Backups are now a thing.

4. The Docs Are Your Friend

There’s a lot of assumed knowledge bundled into Spark. Most of the bundled views use (or at least reference) VueJS components. Spark depends on Cashier and either Stripe or Braintree.

You don’t need to be an expert on these things, but if you need to touch any of them, don’t try and do it without first going through the related documentation. Or all the documentation.

I found sections like “Adding registration fields” particularly useful, because they cover the full range of edits required to make a change.

Take a look at the free Laracasts videos as well. They’re a bit dated now, but still a good source of knowledge.

5. Don’t Feel Pressured to Learn VueJS

I know I just mentioned VueJS, but the truth is that you don’t really need to learn it before trying Spark. Before I spent a lot of time in Spark, I thought that I did. Turns out the docs tell you all you need to know, and the bundled views fill any gaps with examples.

If your goal is to do some swish-bang front-end stuff, it’s not a bad idea to learn VueJS. If all you need (JabbaScript-wise) is to add a field here or there, just follow the examples in code.

There’s nothing stopping you from making all your app-specific code plain ol’ HTML and PHP.

6. Host on Forge

Sincerely (and without any encouragement to mention them), I cannot recommend Forge highly enough. It’s sensible, affordable server management, geared towards Laravel applications.

I’ve hosted other (non-Spark) things there, but it has made my Spark experience richer. I’ve particularly enjoyed the .env, scheduler and queued job daemon management tools. Every subscription-based app needs scheduled jobs. Every moderately complex application benefits from queued jobs.

7. Re-Arrange Middleware

One of the best features (in my personal opinion) of Laravel is route model binding. That’s when you define routes like this:

use App\Http\Controllers\CustomersController;

Route::get("customers/:customer", [
    "uses" => CustomersController::class,
    "as" => "customers.edit",
]);

…and then define that action as:

/**
 * @param Customer $customer
 *
 * @return Response
 */
public function edit(Customer $customer)
{
    return view("customers.edit", [
        "customer" => $customer,
        "groups" => Groups::all(),
    ]);
}

If you run this code (as a controller action), $customer will automatically be pulled from the database. It’s a powerful feature! When I started this Spark 1.x application, I was careful to apply global scopes to all team-specific models:

namespace App\Scopes;

use App\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class TeamScope implements Scope
{
    /**
     * @param Builder $builder
     * @param Model $model
     *
     * @return Builder
     */
    public function apply(Builder $builder, Model $model)
    {
        /** @var User $user */
        $user = auth()->user();

        return $builder->where(
            "team_id", "=", $user->currentTeam()->id
        );
    }
}

This is from app/Scopes/TeamScope.php

I applied this in the models’ boot() methods:

namespace App;

use App\Scopes\TeamScope;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{

    /**
     * @inheritdoc
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new TeamScope());
    }
}

The expected behavior would be that all customers are then filtered according to logged-in users’ current teams. The trouble is that this doesn’t work in 5.2.x, as the session isn’t started when route model bindings happen. To get around this, I had to move the session middleware out of the web group and into the global group:

/**
 * The application's global HTTP middleware stack.
 *
 * These middleware are run during every request to your application.
 *
 * @var array
 */
protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Session\Middleware\StartSession::class
];

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        // \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],

    'api' => [
        'throttle:60,1',
    ],
];

This is from app/Http/Kernel.php

Notice how I’ve commented out \Illuminate\Session\Middleware\StartSession::class in $middlewareGroups["web"], and added it to $middleware? Doing that starts the session before Model::boot(), which means auth()->user() (or Auth::user()) will then return the logged-in user.

8. Make Your Own Helpers

I cannot tell you how many times I used the following code:

/** @var User $user */
$user = auth()->user();

/** @var Team $team */
$team = user()->currentTeam();

…before I created these helpers:

use App\User;
use App\Team;

if (!function_exists("user")) {
    /**
     * @return App\User
     */
    function user() {
        return auth()->user();
    }
}

if (!function_exists("team")) {
    /**
     * @return App\Team
     */
    function team() {
        return user()->team();
    }
}

They’re not crazy or complex. They’re not even a lot of code to type. But I recommend you include them from the start, because you’ll be typing (and type-hinting) the alternatives a lot.

9. Use Ngrok for Testing Web-Hooks

It’s rather common to build a product around one or more third-party services. Think about it — you’re already depending on Stripe and/or Braintree. What about when you want to post to Twitter, or send an SMS?

When that happens, you’ll often need to provide a web-hook URL. These are routes in your application that respond to (or gather data from) requests from the third-party service. It’s usually a delivery report from a transaction mail service, or confirmation data from that shipping provider.

You may be tempted to upload your application to a public server, so these third-party services can reach the web-hook URLs. You could do that (though it’s going to slow your development cycles dramatically) or you could use something like Ngrok to give your local development server an obscure public URL.

It’s easier than you think. Install Ngrok with Homebrew:

brew install ngrok

…Then serve your Laravel application (presumably with the PHP development server):

php artisan serve

…And in another tab, run Ngrok:

ngrok http 8000

You’ll see a public url (like http://7d54aeb8.ngrok.io -> localhost:8000). When you try that URL in your browser, you’ll be able to view your application!

Conclusion

If you’re on the fence about trying Spark, I can recommend it. It’s given my product a head-start it wouldn’t have had otherwise. Hopefully these tips will save you even more time. Have you discovered any tips for Spark development? Let your fellow developers know in the comments!

Frequently Asked Questions about Laravel Spark

What is Laravel Spark and why is it important?

Laravel Spark is a powerful, feature-rich library for Laravel, a popular PHP framework. It provides a range of functionalities that simplify the process of building robust, scalable web applications. It offers a pre-built authentication system, subscription billing, team management, and other essential features. This saves developers a significant amount of time and effort, allowing them to focus on the unique aspects of their application rather than reinventing the wheel.

How can I get started with Laravel Spark?

To get started with Laravel Spark, you first need to install Laravel and Composer, a dependency management tool for PHP. Once these are installed, you can use Composer to install Spark. After installation, you can start building your application using Spark’s features. Remember to refer to the official Laravel and Spark documentation for detailed instructions and best practices.

What are some tips for using Laravel Spark effectively?

There are several tips that can help you use Laravel Spark more effectively. First, familiarize yourself with the features and capabilities of Spark. This will help you understand how to best leverage its functionalities. Second, follow best practices for Laravel development. This includes using version control, writing clean and maintainable code, and thoroughly testing your application. Finally, take advantage of the community resources available, such as forums, tutorials, and documentation.

How does Laravel Spark compare to other Laravel packages?

Laravel Spark stands out from other Laravel packages due to its comprehensive set of features. While other packages may offer specific functionalities, Spark provides a complete solution for building web applications. This includes user authentication, subscription billing, team management, and more. Additionally, Spark is officially supported by Laravel, ensuring its quality and reliability.

Can I customize Laravel Spark to suit my needs?

Yes, Laravel Spark is highly customizable. You can modify its views, routes, and controllers to suit your application’s specific needs. Additionally, you can extend its functionality by integrating it with other Laravel packages or third-party services. Remember to follow best practices when customizing Spark to ensure the maintainability and stability of your application.

What are the system requirements for Laravel Spark?

Laravel Spark has the same system requirements as Laravel. This includes a web server, PHP, and a database. Additionally, you need Composer to manage dependencies. For detailed system requirements, refer to the official Laravel documentation.

How can I troubleshoot issues with Laravel Spark?

If you encounter issues with Laravel Spark, there are several steps you can take. First, check the error messages for clues about the problem. Second, refer to the official Spark and Laravel documentation for guidance. Third, search for similar issues on community forums or Stack Overflow. If all else fails, consider reaching out to the Laravel community for help.

Is Laravel Spark suitable for large-scale applications?

Yes, Laravel Spark is suitable for both small and large-scale applications. Its robust features and scalability make it a good choice for complex, high-traffic applications. However, for very large applications, you may need to consider additional factors such as server infrastructure and database optimization.

How can I keep my Laravel Spark application secure?

Laravel Spark includes several security features, such as CSRF protection and secure password hashing. However, application security also depends on best practices, such as keeping your software up to date, using secure connections, and following the principle of least privilege. Additionally, regularly review your application for potential security vulnerabilities.

Where can I learn more about Laravel Spark?

The best place to learn more about Laravel Spark is the official Laravel and Spark documentation. These provide detailed information about Spark’s features, installation, and usage. Additionally, there are many tutorials, blog posts, and online courses available that cover Laravel Spark in depth.