Passed
Push — master ( 986e68...75c6dc )
by Yaroslav
14:23
created

HasCoordinates::getLatitude()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace LaraGeoData\Models;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Support\Facades\DB;
7
use LaraGeoData\Contracts\ModelWithCoordinates;
8
9
trait HasCoordinates
10
{
11
    /**
12
     * Table column name for latitude.
13
     */
14 4
    public function latitudeColName(): string
15
    {
16 4
        return $this->latitudeColumnName ?? 'lat';
17
    }
18
19
    /**
20
     * Table column name for longitude.
21
     */
22 4
    public function longitudeColName(): string
23
    {
24 4
        return $this->longitudeColumnName ?? 'lng';
25
    }
26
27
    /**
28
     * Filed name for distance. This field will be created only id use "nearest" scope.
29
     */
30 4
    public function distanceColName(): string
31
    {
32 4
        return $this->distanceColumnName ?? 'distance';
33
    }
34
35
    /**
36
     * Haversine formula (from Google solution example).
37
     * By default use radius in kilometers.
38
     */
39 2
    public function scopeNearest(Builder $query, float $lat, float $lng, float $radius, int $coef = ModelWithCoordinates::HAVERSINE_COEF_KILOMETERS)
40
    {
41 2
        $latColName        = $this->latitudeColName();
42 2
        $lngColName        = $this->longitudeColName();
43 2
        $distanceFieldName = $this->distanceColName();
44
45 2
        return $query->select([
46 2
            '*',
47 2
            DB::raw("
48 2
               ( {$coef} *
49 2
               acos(cos(radians({$lat})) *
50 2
               cos(radians({$latColName})) *
51 2
               cos(radians({$lngColName}) -
52 2
               radians({$lng})) +
53 2
               sin(radians({$lat})) *
54 2
               sin(radians({$latColName})))
55 2
            ) AS {$distanceFieldName} "),
56 2
        ])->having($distanceFieldName, '<=', $radius);
57
    }
58
59 1
    public function scopeNearestInKilometers(Builder $query, float $lat, float $lng, float $radius)
60
    {
61 1
        return $this->scopeNearest($query, $lat, $lng, $radius, ModelWithCoordinates::HAVERSINE_COEF_KILOMETERS);
62
    }
63
64 1
    public function scopeNearestInMiles(Builder $query, float $lat, float $lng, float $radius)
65
    {
66 1
        return $this->scopeNearest($query, $lat, $lng, $radius, ModelWithCoordinates::HAVERSINE_COEF_MILES);
67
    }
68
69
    /**
70
     * Order query results by distance.
71
     */
72 2
    public function scopeOrderByNearest(Builder $query, string $direction = 'asc')
73
    {
74 2
        return $query->orderBy($this->distanceColName(), $direction);
75
    }
76
77
    /**
78
     * Field has value only is use "nearest" scope.
79
     */
80 4
    public function getDistanceAttribute(): float
81
    {
82 4
        if (array_key_exists($this->distanceColName(), $this->attributes)) {
83 4
            return (float) $this->attributes[$this->distanceColName()];
84
        }
85
86
        return 0;
87
    }
88
89 2
    public function getLatitude(): ?float
90
    {
91 2
        return $this->{$this->latitudeColName()};
92
    }
93
94 2
    public function getLongitude(): ?float
95
    {
96 2
        return $this->{$this->longitudeColName()};
97
    }
98
99 2
    public function getDistance(): float
100
    {
101 2
        return $this->distance;
102
    }
103
}
104