Translatable::saveTranslation()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 10
Bugs 6 Features 0
Metric Value
eloc 4
c 10
b 6
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Mikehins\Translatable;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\DB;
7
use Illuminate\Support\Str;
8
9
trait Translatable
10
{
11
    public static $transtableFieldName = 'translatable';
12
    
13
    public $translatable;
14
    public $model;
15
    
16
    protected $locale;
17
    
18
    public static function bootTranslatable()
19
    {
20
        static::addGlobalScope(new TranslatableScope);
21
        
22
        static::saving(function ($model) {
23
            $model->translatable = collect($model->attributes)->only(static::$transtableFieldName)->toArray();
24
            $model->attributes = collect($model->attributes)->except(static::$transtableFieldName)->toArray();
25
        });
26
        
27
        static::saved(function ($model) {
28
            if ($model->translatable) {
29
                (new self)->saveTranslation($model);
30
            }
31
        });
32
        
33
        static::deleted(function ($model) {
34
            if ((new $model)->has('translations')) {
35
                $model->translations()->delete();
36
            }
37
        });
38
    }
39
    
40
    public function locale($value = null)
41
    {
42
        $this->locale = $value;
43
        
44
        return $this;
45
    }
46
    
47
    // Relationship
48
    public function translations()
49
    {
50
        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

50
        return $this->/** @scrutinizer ignore-call */ morphMany(Translation::class, 'translatable');
Loading history...
51
    }
52
    
53
    // scope
54
    public function scopeTranslated($query, ...$fields)
55
    {
56
        $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

56
        $this->locale = $this->locale ?? app()->/** @scrutinizer ignore-call */ getLocale();
Loading history...
57
        
58
        $fields = empty($fields) ? $this->getTranslatedFieldsForCurrentModel() : collect($fields);
59
        
60
        if ($fields->isEmpty()) {
61
            return $query;
62
        }
63
        
64
        // Add select * if nothing has been selected yet
65
        if ($query->getQuery()->columns === null) {
66
            $query->select('*');
67
        }
68
        
69
        // Build the sub select
70
        $fields->each(function ($key) use ($query) {
71
            $this->subSelectTranslation($query, $key);
72
        });
73
        
74
        return $query;
75
    }
76
    
77
    protected function subSelectTranslation($query, $key): void
78
    {
79
        $query->addSelect([
80
            $key => function ($query) use ($key) {
81
                $query->select(Translation::getTableName() . '.value')
82
                    ->from(Translation::getTableName())
83
                    ->where(Translation::getTableName() . '.translatable_type', '=', \get_class($this))
84
                    ->where(Translation::getTableName() . '.locale', '=', $this->locale)
85
                    ->where(Translation::getTableName() . '.key', '=', $key)
86
                    ->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

86
                    ->where(Translation::getTableName() . '.translatable_id', '=', \DB::raw($this->/** @scrutinizer ignore-call */ getTable() . '.' . $this->primaryKey));
Loading history...
87
            }
88
        ]);
89
    }
90
    
91
    /**
92
     * Query the translations table for possible keys if none are provided.
93
     * @return Collection
94
     */
95
    public function getTranslatedFieldsForCurrentModel(): Collection
96
    {
97
        $table = Translation::getTableName();
98
        
99
        return DB::table($table)->select($table . '.key')
100
            ->where($table . '.translatable_type', \get_class($this))
101
            ->where($table . '.locale', $this->locale)
102
            ->groupBy($table . '.key')
103
            ->pluck('key');
104
    }
105
    
106
    public function saveTranslation($model): int
107
    {
108
        return (new Translation)->store([
109
            'translatable'      => $model->translatable[static::$transtableFieldName],
110
            'translatable_type' => \get_class($model),
111
            'translatable_id'   => $model->id,
112
        ]);
113
    }
114
    
115
    protected function fullTextWildcards($term)
116
    {
117
        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

117
        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...
118
            return strlen(trim($word)) >= 3 ? '+' . trim($word) . '*' : '';
119
        })->implode(' ');
120
    }
121
    
122
    public function scopeSearchFullText($query, $term)
123
    {
124
        $term = $this->fullTextWildcards($term);
125
        
126
        $matches = Translation::selectRaw('translatable_id, MATCH(`value`) AGAINST (\'' . $term . '\' IN BOOLEAN MODE) as relevance')
127
            ->whereRaw(\DB::raw('MATCH (`value`) AGAINST (\'' . $term . '\' IN BOOLEAN MODE)'))
128
            ->where('translations.translatable_type', '=', \get_class($this))
129
            ->having('relevance', '>', 0)
130
            ->orderBy('relevance')
131
            // force to search only in the current language
132
            //->where('translations.locale', app()->getLocale());
133
            ->pluck('translatable_id')
134
            ->toArray();
135
        
136
        return $query->whereIn(DB::raw($this->getTable() . '.' . $this->primaryKey), $matches);
137
    }
138
}
139