Adapts advanced search on addresses to our new geocoding engine (gmaps v3).
authorStéphane Jacob <sj@m4x.org>
Fri, 6 May 2011 14:04:38 +0000 (16:04 +0200)
committerStéphane Jacob <sj@m4x.org>
Tue, 10 May 2011 15:44:41 +0000 (17:44 +0200)
Only search on localities and countries works for now.

Signed-off-by: Stéphane Jacob <sj@m4x.org>
classes/direnum.php
classes/profile.php
classes/userfilter.php
classes/userfilter/conditions.inc.php
include/profilefields.inc.php
include/ufbuilder.inc.php
templates/search/adv.form.tpl

index a616061..2f353ae 100644 (file)
@@ -44,11 +44,13 @@ class DirEnum
     const ORIGINCORPS    = 'origincorps';
     const CORPSRANKS     = 'corpsranks';
 
-    const NATIONALITIES  = 'nationalities';
-    const COUNTRIES      = 'countries';
-    const ADMINAREAS     = 'adminareas';
-    const SUBADMINAREAS  = 'subadminareas';
-    const LOCALITIES     = 'localities';
+    const NATIONALITIES       = 'nationalities';
+    const SUBLOCALITIES       = 'sublocalities';
+    const LOCALITIES          = 'localities';
+    const ADMNISTRATIVEAREAS3 = 'admnistrativeareas3';
+    const ADMNISTRATIVEAREAS2 = 'admnistrativeareas2';
+    const ADMNISTRATIVEAREAS1 = 'admnistrativeareas1';
+    const COUNTRIES           = 'countries';
 
     const COMPANIES      = 'companies';
     const JOBDESCRIPTION = 'jobdescription';
@@ -590,56 +592,49 @@ class DE_Nationalities extends DirEnumeration
 }
 // }}}
 
-// {{{ class DE_Countries
-class DE_Countries extends DirEnumeration
+// {{{ class DE_AddressesComponents
+class DE_AddressesComponents extends DirEnumeration
 {
-    protected $idfield   = 'geoloc_countries.iso_3166_1_a2';
-    protected $valfield  = 'geoloc_countries.country';
-    protected $valfield2 = 'geoloc_countries.countryEn';
-    protected $from      = 'geoloc_countries';
+    protected $idfield   = 'profile_addresses_components_enum.short_name';
+    protected $valfield  = 'profile_addresses_components_enum.long_name';
+    protected $from      = 'profile_addresses_components_enum';
 
-    protected $ac_join   = 'INNER JOIN profile_addresses ON (geoloc_countries.iso_3166_1_a2 = profile_addresses.countryId)';
-    protected $ac_unique = 'profile_addresses.pid';
-    protected $ac_where  = 'profile_addresses.type = \'home\'';
+    protected $ac_join   = 'INNER JOIN profile_addresses_components ON (profile_addresses_components.component_id = profile_addresses_components_enum.id)';
+    protected $ac_unique = 'profile_addresses_components.pid';
+    protected $ac_where  = 'profile_addresses_components.type = \'home\'';
 }
 // }}}
-
-// {{{ class DE_AdminAreas
-class DE_AdminAreas extends DE_WithSuboption
+// {{{ class DE_AddressesComponents extensions
+class DE_Countries extends DE_AddressesComponents
 {
-    protected $idfield   = 'geoloc_administrativeareas.id';
-    protected $optfield  = 'geoloc_administrativeareas.country';
-    protected $valfield  = 'geoloc_administrativeareas.name';
-    protected $from      = 'geoloc_administrativeareas';
+    protected $where = 'WHERE  FIND_IN_SET(\'country\', profile_addresses_components_enum.types)';
+}
 
-    protected $ac_join   = 'INNER JOIN profile_addresses ON (profile_addresses.administrativeAreaId = geoloc_administrativeareas.id)';
-    protected $ac_unique = 'profile_addresses.pid';
+class DE_Admnistrativeareas1 extends DE_AddressesComponents
+{
+    protected $where = 'WHERE  FIND_IN_SET(\'admnistrativeareas1\', profile_addresses_components_enum.types)';
 }
-// }}}
 
-// {{{ class DE_SubAdminAreas
-class DE_SubAdminAreas extends DE_WithSuboption
+class DE_Admnistrativeareas2 extends DE_AddressesComponents
 {
-    protected $idfield   = 'geoloc_subadministrativeareas.id';
-    protected $optfield  = 'geoloc_subadministrativeareas.administrativearea';
-    protected $valfield  = 'geoloc_subadministrativeareas.name';
-    protected $from      = 'geoloc_subadministrativeareas';
+    protected $where = 'WHERE  FIND_IN_SET(\'admnistrativeareas2\', profile_addresses_components_enum.types)';
+}
 
-    protected $ac_join   = 'INNER JOIN profile_addresses ON (profile_addresses.subadministrativeAreaId = geoloc_subadministrativeareas.id)';
-    protected $ac_unique = 'profile_addresses.pid';
+class DE_Admnistrativeareas3 extends DE_AddressesComponents
+{
+    protected $where = 'WHERE  FIND_IN_SET(\'admnistrativeareas3\', profile_addresses_components_enum.types)';
 }
-// }}}
 
-// {{{ class DE_Localities
-class DE_Localities extends DirEnumeration
+class DE_Localities extends DE_AddressesComponents
 {
-    protected $idfield   = 'geoloc_localities.id';
-    protected $valfield  = 'geoloc_localities.name';
-    protected $from      = 'geoloc_localities';
+    protected $where = 'WHERE  FIND_IN_SET(\'localities\', profile_addresses_components_enum.types)';
+}
 
-    protected $ac_join   = 'INNER JOIN profile_addresses ON (profile_addresses.localityID = geoloc_localities.id)';
-    protected $ac_unique = 'profile_addresses.pid';
+class DE_Sublocalities extends DE_AddressesComponents
+{
+    protected $where = 'WHERE  FIND_IN_SET(\'sublocalities\', profile_addresses_components_enum.types)';
 }
+
 // }}}
 
 /** JOBS
index 5ecfca7..cf6bcd0 100644 (file)
@@ -397,15 +397,15 @@ class Profile implements PlExportable
     public function nationalities()
     {
         $nats = array();
-        $countries = DirEnum::getOptions(DirEnum::COUNTRIES);
+        $nationalities = DirEnum::getOptions(DirEnum::NATIONALITIES);
         if ($this->nationality1) {
-            $nats[$this->nationality1] = $countries[$this->nationality1];
+            $nats[$this->nationality1] = $nationalities[$this->nationality1];
         }
         if ($this->nationality2) {
-            $nats[$this->nationality2] = $countries[$this->nationality2];
+            $nats[$this->nationality2] = $nationalities[$this->nationality2];
         }
         if ($this->nationality3) {
-            $nats[$this->nationality3] = $countries[$this->nationality3];
+            $nats[$this->nationality3] = $nationalities[$this->nationality3];
         }
         return $nats;
     }
index 9dd25c6..b4bf316 100644 (file)
@@ -993,44 +993,28 @@ class UserFilter extends PlFilter
 
     /** ADDRESSES
      */
-    private $with_pa = false;
-    public function addAddressFilter()
+    private $types = array();
+    public function addAddressFilter($type)
     {
         $this->requireProfiles();
         $this->with_pa = true;
-        return 'pa';
-    }
-
-    private $with_pac = false;
-    public function addAddressCountryFilter()
-    {
-        $this->requireProfiles();
-        $this->addAddressFilter();
-        $this->with_pac = true;
-        return 'gc';
-    }
 
-    private $with_pal = false;
-    public function addAddressLocalityFilter()
-    {
-        $this->requireProfiles();
-        $this->addAddressFilter();
-        $this->with_pal = true;
-        return 'gl';
+        $sub = '_' . $this->option++;
+        $this->types[$type] = $sub;
+        return $sub;
     }
 
     protected function addressJoins()
     {
         $joins = array();
-        if ($this->with_pa) {
-            $joins['pa'] = PlSqlJoin::left('profile_addresses', '$ME.pid = $PID');
-        }
-        if ($this->with_pac) {
-            $joins['gc'] = PlSqlJoin::left('geoloc_countries', '$ME.iso_3166_1_a2 = pa.countryID');
-        }
-        if ($this->with_pal) {
-            $joins['gl'] = PlSqlJoin::left('geoloc_localities', '$ME.id = pa.localityID');
+        foreach ($this->types as $type => $sub) {
+            $joins['pa' . $sub] = PlSqlJoin::inner('profile_addresses', '$ME.pid = $PID');
+            $joins['pac' . $sub] = PlSqlJoin::inner('profile_addresses_components',
+                                                    '$ME.pid = pa' . $sub . '.pid AND $ME.jobid = pa' . $sub . '.jobid AND $ME.groupid = pa' . $sub . '.groupid AND $ME.type = pa' . $sub . '.type AND $ME.id = pa' . $sub . '.id');
+            $joins['pace' . $sub] = PlSqlJoin::inner('profile_addresses_components_enum',
+                                                     '$ME.id = pac' . $sub . '.component_id AND FIND_IN_SET({?}, $ME.types)', $type);
         }
+
         return $joins;
     }
 
index 54932f9..85d1d03 100644 (file)
@@ -1006,17 +1006,20 @@ class UFC_Email extends UserFilterCondition
 // {{{ class UFC_Address
 abstract class UFC_Address extends UserFilterCondition
 {
-    /** Valid address type ('hq' is reserved for company addresses)
+    /** Valid address type
      */
-    const TYPE_HOME = 1;
-    const TYPE_PRO  = 2;
-    const TYPE_ANY  = 3;
+    const TYPE_HOME     = 1;
+    const TYPE_PRO      = 2;
+    const TYPE_NON_HQ   = 3;
+    const TYPE_HQ       = 4;
+    const TYPE_ANY      = 7;
 
     /** Text for these types
      */
     protected static $typetexts = array(
         self::TYPE_HOME => 'home',
         self::TYPE_PRO  => 'pro',
+        self::TYPE_HQ   => 'hq',
     );
 
     protected $type;
@@ -1061,13 +1064,13 @@ abstract class UFC_Address extends UserFilterCondition
             }
         }
         if (count($types)) {
-            $conds[] = XDB::format($sub . '.type IN {?}', $types);
+            $conds[] = XDB::format('pa' . $sub . '.type IN {?}', $types);
         }
 
         if ($this->flags != self::FLAG_ANY) {
             foreach(self::$flagtexts as $flag => $text) {
                 if ($flag & $this->flags) {
-                    $conds[] = 'FIND_IN_SET(' . XDB::format('{?}', $text) . ', ' . $sub . '.flags)';
+                    $conds[] = 'FIND_IN_SET(' . XDB::format('{?}', $text) . ', pa' . $sub . '.flags)';
                 }
             }
         }
@@ -1076,61 +1079,6 @@ abstract class UFC_Address extends UserFilterCondition
 
 }
 // }}}
-// {{{ class UFC_AddressText
-/** Select users based on their address, using full text search
- * @param $text Text for filter in fulltext search
- * @param $textSearchMode Mode for search (one of XDB::WILDCARD_*)
- * @param $type Filter on address type
- * @param $flags Filter on address flags
- * @param $country Filter on address country
- * @param $locality Filter on address locality
- */
-class UFC_AddressText extends UFC_Address
-{
-
-    private $text;
-    private $textSearchMode;
-
-    public function __construct($text = null, $textSearchMode = XDB::WILDCARD_CONTAINS,
-        $type = null, $flags = self::FLAG_ANY, $country = null, $locality = null)
-    {
-        parent::__construct($type, $flags);
-        $this->text           = $text;
-        $this->textSearchMode = $textSearchMode;
-        $this->country        = $country;
-        $this->locality       = $locality;
-    }
-
-    private function mkMatch($txt)
-    {
-        return XDB::formatWildcards($this->textSearchMode, $txt);
-    }
-
-    public function buildCondition(PlFilter $uf)
-    {
-        $sub = $uf->addAddressFilter();
-        $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub'));
-        if ($this->text != null) {
-            $conds[] = $sub . '.text' . $this->mkMatch($this->text);
-        }
-
-        if ($this->country != null) {
-            $subc = $uf->addAddressCountryFilter();
-            $subconds = array();
-            $subconds[] = $subc . '.country' . $this->mkMatch($this->country);
-            $subconds[] = $subc . '.countryFR' . $this->mkMatch($this->country);
-            $conds[] = implode(' OR ', $subconds);
-        }
-
-        if ($this->locality != null) {
-            $subl = $uf->addAddressLocalityFilter();
-            $conds[] = $subl . '.name' . $this->mkMatch($this->locality);
-        }
-
-        return implode(' AND ', $conds);
-    }
-}
-// }}}
 // {{{ class UFC_AddressField
 /** Filters users based on their address,
  * @param $val Either a code for one of the fields, or an array of such codes
@@ -1138,55 +1086,36 @@ class UFC_AddressText extends UFC_Address
  * @param $type Filter on address type
  * @param $flags Filter on address flags
  */
-class UFC_AddressField extends UFC_Address
+class UFC_AddressComponent extends UFC_Address
 {
-    const FIELD_COUNTRY    = 1;
-    const FIELD_ADMAREA    = 2;
-    const FIELD_SUBADMAREA = 3;
-    const FIELD_LOCALITY   = 4;
-    const FIELD_ZIPCODE    = 5;
+    static $components = array('sublocality', 'locality', 'administrative_area_level_3', 'administrative_area_level_2', 'administrative_area_level_1', 'country');
 
     /** Data of the filter
      */
     private $val;
     private $fieldtype;
+    private $exact;
 
-    public function __construct($val, $fieldtype, $type = null, $flags = self::FLAG_ANY)
+    public function __construct($val, $fieldtype, $exact = true, $type = null, $flags = self::FLAG_ANY)
     {
-        parent::__construct($type, $flags);
+        if (!in_array($fieldtype, self::$components)) {
+            Platal::page()->killError('Invalid address field type: ' . $this->fieldtype);
+        }
 
+        parent::__construct($type, $flags);
         if (!is_array($val)) {
             $val = array($val);
         }
         $this->val       = $val;
         $this->fieldtype = $fieldtype;
+        $this->exact     = $exact;
     }
 
     public function buildCondition(PlFilter $uf)
     {
-        $sub = $uf->addAddressFilter();
-        $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub'));
-
-        switch ($this->fieldtype) {
-        case self::FIELD_COUNTRY:
-            $field = 'countryId';
-            break;
-        case self::FIELD_ADMAREA:
-            $field = 'administrativeAreaId';
-            break;
-        case self::FIELD_SUBADMAREA:
-            $field = 'subAdministrativeAreaId';
-            break;
-        case self::FIELD_LOCALITY:
-            $field = 'localityId';
-            break;
-        case self::FIELD_ZIPCODE:
-            $field = 'postalCode';
-            break;
-        default:
-            Platal::page()->killError('Invalid address field type: ' . $this->fieldtype);
-        }
-        $conds[] = XDB::format($sub . '.' . $field . ' IN {?}', $this->val);
+        $sub = $uf->addAddressFilter($this->fieldtype);
+        $conds = $this->initConds($sub, $uf->getVisibilityCondition('pa' . $sub . '.pub'));
+        $conds[] = XDB::format('pace' . $sub . '.short_name IN {?}', $this->val);
 
         return implode(' AND ', $conds);
     }
index 2de1e6b..8d4ef1b 100644 (file)
@@ -735,8 +735,7 @@ class CompanyList
         }
 
         $it = XDB::iterator('SELECT  pje.id, pje.name, pje.acronym, pje.url,
-                                     pa.flags, pa.text, pa.postalCode, pa.countryId,
-                                     pa.type, pa.pub
+                                     pa.flags, pa.text, pa.type, pa.pub
                                FROM  profile_job_enum AS pje
                           LEFT JOIN  profile_addresses AS pa ON (pje.id = pa.jobid AND pa.type = \'hq\')
                                   ' . $join . '
index e329bbc..40ad2fd 100644 (file)
@@ -347,10 +347,12 @@ class UFB_AdvancedSearch extends UserFilterBuilder
             new UFBF_HasEmailRedirect('has_email_redirect', 'A une redirection active'),
             new UFBF_Dead('alive', 'En vie'),
 
-            new UFBF_Town('city', 'Ville / Code Postal'),
-            new UFBF_Country('countryTxt', 'country', 'Pays'),
-            new UFBF_AdminArea('administrativearea', 'Région'),
-            new UFBF_SubAdminArea('subadministrativearea', 'Département'),
+            new UFBF_AddressIndex('sublocality', 'Arrondissement', 'SUBLOCALITIES'),
+            new UFBF_AddressIndex('administrative_area_level_3', 'Canton', 'ADMNISTRATIVEAREAS3'),
+            new UFBF_AddressIndex('administrative_area_level_2', 'Département', 'ADMNISTRATIVEAREAS2'),
+            new UFBF_AddressIndex('administrative_area_level_1', 'Région', 'ADMNISTRATIVEAREAS1'),
+            new UFBF_AddressMixed('localityTxt', 'locality', 'Ville', 'LOCALITIES'),
+            new UFBF_AddressMixed('countryTxt', 'country', 'Pays', 'COUNTRIES'),
 
             new UFBF_JobCompany('entreprise', 'Entreprise'),
             new UFBF_JobDescription('jobdescription', 'Fonction'),
@@ -1032,69 +1034,16 @@ class UFBF_Dead extends UFBF_Enum
 }
 // }}}
 
-// {{{ class UFBF_Town
-/** Retrieves a town, either from a postal code or a town name
- */
-class UFBF_Town extends UFBF_Text
-{
-    const TYPE_TEXT = 1;
-    const TYPE_ZIP  = 2;
-    const TYPE_ANY  = 3;
-
-    private $type;
-    private $onlycurrentfield;
-
-    public function __construct($envfield, $formtext = '', $type = self::TYPE_ANY, $onlycurrentfield = 'only_current')
-    {
-        $this->type = $type;
-        $this->onlycurrentfield = $onlycurrentfield;
-        parent::__construct($envfield, $formtext, 2, 30);
-    }
-
-    protected function buildUFC(UserFilterBuilder $ufb)
-    {
-        if ($ufb->isOn($this->onlycurrentfield)) {
-            $flags = UFC_Address::FLAG_CURRENT;
-        } else {
-            $flags = UFC_Address::FLAG_ANY;
-        }
-
-        if (preg_match('/[0-9]/', $this->val)) {
-            if ($this->type & self::TYPE_ZIP) {
-                return new UFC_AddressField($this->val, UFC_AddressField::FIELD_ZIPCODE, UFC_Address::TYPE_ANY, $flags);
-            } else {
-                return new PFC_False();
-            }
-        } else {
-            $byname = new UFC_AddressText(null, XDB::WILDCARD_CONTAINS, UFC_Address::TYPE_ANY, $flags, null, $this->val);
-            $byzip  = new UFC_AddressField($this->val, UFC_AddressField::FIELD_ZIPCODE, UFC_Address::TYPE_ANY, $flags);
-            if ($this->type & self::TYPE_ANY) {
-                return new PFC_Or($byname, $byzip);
-            } else if ($this->type & self::TYPE_TEXT) {
-                return $byname;
-            } else {
-                return $byzip;
-            }
-        }
-    }
-
-    public function getEnvFieldNames()
-    {
-        return array($this->envfield, $this->onlycurrentfield);
-    }
-}
-// }}}
-
-// {{{ class UFBF_Country
-class UFBF_Country extends UFBF_Mixed
+// {{{ class UFBF_AddressMixed
+class UFBF_AddressMixed extends UFBF_Mixed
 {
-    protected $direnum = DirEnum::COUNTRIES;
     protected $onlycurrentfield;
 
-    public function __construct($envfieldtext, $envfieldindex, $formtext = '', $onlycurrentfield = 'only_current')
+    public function __construct($envfieldtext, $envfieldindex, $formtext = '', $addressfield, $onlycurrentfield = 'only_current')
     {
         parent::__construct($envfieldtext, $envfieldindex, $formtext);
         $this->onlycurrentfield = $onlycurrentfield;
+        $this->direnum = constant('DirEnum::' . $addressfield);
     }
 
     protected function buildUFC(UserFilterBuilder $ufb)
@@ -1105,7 +1054,7 @@ class UFBF_Country extends UFBF_Mixed
             $flags = UFC_Address::FLAG_ANY;
         }
 
-        return new UFC_AddressField($this->val, UFC_AddressField::FIELD_COUNTRY, UFC_Address::TYPE_ANY, $flags);
+        return new UFC_AddressComponent($this->val, $this->envfieldindex, UFC_Address::TYPE_NON_HQ, $flags);
     }
 
     public function getEnvFieldNames()
@@ -1115,47 +1064,17 @@ class UFBF_Country extends UFBF_Mixed
 }
 // }}}
 
-// {{{ class UFBF_AdminArea
-class UFBF_AdminArea extends UFBF_Index
-{
-    protected $direnum = DirEnum::ADMINAREAS;
-    protected $onlycurrentfield;
-
-    public function __construct($envfield, $formtext = '', $onlycurrentfield = 'only_current')
-    {
-        parent::__construct($envfield, $formtext);
-        $this->onlycurrentfield = $onlycurrentfield;
-    }
-
-
-    protected function buildUFC(UserFilterBuilder $ufb)
-    {
-        if ($ufb->isOn($this->onlycurrentfield)) {
-            $flags = UFC_Address::FLAG_CURRENT;
-        } else {
-            $flags = UFC_Address::FLAG_ANY;
-        }
-
-        return new UFC_AddressField($this->val, UFC_AddressField::FIELD_ADMAREA, UFC_Address::TYPE_ANY, $flags);
-    }
-
-    public function getEnvFieldNames()
-    {
-        return array($this->envfield, $this->onlycurrentfield);
-    }
-}
-// }}}
-
-// {{{ class UFBF_SubAdminArea
-class UFBF_SubAdminArea extends UFBF_Index
+// {{{ class UFBF_AddressIndex
+class UFBF_AddressIndex extends UFBF_Index
 {
-    protected $direnum = DirEnum::SUBADMINAREAS;
+    protected $direnum;
     protected $onlycurrentfield;
 
-    public function __construct($envfield, $formtext = '', $onlycurrentfield = 'only_current')
+    public function __construct($envfield, $formtext = '', $addressfield, $onlycurrentfield = 'only_current')
     {
         parent::__construct($envfield, $formtext);
         $this->onlycurrentfield = $onlycurrentfield;
+        $this->direnum = constant('DirEnum::' . $addressfield);
     }
 
 
@@ -1167,7 +1086,7 @@ class UFBF_SubAdminArea extends UFBF_Index
             $flags = UFC_Address::FLAG_ANY;
         }
 
-        return new UFC_AddressField($this->val, UFC_AddressField::FIELD_SUBADMAREA, UFC_Address::TYPE_ANY, $flags);
+        return new UFC_AddressComponent($this->val, $this->envfield, UFC_Address::TYPE_NON_HQ, $flags);
     }
 
     public function getEnvFieldNames()
index 4d47703..6596881 100644 (file)
@@ -404,8 +404,8 @@ function cleanForm(f) {
       <th colspan="2">Géographie</th>
     </tr>
     <tr>
-      <td>Ville ou code postal</td>
-      <td><input type="text" class="autocomplete" name="city" size="32" value="{$smarty.request.city}" /></td>
+      <td>Ville</td>
+      <td><input type="text" class="autocomplete" name="locality" size="32" value="{$smarty.request.locality}" /></td>
     </tr>
     <tr>
       <td>Pays</td>
@@ -416,18 +416,6 @@ function cleanForm(f) {
         <a href="country" class="autocompleteToSelect">{icon name="table" title="Tous les pays"}</a>
       </td>
     </tr>
-    <tr id="administrativearea_list">
-      <td>Région, province, état&hellip;</td>
-      <td>
-        <input name="administrativearea" type="hidden" size="32" value="{$smarty.request.administrativearea}" />
-      </td>
-    </tr>
-    <tr id="subadministrativearea_list">
-      <td>Département, comté&hellip;</td>
-      <td>
-        <input name="subadministrativearea" type="hidden" size="32" value="{$smarty.request.subadministrativearea}" />
-      </td>
-    </tr>
     <tr>
       <td colspan="2">
         <label for="only_current">