Blog Detail

14

Sep
Now Build Your custom Laravel Model Searches a lot easier cover image

arrow_back Now Build Your custom Laravel Model Searches a lot easier

Laravel Model Finder is a simple trait that makes building your own custom Laravel Model Searches a lot easier and safer. It ensures that your search criteria match one, and only one, result in the table being searched, allowing you to comfortably type-hint your methods by ensuring that the result of a query will never be null or a Collection, but always an instance of the specific Model you’re querying. It does this by searching for a row that uniquely contains the data you’re looking for in one of the named columns. That’s the selling point of this package; it will only return a result if that result is the only result for your query.

Installation

To use this library, all you need to do is require the package in the root directory of your Laravel project:

composer require brekitomasson/laravel-model-finder

Usage

This package is used by adding one of the two traits that it offers to a class. There are two traits because there are two main ways to use this package; either by (1) building your own custom Finder-classes or by (2) adding unique search-functionality to your Models.

1. Building Your Own Finder-Class

Let’s create a new CountryFinder in the App\Tools namespace. It doesn’t need to extend or implement any other classes, but it needs to use the CanFindModelEntries trait. Depending on your IDE, this will then inform you that you have a method stub for the static method find that needs to be implemented, so let’s do that.

Now, since PHP doesn’t natively support abstract keywords in their Traits (Seriously, PHP; what’s up with that?), we have to implement the next two things manually. They are the protected static array $queryKeys and the protected static Model|string $queryModel. You populate these with:

  • protected static array $queryKeys: An array containing the list of attributes to be searched, and
  • protected static Model|string $queryModel: the FQN (including ::class) of the Model being searched.
    At this point, the file should look something like this:
<?php

declare(strict_types = 1);

namespace App\Tools;

use BrekiTomasson\LaravelModelFinder\CanFindModelEntries;
use Illuminate\Database\Eloquent\Model;

class CountryFinder
{
    use CanFindModelEntries;
    
    protected static array $queryKeys = [
        'alpha2',
        'alpha3',
        'name',
        'short_name',
    ];

    protected static Model|string $queryModel = \App\Models\World\Country::class;

    public static function find(mixed $value) : Model
    {
        // TODO: Implement find() method.
    }
}

The next step is to implement the find(mixed $value) method. The way you implement the find(mixed $value) is fairly standardized but has been left to the user so that any customization or tweaking can be done here. A fairly standard implementation - with inline comments for added clarification - will look something like the code below, which you can copy/paste into your own implementation. Note that I’ve changed the return type of the find() method from the default Model to Country here, so that my IDE will correctly understand which methods and attributes are available on the returned object rather than suggesting the methods and attributes on the base Model class.

public static function find(mixed $value) : Country
{
    // First, we 'clean' the value by removing any trailing or leading spaces, squishing extra spaces down to
    // single spaces, casting the result to string, etc.
    $value_object = new \BrekiTomasson\LaravelModelFinder\DataObjects\ValueObject($value);
    
    // Then, we generate the Cache Helper using the Value Object we've just generated. This will allow us to query
    // the cache for the search criteria you've entered.
    $cache = self::getCacheHelper($value_object);

    // If we've already got the results for this search in our cache, we can return it as is.
    if ($cache->exists()) {
        return $cache->get();
    }

    // Perform the search and store the result in $result. This will throw a ModelNotFoundException if no result is
    // found or a MultipleRecordsFoundException if two or more results are found.
    $result = self::searchInModel($value_object);

    // Return $result, ensuring we also store it in the cache for future use.
    return $cache->put($result);
}

2. Powering Up Your Models

Please read through Method 1 first to understand a little more about how this package works under the hood, as that will help you understand this method of implementation better.

This way of implementing the package does not require you to create an entirely new class. Instead, all you need to do is use CanBeSoleSearched inside of the Model you wish to be searchable and define the required attributes, same as above. Unfortunately, you still need to define the $queryModel property as there is no good way for a static method to automatically populate this field from within a Trait, although this is something that I’m trying to figure out a good way to do for a future release.

After that is done, you should be able to call Country::findSole(‘taiwan’), for example, and it will scan the columns defined in $queryKeys and return a single result, if available. You can, of course, define your own findSole method that overwrites the one defined in the trait, but this is usually not necessary.

For more details & source code please visit here.

Published at : 14-09-2022

Author : Rizwan Aslam
AUTHOR
Rizwan Aslam

I am a highly results-driven professional with 12+ years of collective experience in the grounds of web application development especially in laravel, native android application development in java, and desktop application development in the dot net framework. Now managing a team of expert developers at Codebrisk.

Launch your project

Launch project