Вопрос «Где?» возникает сразу же после вопроса «Что?» эта закономерность верна и в вебразработке. Многие сайты запрашивают информацию у пользователя, предлагая ему ввести свой адрес, т. е. страну, регион, город, улицу, дом почтовый индекс. Но как потом обрабатывать эти данные, если они были указаны в свободной форме? В своих первых проектах мы использовали свой «велосипед», но по мере роста и развития это «чудо» превратилось в «чудовище», которое поставило крест на эффективной обработке гео-информации о наших пользователях. Мне была поставлена задача прибить этого монстра, заменив его стандартизованной гео-базой и простым интерфейсом для работы с ней. Гугление на эту тему не дали готового решения, поэтому пришлось отбросить простой вариант и сделать свой гео-модуль.
База адресов России
Для начала, нужно было найти базу адресов России. В поисках базы адресов я наткнулся на две и вполне возможно, что единственные:
- КЛАДР (Классификатор адресов РФ) распространяется в *.dbf формате
- ФИАС (Федеральная информационная адресная система). По умолчанию распространятся в виде xml структуры, но видать пришлось еще подстраиваться под КЛАДР и из-за его архаизма ФИАС стал распространятся еще и в dbf формате
Разница между ними такая: 400 Мб КЛАДР-а против 9 Гб ФИАС-а — существенно, не правда ли? По этому определённо хочется пользоваться ФИАС-ом, т. к. по объёму можно полагать, что данные у него более избыточны, что соответственно и лучше. Но работа с ФИАС у меня не сложилась. Запросы по таблице адресов, были ужасно долгие и ни расстановка индексов, ни оптимизация запросов мне не помогли, пользовался я при этом MySQL 5.5
С КЛАДР-ом же, работа сложилась и как выяснилось позже, его детализации для моих (стандартных) задач, вполне хватает. Обзор по структуре таблиц КЛАДР-а можно почитать здесь/ Для него же кто-то сделал api, которое не работает :-), но авось ребята допилят, думаю многим будет полезно.
Для того, что бы можно было использовать КЛАДР в проекте, нужно его из распространяемого dbf формата конвертировать в что-то понятное MySQL. Впрочем можно залить базу напрямую, для этого можно использовать navicat или mydbf2mysql
Таким образом, я сделал простой гео-модуль, который можно докрутить под любые нужды.
Проект можно получить на Github
Что из себя представляет модуль?
Проект писался с использованием php 5.3, что важно.
СУБД MySQL 5.5, что не очень важно
Используемые библиотеки
- php Data Layer Doctrine 2
- js jquery
- js jquery.form
- js jquery.autocomplete
- css 960cs
.project # Корень проекта -css -js --plugins ---autocomplete ----jquery.autocomplete.js ---jquery.form.js --cabinet.js # скрипт для страницы с формой --initialize.js # скрипт инициализации --jquery-1.7.2.js -Entities --GeoLocation.php # Сущность с данными локации ip адреса --UserLocation.php # Сущность с данными локации пользователя --Kladr.php # Сущность содержит записи с объектами первых четырех уровней классификации --Socrbase.php # Сущность содержит записи с краткими наименованиями типов адресных объектов --Street.php # Сущность содержит записи с объектами пятого уровня классификации --Doma.php # Сущность содержит записи с объектами шестого уровня классификации --KladrRepository.php --HomeRepository.php --StreetRepository.php -Geo --Providers ---Deliveries # Поставщики услуг доставки ----Ems -----EmsDeliveryDecorator.php # Класс декоратор рассчитывающий EMS доставку -----EmsDiliveryProvider.php # Класс реализующий API сервиса EMS для расчёта доставки -----ENUM_EMS.php # перечисления команд ----RussianPost -----RussianPostDeliveryDecorator.php # Класс декоратор рассчитывающий доставку Почты России -----RussianPostDeliveryProvider.php # Класс реализующий API сервиса PostCalc для расчёта доставки ---Geocoder # Поставщики сервисов гео-кодирования ----Yandex -----Geocoder.php ----MapApiBase.php # Абстрактный класс для гео-кодирования ---Delivery.php ---DeliveryBase.php ---DeliveryDecoratorBase.php ---DeliveryDecoratorRound.php ---DeliveryProviderBase.php --common.php --Geo.php --GoecoderCreater.php # Фабрика для объекта гео-кодирования --ILocationBuilder.php --Location.php # класс умеющий делать запросы в сервис geo-ip --LocationBuilder.php # строитель объкта EntitiesUserLocation, по данным полученны от геокодера -_content.php -autobox.php # точка входа для запросов плагина выпадающих списков(оркуг/город) -autocomlete.php # точка входа для -Autoloader.php # мой авто-загрузчик классов -delivery.php # точка входа для запросов на расчёт доставки -index.php # основная точка входа -popup.php # пример реализации через модальное popup окно colorbox -run.php # bootstrap example приложения -String.php # строковые общие статические методы
Используемые api сервисы
- Geo IP сервис — этих ребят blog.ipgeobase.ru
- EMS расчёт доставки emspost.ru/
- RussianPost(иначе почта России) расчёт доставки postcalc.ru
- Yandex карта 2.0
Что умеем
- Делать запросы в КЛАДР
- Делать запросы в ipgeo, для получения расположения пользователя по его ip
- Делать запросы в EMS API для расчёта доставки
- Делать запросы в PostCalc для расчёта доставки
- Серверное гео-кодирование yandex map
Процесс устроен так: при загрузки страницы, получаем по ip адресу geo расположения пользователя, для этого сначала смотрим существует ли запись с ключом(ip адресом) в таблице geoLocation, если есть берём от туда, если нет, делаем запрос в сервис ipGeo полученные данные сохраняем в табличке geoLocation, для последующего сокращения трафика запросов в ipgeo сервис. Имеющиеся данные о расположении пользователя используем для предсказания расположения пользователя, т.е. три (регион/округ/город) выпадающих списках, заполняем данными и выделяем в них нужное расположение. Если расположение угадано верно, то пользователю останется указать только улицу и дом, а индекс (если он есть в кладре) подставится автоматически. Впрочем если по ip адресу расположение было не угадано, то регион/округ/город можно изменить. Для этого был написал простенки js плагин, который согласно выбранного региона запрашивает округ и большие города региона, а согласно выбранного округа, города округа.
Есть yandex карта для отображения сохраненного расположения пользователя. Впрочем, можно сделать что бы карта на лету реагировала, на выбор пользователем локации.
В конце страницы с формой задания адреса, для демонстрации имеется блок с расчётом доставки. Сам пакет доставки реализован, как «декоратор», поэтому можно настраивать калькуляцию сумм или время доставки. Собственно как работает калькуляция, должно быть понятно, нужно знать откуда и куда, а далее дело техники. Расчёт доставки можно расширить, путём добавления нового *поставщика*.
Удачно то, что структура указания адресов ФИАС схожа с КЛАДР, прошу заметить не идентична, а схожа поэтому если немного от-рефакторить код репозитория EntitiesKadrRepository, то можно использовать и ФИАС как хранилище адресов, вопрос только нужно ли это.
Подробное описание API модуля публикую в WiKi проекта на github
Надеюсь, что кому-то этот модуль будет полезен, но не претендую на идеальное решение, буду рад услышать замечания и предложения.
Автор: zpayment