diff --git a/DependencyInjection/Compiler/FormPass.php b/DependencyInjection/Compiler/FormPass.php new file mode 100644 index 0000000..b8ab9fc --- /dev/null +++ b/DependencyInjection/Compiler/FormPass.php @@ -0,0 +1,28 @@ + + */ +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); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 9a273b6..d85ad06 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -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; } diff --git a/DependencyInjection/OhGoogleMapFormTypeExtension.php b/DependencyInjection/OhGoogleMapFormTypeExtension.php index 25282f4..b973d31 100644 --- a/DependencyInjection/OhGoogleMapFormTypeExtension.php +++ b/DependencyInjection/OhGoogleMapFormTypeExtension.php @@ -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']); } } diff --git a/Form/Type/GoogleMapType.php b/Form/Type/GoogleMapType.php index 25cbe22..dd16c96 100755 --- a/Form/Type/GoogleMapType.php +++ b/Form/Type/GoogleMapType.php @@ -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 )); } @@ -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() diff --git a/OhGoogleMapFormTypeBundle.php b/OhGoogleMapFormTypeBundle.php index ff4f2bb..d18d89a 100755 --- a/OhGoogleMapFormTypeBundle.php +++ b/OhGoogleMapFormTypeBundle.php @@ -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 -{ } diff --git a/README.md b/README.md index 28c09ac..ad4a440 100755 --- a/README.md +++ b/README.md @@ -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 @@ -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 %} - - {% endblock %} +``` twig +{% block javascripts %} + + + {{ form_javascript(form) }} +{% endblock %} +{% block body %} +
+ {{ form_widget(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 %} + +{% 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 %} +
+
MY CUSTOM TEXT FOR CURRENT LOCATION +
+
+
+{% endblock %} +``` + Screenshots ------- @@ -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 ------- diff --git a/Resources/config/config.yml b/Resources/config/config.yml deleted file mode 100755 index e69de29..0000000 diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 6cac9f7..aa6547a 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -6,12 +6,21 @@ Oh\GoogleMapFormTypeBundle\Form\Type\GoogleMapType + Oh\GoogleMapFormTypeBundle\Twig\Extension\GlobalsExtension + + %type.oh_google_maps.form.options% + + + + + + %api_key% \ No newline at end of file diff --git a/Resources/config/twig.xml b/Resources/config/twig.xml new file mode 100644 index 0000000..ca917c5 --- /dev/null +++ b/Resources/config/twig.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Resources/views/Form/div_layout.html.twig b/Resources/views/Form/div_layout.html.twig new file mode 100644 index 0000000..40c04f1 --- /dev/null +++ b/Resources/views/Form/div_layout.html.twig @@ -0,0 +1,20 @@ +{% block oh_google_maps_widget %} +
+ {% block oh_google_maps_html %} +
+
Current location +
+
+
+ {% endblock %} + {% block oh_google_maps_fields %} + {% for child in form %} + {{ form_row(child) }} + {% endfor %} + {% endblock %} +
+ + {% if js_inside_html %} + {% include "OhGoogleMapFormTypeBundle:Form:jquery_layout.html.twig" %} + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig deleted file mode 100755 index 76523b8..0000000 --- a/Resources/views/Form/fields.html.twig +++ /dev/null @@ -1 +0,0 @@ -{% extends "OhGoogleMapFormTypeBundle:Form:google_maps.html.twig" %} \ No newline at end of file diff --git a/Resources/views/Form/google_maps.html.twig b/Resources/views/Form/google_maps.html.twig deleted file mode 100755 index b4df551..0000000 --- a/Resources/views/Form/google_maps.html.twig +++ /dev/null @@ -1,56 +0,0 @@ -{% block oh_google_maps_widget %} -
- {% block oh_google_maps_html %} -
-
Current location -
-
-
- {% endblock %} - {% block oh_google_maps_fields %} - {% for child in form %} - {{ form_row(child) }} - {% endfor %} - {% endblock %} - {% block oh_google_maps_javascripts %} - {% if include_jquery %} - - {% endif %} - {% if include_gmaps_js %} - - {% endif %} - {% javascripts - '@OhGoogleMapFormTypeBundle/Resources/public/js/jquery.ohgooglemaps.js' - %} - - {% endjavascripts %} - {% endblock %} - {% block oh_google_maps_javascript %} - {% block oh_google_maps_callback %} - - {% endblock %} - - {% endblock %} -
-{% endblock %} diff --git a/Resources/views/Form/jquery_layout.html.twig b/Resources/views/Form/jquery_layout.html.twig new file mode 100644 index 0000000..204327f --- /dev/null +++ b/Resources/views/Form/jquery_layout.html.twig @@ -0,0 +1,61 @@ +{% block form_javascript %} + {% spaceless %} + {% for child in form %} + {{ form_javascript(child) }} + {% endfor %} + {% endspaceless %} +{% endblock form_javascript %} + +{% block field_javascript "" %} + +{% block button_javascript "" %} + +{% block oh_google_maps_javascript %} + + {% block oh_google_maps_javascripts %} + {% if include_jquery %} + + {% endif %} + {% if include_gmaps_js %} + + {% endif %} + {% javascripts + '@OhGoogleMapFormTypeBundle/Resources/public/js/jquery.ohgooglemaps.js' + %} + + {% endjavascripts %} + {% endblock %} + + + {% block oh_google_maps_callback %} + + {% endblock %} +{% endblock %} diff --git a/Twig/Extension/FormExtension.php b/Twig/Extension/FormExtension.php new file mode 100644 index 0000000..8bbd38a --- /dev/null +++ b/Twig/Extension/FormExtension.php @@ -0,0 +1,61 @@ + + */ +class FormExtension extends \Twig_Extension +{ + /** + * This property is public so that it can be accessed directly from compiled + * templates without having to call a getter, which slightly decreases performance. + * + * @var \Symfony\Component\Form\FormRendererInterface + */ + public $renderer; + + public function __construct(TwigRendererInterface $renderer) + { + $this->renderer = $renderer; + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('form_javascript', array($this, 'renderJavascript'), array('is_safe' => array('html'))) + ); + } + + /** + * Render Function Form Javascript + * + * @param FormView $view + * @param bool $prototype + * + * @return string + */ + public function renderJavascript(FormView $view, $prototype = false) + { + $block = $prototype ? 'javascript_prototype' : 'javascript'; + + return $this->renderer->searchAndRenderBlock($view, $block); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oh.twig.extension.form'; + } +} + diff --git a/Twig/Extension/GlobalsExtension.php b/Twig/Extension/GlobalsExtension.php new file mode 100644 index 0000000..8621eed --- /dev/null +++ b/Twig/Extension/GlobalsExtension.php @@ -0,0 +1,33 @@ + + */ +class GlobalsExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface +{ + private $apiKey; + + /** + * @param string $apiKey + */ + public function __construct($apiKey) + { + $this->apiKey = $apiKey; + } + + public function getGlobals() + { + return array( + 'apiKey' => $this->apiKey, + ); + } + + public function getName() + { + return 'oh.twig.extension.globals'; + } +}