Magellan 2.x introduce some breaking changes, which enforces some migrations.
The following 5 Steps provide all the necessary information by examples.
With Magellan 2.x we move from having a trait with casting logic to the default Laravel Way of using casters and made all
Geometry
classes available as casters for a better syntax.
use Clickbar\Magellan\Database\Eloquent\HasPostgisColumns;
use Clickbar\Magellan\Cast\BBoxCast;
class Port extends Model
{
use HasPostgisColumns;
protected array $postgisColumns = [
'location' => [
'type' => 'geometry',
'srid' => 4326,
],
];
protected array $casts = [
'bounding_box' => BBoxCast::class
];
}
use Clickbar\Magellan\Data\Geometries\Point;
use Clickbar\Magellan\Data\Boxes\Box2D;
class Port extends Model
{
protected array $casts = [
'location' => Point::class,
'bounding_box' => Box2D::class,
];
}
Remove the HasPostgisColumns
trait and the
$postgisColumns
array and add the appropriate cast based on the geometry in the database (e.g. Point::class, Geometry::class, LineString::class, ...).
Also change from the generic BBoxCast
to the appropriate Box model class (e.g. Box2D::class
or Box3D::class
).
With the 2.x release we've removed the custom
st
-prefixed query builder methods. You can now use the default Laravel methods.
The ST
functions can now be used directly in the query builder methods.
For renaming the results we added a new
Aliased
expression class, which can be used to rename the result of a function.
But we also added a utility function on all ST
expressions: ST::distanceSphere(...)->as("myalias")
.
$currentShipPosition = Point::makeGeodetic(50.107471773560114, 8.679861151457937);
$portsWithDistance = Port::select(['name', 'country'])
->stSelect(ST::distanceSphere($currentShipPosition, 'location'), as: 'distance_to_ship')
->stWhere(ST::distanceSphere($currentShipPosition, 'location'), '<=', 50000)
->stOrderBy(ST::distanceSphere($currentShipPosition, 'location'))
->get();
$currentShipPosition = Point::makeGeodetic(50.107471773560114, 8.679861151457937);
$portsWithDistance = Port::select(['name', 'country'])
->addSelect(ST::distanceSphere($currentShipPosition, 'location')->as('distance_to_ship'))
->where(ST::distanceSphere($currentShipPosition, 'location'), '<=', 50000)
->orderBy(ST::distanceSphere($currentShipPosition, 'location'))
->withMagellanCasts() // <-- automatically adds casts for st functions returning geometry or bbox
->get();
For almost all methods, we can simply remove the st-
prefix and use the default Laravel methods.
stSelect
is a special case: It acted like an
addSelect
and also automatically took care of the casting. Therefore, it must be replaced by a call to
addSelect
and we also need to add a call to withMagellanCasts()
.
In fact, in this concrete example, we can now completely get rid of the addSelect
by merging it into the other
select
:
$portsWithDistance = Port::select([
'name',
'country',
ST::distanceSphere($currentShipPosition, 'location')->as('distance_to_ship'),
])
The 1.x version of Magellan always used a
::geometry
cast under the hood for all parameters that expected any kind of geometry. In case there was a function that could also take geography, the function had an optional parameter named
$geometryType
which could be used to tell Magellan to use ::geography
instead.
With Magellan 2.x we decided to remove this. With the most amount of
ST_
functions of PostGIS being defined on geometry only anyway, we wanted to give back the developer a bit more control and also responsibility.
If you want to cast your input, you now need to use the AsGeometry
and
AsGeography
cast expressions wrapping the geometry or function you want to cast.
But let's look at this using an example. If you want to use st_buffer to buffer a geometry using a radius in meters, you need a geography as input instead of geometry.
$bufferedPorts = Port::query()
->stSelect(ST::buffer('location', 50, geometryType: GeometryType::geography), as: 'buffered_location'))
->get();
$bufferedPorts = Port::query()
->select(ST::buffer(new AsGeography('location'), 50)->as('buffered_location'))
->withCasts(['buffered_location' => Polygon::class]) // or ->withMagellanCasts()
->get();
NOTE Only relevant if you used magellan.eloquent.transform_to_database_projection = true in config.
Port::create([
'name' => 'Magellan Home Port',
'country' => 'Germany',
'location' => Point::make(473054.9891044726, 5524365.310057224, srid: 25832),
]);
// -- or --
$port = Port::find(1);
$port->location = Point::make(473054.9891044726, 5524365.310057224, srid: 25832);
$port->save();
With the removal of the HasPostgisColumns
trait we also removed the auto transform feature.
If you relied on this, you now need to transform it directly on insert or update using ST::transform
:
$point = Point::make(473054.9891044726, 5524365.310057224, srid: 25832);
Port::create([
'name' => 'Magellan Home Port',
'country' => 'Germany',
'location' => ST::transform($point, 4326),
]);
// -- or --
$port = Port::find(1);
$port->query()->update([
'location' => ST::transform(Point::make(473054.9891044726, 5524365.310057224, srid: 25832), 4326),
]);
NOTE Only relevant if you used the
GeometryWKBCast
directly somewhere
$hullWithArea = Port::select('country')
->stSelect(ST::convexHull(ST::collect('location')), 'hull')
->stSelect(ST::area(ST::convexHull(ST::collect('location'))))
->groupBy('country')
->withCasts(['hull' => GeometryWKBCast::class])
->first();
$hullWithArea = Port::query()
->select([
'country',
ST::convexHull(ST::collect('location'))->as('hull'),
ST::area(ST::convexHull(ST::collect('location'))),
])
->groupBy('country')
->withCasts(['hull' => Polygon::class])
->first();
We removed the GeometryWKBCast
class and added new casters using the appropriate Geometry class.
You can also go ahead and remove the magellan.eloquent
config and the magellan.model_directories
configs.
We also renamed the toString
function on Box classes to toRawSql
.
The BBoxCast
class was refactored and the Box2D / Box3D classes should be used as casts directly instead.
For a more detailed list of changes, please refer to the CHANGELOG.