Skip to content

Separating HTML and JS, config API KEY and Improved user experience in search field #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
28 changes: 28 additions & 0 deletions DependencyInjection/Compiler/FormPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Oh\GoogleMapFormTypeBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Add a new twig.form.resources
*
* @author Olivier Chauvel <[email protected]>
*/
class FormPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$resources = $container->getParameter('twig.form.resources');

foreach (array('div', 'jquery') as $template) {
$resources[] = 'OhGoogleMapFormTypeBundle:Form:' . $template . '_layout.html.twig';
}

$container->setParameter('twig.form.resources', $resources);
}
}
9 changes: 6 additions & 3 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ public function getConfigTreeBuilder()

$rootNode = $treeBuilder->root('oh_google_map_form_type');

// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
$rootNode
->children()
->scalarNode('api_key')
->isRequired()
->end()
->end();

return $treeBuilder;
}
Expand Down
5 changes: 4 additions & 1 deletion DependencyInjection/OhGoogleMapFormTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public function load(array $configs, ContainerBuilder $container)
$config = $this->processConfiguration($configuration, $configs);

$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
$loader->load('twig.xml');
$loader->load('services.xml');

$container->setParameter('api_key', $config['api_key']);
}
}
26 changes: 14 additions & 12 deletions Form/Type/GoogleMapType.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,20 @@ public function buildForm(FormBuilderInterface $builder, array $options)
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'type' => 'text', // the types to render the lat and lng fields as
'options' => array(), // the options for both the fields
'lat_options' => array(), // the options for just the lat field
'lng_options' => array(), // the options for just the lng field
'lat_name' => 'lat', // the name of the lat field
'lng_name' => 'lng', // the name of the lng field
'type' => 'text', // the types to render the lat and lng fields as
'options' => array(), // the options for both the fields
'lat_options' => array(), // the options for just the lat field
'lng_options' => array(), // the options for just the lng field
'lat_name' => 'lat', // the name of the lat field
'lng_name' => 'lng', // the name of the lng field
'error_bubbling' => false,
'map_width' => 300, // the width of the map
'map_height' => 300, // the height of the map
'default_lat' => 51.5, // the starting position on the map
'default_lng' => -0.1245, // the starting position on the map
'include_jquery' => false, // jquery needs to be included above the field (ie not at the bottom of the page)
'include_gmaps_js'=>true // is this the best place to include the google maps javascript?
'map_width' => '100%', // the width of the map, you must include units (ie, px or %)
'map_height' => '300px', // the height of the map, you must include units (ie, px or %)
'default_lat' => 51.5, // the starting position on the map
'default_lng' => -0.1245, // the starting position on the map
'include_jquery' => false, // jquery needs to be included above the field (ie not at the bottom of the page)
'include_gmaps_js'=>true, // is this the best place to include the google maps javascript?
'js_inside_html' => false // if you don't have the possibility to include form_javascript(), for example, in Sonata Admin Class, set true this option
));
}

Expand All @@ -59,6 +60,7 @@ public function buildView(FormView $view, FormInterface $form, array $options)
$view->vars['default_lng'] = $options['default_lng'];
$view->vars['include_jquery'] = $options['include_jquery'];
$view->vars['include_gmaps_js'] = $options['include_gmaps_js'];
$view->vars['js_inside_html'] = $options['js_inside_html'];
}

public function getParent()
Expand Down
14 changes: 12 additions & 2 deletions OhGoogleMapFormTypeBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@
namespace Oh\GoogleMapFormTypeBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Oh\GoogleMapFormTypeBundle\DependencyInjection\Compiler\FormPass;

class OhGoogleMapFormTypeBundle extends Bundle {

/**
* {@inheritdoc}
*/
public function build(ContainerBuilder $container) {
parent::build($container);
$container->addCompilerPass(new FormPass());
}

class OhGoogleMapFormTypeBundle extends Bundle
{
}
166 changes: 106 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ This bundle is compatible with Symfony 2.1. Add the following to your `composer.

"oh/google-map-form-type-bundle": "dev-master"

or execute:

php composer.phar require oh/google-map-form-type-bundle

Register the bundle in your `app/AppKernel.php`:

```php
Expand All @@ -30,85 +34,132 @@ Add OhGoogleMapFormTypeBundle to assetic
assetic:
bundles: [ 'OhGoogleMapFormTypeBundle' ]
```
You might config your [Google Maps Api Key](https://developers.google.com/maps/documentation/javascript/get-api-key).

```yaml
# app/config/config.yml
oh_google_map_form_type:
api_key: "my-key"
```

After this, you have to install assets:

php app/console assets:install --symlink

Usage
------------
-------

This bundle contains a new FormType called GoogleMapType which can be used in your forms like so:

$builder->add('latlng', 'oh_google_maps');

On your model you will have to process the latitude and longitude array
``` php
// Your model eg, src/My/Location/Entity/MyLocation.php
use Symfony\Component\Validator\Constraints as Assert;
use Oh\GoogleMapFormTypeBundle\Validator\Constraints as OhAssert;

// Your model eg, src/My/Location/Entity/MyLocation.php
use Symfony\Component\Validator\Constraints as Assert;
use Oh\GoogleMapFormTypeBundle\Validator\Constraints as OhAssert;
class MyLocation
{
// ... include your lat and lng fields here

class MyLocation
public function setLatLng($latlng)
{
// ... include your lat and lng fields here

public function setLatLng($latlng)
{
$this->setLat($latlng['lat']);
$this->setLng($latlng['lng']);
return $this;
}

/**
* @Assert\NotBlank()
* @OhAssert\LatLng()
*/
public function getLatLng()
{
return array('lat'=>$this->getLat(),'lng'=>$this->getLng());
}
$this->setLat($latlng['lat']);
$this->setLng($latlng['lng']);
return $this;
}

/**
* @Assert\NotBlank()
* @OhAssert\LatLng()
*/
public function getLatLng()
{
return array('lat'=>$this->getLat(),'lng'=>$this->getLng());
}

Include the twig template for the layout. It's generally a good idea to overwrite the form template in your own twig template
}
```

# your config.yml
twig:
form:
resources:
# This uses the default - you can put your own one here
- 'OhGoogleMapFormTypeBundle:Form:fields.html.twig'
**Add form_javascript** this principle is to separate the javascript and html. This allows better integration of web pages. Inspired by its use in [DatetimepickerBundle](https://github.com/stephanecollot/DatetimepickerBundle)

If you are intending to override some of the elements in the template then you can do so by extending the default `google_maps.html.twig`. This example adds a callback to the javascript when a new map position is selected.
### Example:

{# your template which is inluded in the config.yml (above)
eg src/My/Location/Resources/views/Form/fields.html.twig #}
{% extends "OhGoogleMapFormTypeBundle:Form:google_maps.html.twig" %}
{% block oh_google_maps_callback %}
<script type="text/javascript">
var oh_google_maps_callback = function(location, gmap){
// logs to the console your new latitude
console.log('Your new latitude is: '+location.lat());
}
</script>
{% endblock %}
``` twig
{% block javascripts %}
<script src="{{ asset('js/other.js') }}"></script>

{{ form_javascript(form) }}
{% endblock %}

{% block body %}
<form action="{{ path('my_route_form') }}" type="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}

<input type="submit" />
</form>
{% endblock %}
```

Options
-------

There are a number of options, mostly self-explanatory

array(
'type' => 'text', // the types to render the lat and lng fields as
'options' => array(), // the options for both the fields
'lat_options' => array(), // the options for just the lat field
'lng_options' => array(), // the options for just the lng field
'lat_name' => 'lat', // the name of the lat field
'lng_name' => 'lng', // the name of the lng field
'map_width' => 300, // the width of the map
'map_height' => 300, // the height of the map
'default_lat' => 51.5, // the starting position on the map
'default_lng' => -0.1245, // the starting position on the map
'include_jquery' => false, // jquery needs to be included above the field (ie not at the bottom of the page)
'include_gmaps_js'=>true // is this the best place to include the google maps javascript?
)
``` php
array(
'type' => 'text', // the types to render the lat and lng fields as
'options' => array(), // the options for both the fields
'lat_options' => array(), // the options for just the lat field
'lng_options' => array(), // the options for just the lng field
'lat_name' => 'lat', // the name of the lat field
'lng_name' => 'lng', // the name of the lng field
'map_width' => '100%', // the width of the map, you must include units (ie, px or %)
'map_height' => '300px', // the height of the map, you must include units (ie, px or %)
'default_lat' => 51.5, // the starting position on the map
'default_lng' => -0.1245, // the starting position on the map
'include_jquery' => false, // jquery needs to be included above the field (ie not at the bottom of the page)
'include_gmaps_js' => true, // is this the best place to include the google maps javascript?
'js_inside_html' => false // if you don't have the possibility to include form_javascript(), ie, in Sonata Admin Class, set true this option
)
```

### Twig customization:
You have 2 twig templates for the layout, for HTML and for JQUERY (js). It's generally a good idea to overwrite the form templates, especially HTML, in your own twig template. Place them on folder: `app/Resources/OhGoogleMapFormTypeBundle/views/Form/`

- HTML: `vendor/oh/google-map-form-type-bundle/Oh/GoogleMapFormTypeBundle/Resources/views/Form/div_layout.html.twig`
- JQUERY (js): `vendor/oh/google-map-form-type-bundle/Oh/GoogleMapFormTypeBundle/Resources/views/Form/jquery_layout.html.twig`

If you are intending to override some of the elements in the template JQUERY (js), then you can do so by extending the default `jquery_layout.html.twig`. This example adds a callback to the javascript when a new map position is selected.

``` twig
{# your template which is inluded in app/Resources/OhGoogleMapFormTypeBundle/views/Form/ folder (above) #}
{% extends "OhGoogleMapFormTypeBundle:Form:jquery_layout.html.twig" %}
{% block oh_google_maps_callback %}
<script type="text/javascript">
var oh_google_maps_callback = function(location, gmap){
// logs to the console your new latitude
console.log('Your new latitude is: '+location.lat());
}
</script>
{% endblock %}
```

If you have several forms with `oh_google_maps` types, you can override the templates in each one of them with `{% form_theme form 'AppBundle:Forms:your-twig.html.twig' %}` like this:

``` twig
{% extends 'form_div_layout.html.twig' %}

{% block oh_google_maps_html %}
<div id="{{ id }}_container">
<input type="text" id="{{ id }}_input" /><button id="{{ id }}_search_button" class="btn">Search</button><br /><a href="#" id="{{ id }}_current_position">MY CUSTOM TEXT FOR CURRENT LOCATION</a>
<div id="{{ id }}_map_canvas" class="gmap" style="width: {{ map_width }}; height: {{ map_height }}"></div>
<div id="{{ id }}_error"></div>
</div>
{% endblock %}
```


Screenshots
-------
Expand All @@ -118,11 +169,6 @@ Screenshots
[Search locations](https://www.dropbox.com/s/qdft149ggyfil0p/location-form-search.png)
[LatLng validation](https://www.dropbox.com/s/k0xqku5q2gv2nlo/location-form-validation.png)

Known problems
-------

Because the form type template includes javascript, there's not yet a way to bunch it all together at the very bottom of the page, so it is included at the bottom of the field. This means that jquery and the javascript plugin in Resources/public/js needs to be included before the field. I'm not sure of a way around this, but I think it's going to be addressed in a later version of the form framework.

Credits
-------

Expand Down
Empty file removed Resources/config/config.yml
Empty file.
9 changes: 9 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@

<parameters>
<parameter key="form.type.oh_google_maps.class">Oh\GoogleMapFormTypeBundle\Form\Type\GoogleMapType</parameter>
<parameter key="twig.extension.globals_extension.class">Oh\GoogleMapFormTypeBundle\Twig\Extension\GlobalsExtension</parameter>
<parameter key="type.oh_google_maps.form.options" type="collection" />
</parameters>

<services>
<!-- oh_google_maps form type -->
<service id="form.type.oh_google_maps" class="%form.type.oh_google_maps.class%">
<tag name="form.type" alias="oh_google_maps" />
<argument>%type.oh_google_maps.form.options%</argument>
</service>

<!-- variables globales para utilizar en plantillas Twig -->
<service id="twig.extension.globals_extension" class="%twig.extension.globals_extension.class%">
<tag name="twig.extension" />
<argument>%api_key%</argument>
</service>
</services>
</container>
14 changes: 14 additions & 0 deletions Resources/config/twig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="oh_googlemapformtype.twig.extension.form" class="Oh\GoogleMapFormTypeBundle\Twig\Extension\FormExtension">
<tag name="twig.extension" />
<argument type="service" id="twig.form.renderer" />
</service>
</services>

</container>
20 changes: 20 additions & 0 deletions Resources/views/Form/div_layout.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% block oh_google_maps_widget %}
<div {{ block('widget_container_attributes') }}>
{% block oh_google_maps_html %}
<div id="{{ id }}_container">
<input type="text" id="{{ id }}_input" /><button id="{{ id }}_search_button" class="btn">Search</button><br /><a href="#" id="{{ id }}_current_position">Current location</a>
<div id="{{ id }}_map_canvas" class="gmap" style="width: {{ map_width }}; height: {{ map_height }}"></div>
<div id="{{ id }}_error"></div>
</div>
{% endblock %}
{% block oh_google_maps_fields %}
{% for child in form %}
{{ form_row(child) }}
{% endfor %}
{% endblock %}
</div>

{% if js_inside_html %}
{% include "OhGoogleMapFormTypeBundle:Form:jquery_layout.html.twig" %}
{% endif %}
{% endblock %}
1 change: 0 additions & 1 deletion Resources/views/Form/fields.html.twig

This file was deleted.

Loading