Home

Building a Store Locator using Laravel, Leaflet and Meilisearch - Part 1

Meilisearch for maps

Overview

The requirement for data to be displayed on a map is something i've witnessed over again. Often in completely different industries and circumstances but usually implemented in similar manners. Meilisearch and Leaflet JS make usefully displaying this data extremely easy to achieve.

In this walkthrough, we will create a store locator in Laravel that uses Meilisearch and Leaflet JS to allow a user find results within a radius of the postcode that they provide.

Meilisearch

Meilisearch is an open source, super fast, search engine inspired by Algolia and requiring very little setup. Meilisearch provides instant search and typo tolerance out of the box and with a few updates to settings Geosearches become a breeze.

Leaflet

Leaflet is a lightweight open source JS library that makes mapping incredibly quick and easy.

For this project i used:

Requirements:

Laravel Project Setup

Create a new project using your preferred method. I use the Laravel installer via Composer and use Laravel Valet which lets me quickly access the new project via store-locator.test in the browser.

// Composer
composer create-project laravel/laravel store-locator

// Laravel Installer
laravel new store-locator

Although authentication is not needed for this example, I added Laravel Breeze to the fresh Laravel application to quickly make use of the frontend scaffolding that comes for free.

composer require laravel/breeze --dev

Install Laravel Breeze by running the install command with the frontend option of choice. For this project i opted for Vue.

php artisan breeze:install vue

Database

Set up the database of choice by updating the necessary database settings in the project .env file.

For speed I used SQLite by creating a file named database.sqlite inside the database directory and updating the database connection to sqlite in .env.

Once updated continue the Breeze instructions to run database migrations, install JS dependencies and compile frontend assets.

php artisan migrate

npm install

npm run dev

Leaflet JS Installation

To display the store locator, I used Leaflet, a small JS package that makes mapping incredibly easy.

Install Leaflet into your project using NPM

npm install leaflet

and then import the CSS and JS files in resources/js/app.js

...
import 'leaflet/dist/leaflet.css'
import L from 'leaflet';

Alternatively add the CSS and JS links to the head of your page.

// CSS
<link
    rel="stylesheet"
    href="https://unpkg.com/leaflet@1.9.2/dist/leaflet.css"
    integrity="sha256-sA+zWATbFveLLNqWO2gtiw3HL/lh1giY/Inf1BJ0z14="
    crossorigin=""
/>

// JS
<script
    src="https://unpkg.com/leaflet@1.9.2/dist/leaflet.js"
    integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg="
    crossorigin="">
</script>

Postcodes.io

In order to plot locations, real postcodes/LatLng values are required, and as Faker does not necessarily return valid postcodes, I used postcodes.io

This is an open source service that is capable of returning location data when provided with a postcode. As a potentially large number of calls to the service would be required, to save on network calls, I hosted the service locally using Docker.

Launch the postcodes.io service by firstly running the DB container

docker run --name=the_db -p 5432:5432 -e POSTGRES_USER=postcodesio -e POSTGRES_DB=postcodesiodb -e POSTGRES_PASSWORD=password -d idealpostcodes/postcodes.io.db:latest

and then firing up the API.

docker run -p 8000:8000 --link=the_db:db -e POSTGRES_HOST=db -e POSTGRES_USER=postcodesio -e POSTGRES_DATABASE=postcodesiodb -e POSTGRES_PASSWORD=password -d idealpostcodes/postcodes.io:latest

Test that things are running correctly by running curl localhost:8000/random/postcodes in the terminal or sending a GET request to the same endpoint using your favourite API client. This should return a random location.

Config

Create a file named postcodes_io.php in /config and add a key that returns the POSTCODES_IO_URL value if present from .env or the url to the postcodes.io api if not set so the base url can be set if using a local/remote version of the service.

<?php

    return [
        'postcodes_io_url' => env('POSTCODES_IO_URL', 'https://api.postcodes.io')
    ];

If self serving postcodes.io, add the POSTCODES_IO_URL key to .env and set the value to the url of the service with the relevant port. For me this was localhost:8000.

Meilisearch

To run Meilisearch, I used a local Docker container that can be started using the below command1. The below exposes the container on port 7700 in dev mode and uses "MASTER_KEY" for the master key.

docker run -it --rm -p 7700:7700 -e MEILI_MASTER_KEY='MASTER_KEY' -v $(pwd)/meili_data:/meili_data getmeili/meilisearch:v0.29 meilisearch --env="development"

Laravel Scout

Laravel Scout is a first party Laravel package that adds full-text search functionality to Laravel models, the package has drivers for a number of third party solutions including Meilisearch and Algolia out of the box.

Install Laravel Scout to the project

composer require laravel/scout

and then publish the Scout config file

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

Next add the Meilisearch PHP SDK as per the Scout installation instructions 2

composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle

Finally update the Scout and Meilisearch settings in .env, using the master key you set in the Meiliseach setup section and the location of the running Docker container.

SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=localhost:7700
MEILISEARCH_KEY=MASTER_KEY

Now we should have the postcodes.io and Meilisearch services running locally and an empty project that is ready to connect with and utilise them both.

In the next part, we'll seed the database and build a front end in Vue that is able to query the services and retrieve geo based results.

Building a Store Locator using Laravel, Leaflet and Meilisearch - Part 2