Developers

License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Features

Allows linking of array lists with models list or between models
(unlimited levels),

Doctrine and Propel support,

Easy to customize and extend.

Instalation

Install the plugin

$ php symfony plugin:install sfDependentSelectPlugin

Publish javascript

$ php symfony plugin:publish-assets

Clean the cache

$ php symfony cache:clear

Enable the plugin in the project settings
(config/ProjectConfiguration.class.php)

$this->enablePlugins(..., 'sfDependentSelectPlugin');

Enable the module sfDependentSelectAuto if you want to use automated
ajax (apps/{yourapp}/config/settings.yml)

all:
.settings:
...
enabled_modules: [sfDependentSelectAuto]

Dependencies

jQuery: using AJAX only. Must add by yourself in case you need this
functionality. Version >= 1.4.

Content

Widgets

sfWidgetFormArrayDependentSelect: displays a select using an array as a
database,

sfWidgetFormDoctrineDependentSelect: uses Doctrine as a database,

sfWidgetFormPropelDependentSelect: uses Propel as a database.

Actions

sfActionsDependentSelect: implements an "_ajax" action that returns the
values required for each request.

Modules

sfDependentSelectAuto: is the default module used by widgets,
simply extends to sfActionsDependentSelect.

Using examples

The examples are for Doctrine, but you can do it the same way for propel
using the sfWidgetFormPropelDependentSelect class.

Country, state, city

A typical case where you have countries, states and cities related. When
creating a dependency on the city from another entity, it creates a big problem
when displaying the form, and displays all the cities of all provinces in all
countries mixed.

Ok, it should work with that. It displays select "independent" for countries,
according to the value of the provinces it will be shown. Likewise for the
cities by province.

Note that the above example does not remote calls (AJAX), just load the selects
with the different datasets and is showing according to the settings in which
select depends. So you'll notice the speed in the operation, ideal for
small / medium datasets.

When levels are deep and large quantities of choices, you might want to use AJAX.
Next is how to modify the previous example to easily add this feature.

ThatÂ´s all. Remote calls are handled by a special module called
sfDependentSelectAuto that returns the values respecting all the options set as
if it were locally.

Below are explained in detail the options available and how the automatic
module works so you can extend and return your own data.

Before the explanation. Another example.

Products and services

Be used as an example a case of sales of products and services that extend to
an item. When loading the details of the invoice, select the type (product or
service) and then display them in another select.

cache = true: Specifies whether to use the cache of values from a select
once it was loaded remotely (to avoid extra requests),

url = sfDependentSelectAuto/_ajax: URL where you will make remote calls
to load the selects. The value should not be of the "module / action' or path
name (the method of sfWebController genUrl can be used to genre),

params = array(): Additional parameters to send to the remote call,

source_class = null: The class that is used as data source.
(See later in customizing).

source_params = array(): Parameters sent to the data source.

sfWidgetFormArrayDependentSelect > sfWidgetFormDependentSelect

callable = null: Function or method to be called in order to request
the array. In case of a static method, indicate: array ('class', 'method').
Do not use instances of classes such as $ this, it will not work on remote
calls.

It is important to know that when the action calls the {table|peer} method, the
referent value is set as a parameter, in order to be able to filter your data
according to the select value wich it depends.

Creating you own data source or widget

If you want to use another data source (if not using an ORM or just an RSS feed),
you can easily create a custom. This way you can take advantage of the automation
of both local and remote calls and link with other dependent selects using other
sources.

In this example we have extended to sfDependentSelectObjectSource it makes
easy to work with objects, but if you want create an RSS feed, echo on how
sfWidgetFormArrayDependentSelect does.

You can also create your own widget to always use this source or add other
functionality, look at sfWidgetFormDependentSelect sfDependentSelectSource
classes to learn how to create your own.

Extending you module

Another way is to extend your module to sfActionsDependentSelect and define
methods for getValuesFor {name} and getRefValueFor {name}. Do not forget to
specify your action in the 'url' of the widget.

Let's look at the example of countries, if we return the provinces in this way:

apps/tuapp/modules/tumodulo/actions/actions.class.php:

class tuModuloActions extends sfActionsDependentSelect
{
protected function getValuesForPersonaProvincia($request, $source)
{
// in this case we work with objects, but you can do it anyway
// always returning an array with an id as a key
// and the text as the array values.
$valores = array();
$provincias = ProvinciaTable::getInstance()->createQuery('p')
->where('p.pais_id = ? and p.es_productora = true')
->execute($request->getParameter('_ds_ref'));
// the _ds_ref parameter contains the select value wich it depends
// in this case will be the value for pais.id
foreach ($provincias as $provincia) {
$valores[$provincia->getId()] = $provincia->getNombre();
}
return $valores;
}
protected function getRefValueForPersonaProvincia($request, $source)
{
// this method is used in order to "rebuild" the selects chain
// depending of inverse order. It means Only if you have
// the province value, you have to know wich country it belong to
// in order to select it from the country select.
// in this case the value of _ds_ref is the actual value of the select
// of provinces (provincia.id) and we have to return wich country
// it belongs (provincia.pais_id)
$provincia = ProvinciaTable::getInstance()->find($request->getParameter('_ds_ref'));
return $provincia->getPaisId();
}
}

Note that each method also receives as a parameter the data source in case you
need.

You can check sfActionsDependentSelect class to learn more about how to extend
the functionality in your module.

If you can not extend your module class and definitely any of the forms offered
above meet your needs, you must implement an action on your module that contains
all the functionality as the 'ajax' action _sfActionsDependentSelect class
does. With Firebug you can see the parameters sent via POST.

About javascript code

By default the plugin is included in both versions of the script, normal and
minimized. Always minimized charged unless you change your settings:

apps/tuapp/config/app.yml:

dev:
app:
...
sfDependentSelectPlugin:
js: normal

You can also set 'false' to not load the script. The value to show minimized
is 'minimized'.

Â¿Sugestions?

Unfortunately I do not speak English and have developed most of the code trying
to use English terminology with the help of automatic translators. I apologize
for inconsistencies found and I preciate be informed in order to be corrected.

You can write to my personal email for any suggestions or concerns.
I gladly will improve the aspects if necessary