creatortsv/eloquent-elastic-sync

This package helps sync indexing your eloquent models into elasticsearch

dev-master 2020-08-29 19:24 UTC

This package is auto-updated.

Last update: 2024-11-12 15:34:22 UTC


README

This package helps you to sync your eloquent models with elasticsearch documents

tests License Latest Stable Version

Prerequisites

  • PHP >= 7.2

Installation

  1. Run composer command:
composer require creatortsv/eloquent-elastic-sync
  1. Add EloquentObservant trait to your eloquent models which will be syncronized with elasticsearch:
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Creatortsv\EloquentElasticSync\EloquentObservant;

class Flight extends Model
{
    /* ... */
    use EloquentObservant;
    /* ... */
}

Configuration

You may want to create config/elastic_sync.php config file or import it from the package using this artisan command

php artisan vendor:publish --provider="Creatortsv\EloquentElasticSync\EloquentElasticSyncProvider"

For the minimum configuration You should edit host and port properties of the connections.default section of your config/elastic_sync.php config file:

<?php

return [

    /*
     * Describe different connections
     */
    'connections' => [

        /*
         * Connection name
         */
        'default' => [

            'host' => env('ELASTIC_HOST'),
            'port' => env('ELASTIC_PORT'),

        ],

    ],

];

If You want to use another connection by default then describe your own connection into the connections section and change the connection property of the config/elastyc_sync.php file:

<?php

return [
    
    /*
     * Which connection settings will be used
     */
    'connection' => 'awesome_connection', // default

    /*
     * Describe different connections
     */
    'connections' => [

        /* ... */
        
        'awesome_connection' => [

            'host' => 'awesome.com',
            'port' => 9201,

        ],
        
        /* ... */

    ],
    
];

If You want to use different connections for your eloquent models:

  • Describe your own connections for some eloquent models into the connections section of the config/elastyc_sync.php file
<?php

return [
    
    /*
     * Describe different connections
     */
    'connections' => [

        /* ... */
        
        'flights-connection' => [

            'host' => 'awesome.users.com',
            'port' => 9202,

        ],
        
        /* ... */

    ],

];
  • Override the php protected static function boot(): void method into your Eloquent models and set connection name like this
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Creatortsv\EloquentElasticSync\EloquentObservant;

class Flight extends Model
{
    use EloquentObservant;
    
    protected static function boot(): void
    {
        parent::boot();

        static::elastic()->setConnection('flights-connection');
    }
    
    /* ... */
}

Data mapping

By default an Eloquent model will be syncronized to the Elasticsearch document with its own attributes (without relations). But if You want to sync models with mutated attributus, for example:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Creatortsv\EloquentElasticSync\EloquentObservant;

class Flight extends Model
{
    use EloquentObservant;
    
    /* ... */
    
    /**
     * Get full name of the flight
     *  @return string
     */
    public function getFlightNameAttribute(): string
    {
        return $this->name . ' ' . $this->destination;
    }
    
    /* ... */
}

Then You should change the use_mutated_fields property of your config/elastic_sync.php file to true

<?php

return [
    /* ... */
    
    'use_mutated_fields' => true,
    
    /* ... */
];

You can use your own data mapping and index name for your Eloquent models, this data will be used for interacting with Elasticserch index|update|delete actions. By default Index name for Eloquent models (if indexes.default property is null) is equal to the table name property of the Model. You can do it with two different ways:

  1. Describe a data mapping into indexes section of the config/elastyc_sync.php file and set the default option. Also Data mapping may be described for every single Model
<?php

return [
    /* ... */
    
    /*
     * Describe different indexes & its fields
     */
    'indexes' => [
    
        'default' => 'my-index', // if it is null then attributes of model will be used
        
        /**
         * Index name it'll bwe used as index for the documents
         */
        'my-index' => [
        
            /**
             * Base mapping for models
             */
            'base_mapping' => [
            
                'id',
                'name,
            /** 'avatar' => 'avatar.safe_url', Dot anotation allowed for the relations */
            
            ],
            
            App\Flight::class => [
            
                /* ... This mapping will be merged with the base_mapping of the described index */
            
            ],
        
        ],
    
    ],
    
    /* ... */
];
  1. Configure it behavior with boot() method on your Eloquent models
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Creatortsv\EloquentElasticSync\EloquentObservant;

class Flight extends Model
{
    use EloquentObservant;
    
    /* ... */
    
    protected static function boot(): void
    {
        parent::boot();

        /**
         * Use custom data mapping
         * Don't use real data, only field names
         */
        static::elastic()->setMapping(function (Model $model): array {
            return [
                /* Describe yor mapping here */
            ];
        });
        
        /**
         * This name will be used as index for the Elasticsearch document
         */
        static::elastic()->setIndexName('flights-index');
    }
    
    /* ... */
}

For each Eloquent model class You can add Extra fields for the indexing document, like this

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Creatortsv\EloquentElasticSync\EloquentObservant;

class Flight extends Model
{
    use EloquentObservant;
    
    /* ... */
    
    protected static function boot(): void
    {
        parent::boot();

        /**
         * Using callback
         */
        static::elastic()->addExtra('group', function (Model $model): array {
            return $model->getTable();
        });
        
        /**
         * Using simple assign action
         */
        static::elastic()->addExtra('my_field', 'my_value');
    }
    
    /* ... */
}

Also You can modify fields and extra fields before send it to the Elasticsearch document with callback functions, like this

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Creatortsv\EloquentElasticSync\EloquentObservant;

class Flight extends Model
{
    use EloquentObservant;
    
    /* ... */
    
    protected static function boot(): void
    {
        parent::boot();

        /**
         * Modify group extra field for example
         * @param mixed $group It is value after data mapping operation
         * @param array $data All data values after data mapping operation
         */
        static::elastic()->addCallback('group', function ($group, array $data, Model $model) {
            return $group . ' company: ' . $model->company->name; // result: flights company: Some Company Name
        });
        
        /**
         * Another time
         */
        static::elastic()->addCallback('group', function ($group, array $data, Model $model) {
            return $group . ' fixed'; // result: flights company: Some Company Name fixed
        });
    }
    
    /* ... */
}

Artisan Command

Work in progress ...