Completed
Push — master ( 05e8ff...9e3da7 )
by Mike
04:57
created

Translatable::scopeSearchFullText()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 13
rs 9.9666
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Mikehins\Translatable;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
8
trait Translatable
9
{
10
    public static $transtableFieldName = 'translatable';
11
    
12
    public $translatable;
13
    public $model;
14
    
15
    protected $locale;
16
    
17
    public static function bootTranslatable()
18
    {
19
        static::addGlobalScope(new TranslatableScope);
20
        
21
        static::saving(function ($model) {
22
            $model->translatable = collect($model->attributes)->only(static::$transtableFieldName)->toArray();
23
            $model->attributes = collect($model->attributes)->except(static::$transtableFieldName)->toArray();
24
        });
25
        
26
        static::saved(function ($model) {
27
            if ($model->translatable) {
28
                (new self)->saveTranslation($model);
29
            }
30
        });
31
        
32
        static::deleted(function ($model) {
33
            if ((new $model)->has('translations')) {
34
                $model->translations()->delete();
35
            }
36
        });
37
    }
38
    
39
    public function locale($value = null)
40
    {
41
        $this->locale = $value;
42
        
43
        return $this;
44
    }
45
    
46
    // Relationship
47
    public function translations()
48
    {
49
        return $this->morphMany(Translation::class, 'translatable');
0 ignored issues
show
Bug introduced by
It seems like morphMany() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

49
        return $this->/** @scrutinizer ignore-call */ morphMany(Translation::class, 'translatable');
Loading history...
50
    }
51
    
52
    // scope
53
    public function scopeTranslated($query, ...$fields)
54
    {
55
        $this->locale = $this->locale ?? app()->getLocale();
0 ignored issues
show
introduced by
The method getLocale() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        $this->locale = $this->locale ?? app()->/** @scrutinizer ignore-call */ getLocale();
Loading history...
56
        
57
        $fields = empty($fields) ? $this->getTranslatedFieldsForCurrentModel() : collect($fields);
58
        
59
        if ($fields->isEmpty()) {
60
            return $query;
61
        }
62
        
63
        // Add select * if nothing has been selected yet
64
        if ($query->getQuery()->columns === null) {
65
            $query->select('*');
66
        }
67
        
68
        // Build the sub select
69
        $fields->each(function ($key) use ($query) {
70
            $this->subSelectTranslation($query, $key);
71
        });
72
        
73
        return $query;
74
    }
75
    
76
    protected function subSelectTranslation($query, $key): void
77
    {
78
        $query->addSelect([
79
            $key => function ($query) use ($key) {
80
                $query->select(Translation::getTableName() . '.value')
81
                    ->from(Translation::getTableName())
82
                    ->where(Translation::getTableName() . '.translatable_type', '=', \get_class($this))
83
                    ->where(Translation::getTableName() . '.locale', '=', $this->locale)
84
                    ->where(Translation::getTableName() . '.key', '=', $key)
85
                    ->where(Translation::getTableName() . '.translatable_id', '=', \DB::raw($this->getTable() . '.' . $this->primaryKey));
0 ignored issues
show
Bug introduced by
It seems like getTable() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

85
                    ->where(Translation::getTableName() . '.translatable_id', '=', \DB::raw($this->/** @scrutinizer ignore-call */ getTable() . '.' . $this->primaryKey));
Loading history...
86
            }
87
        ]);
88
89
//        $query->addSelect(\DB::raw('(
90
//			SELECT      `' . Translation::getTableName() . '`.`value`
91
//			  FROM      `' . Translation::getTableName() . '`
92
//			 WHERE      `' . Translation::getTableName() . '`.`translatable_type` = "' . \get_class($this) . '"
93
//			   AND      `' . Translation::getTableName() . '`.`locale` = "' . $this->locale . '"
94
//			   AND      `' . Translation::getTableName() . '`.`key` = "' . $key . '"
95
//			   AND      `' . Translation::getTableName() . '`.`translatable_id` = `' . $this->getTable() . '`.`' . $this->primaryKey . '`
96
//			) as `' . $key . '`')
97
//        );
98
    }
99
    
100
    /**
101
     * Query the translations table for possible keys if none are provided.
102
     * @return Collection
103
     */
104
    public function getTranslatedFieldsForCurrentModel(): Collection
105
    {
106
        $table = Translation::getTableName();
107
        
108
        return DB::table($table)->select($table . '.key')
109
            ->where($table . '.translatable_type', \get_class($this))
110
            ->where($table . '.locale', $this->locale)
111
            ->groupBy($table . '.key')
112
            ->pluck('key');
113
    }
114
    
115
    public function saveTranslation($model): int
116
    {
117
        return (new Translation)->store([
118
            'translatable'      => $model->translatable[static::$transtableFieldName],
119
            'translatable_type' => \get_class($model),
120
            'translatable_id'   => $model->id,
121
        ]);
122
    }
123
    
124
    protected function fullTextWildcards($term)
125
    {
126
        return collect(explode(' ', str_replace(['-', '+', '<', '>', '@', '(', ')', '~'], '', $term)))->map(function ($word, $key) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

126
        return collect(explode(' ', str_replace(['-', '+', '<', '>', '@', '(', ')', '~'], '', $term)))->map(function ($word, /** @scrutinizer ignore-unused */ $key) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
127
            return strlen($word) >= 3 ? '+' . $word . '*' : '';
128
        })->implode(' ');
129
    }
130
    
131
    public function scopeSearchFullText($query, $term)
132
    {
133
        return $query->join('translations', 'translations.translatable_id', '=', 'products.id')
134
            ->addSelect([
135
                'relevance' => function ($query) use ($term) {
136
                    $query->selectRaw("MATCH (`translations`.`value`) AGAINST ('" . $this->fullTextWildcards($term) . "' IN BOOLEAN MODE)")
137
                        ->from('translations')
138
                        ->where('translations.translatable_id', DB::raw($this->getTable() . '.' . $this->primaryKey))
139
                        ->limit(1);
140
                }
141
            ])
142
            ->whereRaw("MATCH (`translations`.`value`) AGAINST (? IN BOOLEAN MODE)", $this->fullTextWildcards($term))
143
            ->orderByDesc('relevance');
144
    }
145
}
146