looptribe/form-spatial
Laravel package that adds spatial form fields to Looptribe Form, making it easy to capture and edit geographic data such as points, coordinates, and geometries in your forms. Includes field rendering, validation, and model integration for geospatial inputs.
Reality check before you install: this bundle targets Symfony 2.x (the AppKernel / app/config/config.yml era), has had no release since April 2018, and is archived upstream. It is GPL-2.0, has zero dependents and a single-digit star count, so treat it as reference source you may vendor/fork rather than a dependency you composer require into a live product.
Minimal path in a Symfony 2.x app:
composer require looptribe/form-spatial
// app/AppKernel.php
public function registerBundles()
{
$bundles = [
// ...
new Looptribe\...\...Bundle(), // FQCN exactly as printed in the README
];
}
There is normally no service configuration to write — the value of the bundle is a form type plus (usually) a Twig form-theme block and a data transformer. If the bundle ships a DependencyInjection/ extension, check whether it exposes anything worth configuring (SRID, default widget, precision) before assuming it is plug-and-play.
Where to look first, in this order:
README.md — the field type alias and the expected value type (WKT string vs. a geometry object) are the two facts everything else depends on.Form/Type/*.php — buildForm(), getParent(), getBlockPrefix()/getName(), and which data transformer it attaches. This tells you the actual contract in under five minutes, and it is more reliable than the README.Resources/views/Form/*.html.twig — whether the widget is a plain <input>/<textarea> or a JS map.composer.json — PHP constraint, Symfony component constraints, and which geometry library (looptribe/geo or similar) it expects.First use case: adding a "location" field to an entity form and persisting it.
// src/AppBundle/Form/PlaceType.php
$builder
->add('name')
->add('location', SpatialType::class, [ // alias from the README, e.g. 'spatial'
'required' => false,
'label' => 'Coordinates',
]);
Wire the entity column as string/text (WKT or GeoJSON) for a first proof of concept. Do not start by wiring a Doctrine spatial column — that drags in a second, equally stale dependency and doubles the failure surface.
String-in, string-out (the low-risk pattern). Use the type as a validated text field: the user pastes or enters WKT/GeoJSON, the form maps it to a string property, and you normalise on persist. This works even if the JS widget is broken and gives you a clean upgrade path later.
Data transformer for a domain object. The moment you want $place->getLocation() to return a Point rather than a string, add your own transformer instead of relying on whatever the bundle ships:
$builder->add('location', SpatialType::class)
->addModelTransformer(new PointToStringTransformer($reader, $writer));
Keep the transformer dumb — parse to/from one canonical format (WKT is the safest bet; it is unambiguous about SRID and has mature parsers). Reverse-transform failures into TransformationFailedException, not \Exception, so the form shows a field error instead of a 500.
Compound field with a map widget. The usual architecture is: hidden/text input holds the serialised geometry, a JS map (Leaflet/Google) writes into it on change, and the bundle's form theme renders the container. If the bundle does not ship the JS, add it in your own Resources/views/Form/fields.html.twig override rather than editing vendor/ — you will need that override anyway to survive an update or a fork.
Validation belongs to you. Add a @Assert\Callback or a custom constraint on the entity that parses the value and rejects bad geometry. Form types validate shape, not semantics; an "empty polygon with three points" will happily pass a NotBlank.
Symfony form tests as your safety net. Because there is no upstream CI, write a TypeTestCase that submits a known WKT string and asserts the model value. That test is what tells you when a PHP or Symfony upgrade breaks the bundle:
$form = $this->factory->create(SpatialType::class);
$form->submit('POINT(2.35 48.85)');
$this->assertTrue($form->isSynchronized());
Reuse across forms, not inheritance. The bundle is small; if you need behaviour it lacks (SRID selection, multiple geometries), compose a new type with getParent() returning the bundle's type. Do not subclass — these bundles change buildForm() signatures between patch releases.
getName() vs. getBlockPrefix(), AppKernel removal, no autowiring-friendly service definitions). Budget for a fork, not a composer require.POINT(lng lat) vs [lng, lat]), and so do Google Maps and Leaflet. Pick one order, document it at the transformer, and unit-test a known landmark (e.g. the Eiffel Tower) so swaps fail loudly.ST_GeomFromText(..., 4326), a tiling service — will quietly misbehave if the assumption drifts.float casts can move a coordinate by a metre. Keep the persisted representation as the original string until you have a reason not to.try/catch and convert to TransformationFailedException. Raw InvalidArgumentException from a WKT parser during submit() produces a 500 on user input.php app/console debug:container --tag=form.type (Symfony 2.8+) and check the bundle's Resources/config/ XML/YAML — a missing service definition is the usual cause, often because the bundle class name in AppKernel is wrong.null after a valid submit, the data transformer is the culprit, not the widget.Rule object, and take the WKT parsing library rather than the bundle.How can I help you explore Laravel packages today?