Разработчику/Как-создать-Extension/Телефонная-книга

Телефонная книга


Ещё один пример (уже довольно функциональный) – расширение ContactBook


На этот раз мы решили показать, как можно значительную часть работы переложить на плечи Smarty и как нужно выстраивать архитектуру расширения.


Оглавление документа

1. Smarty-шаблон

Для того, чтобы работать с AJAX в Smarty нужно заключить весь шаблон в такие теги

<div id="divcontactbook">
{startvirtual}

{* здесь написаны все остальные фрагменты *}

{finishvirtual block="divcontactbook"}
</div>


Простейшая форма, отправляемая по AJAX – поиск по телефонной книге

{* форма поиска *}
<b>Поиск</b>
{ajxformopen id="s" actref="divcontactbook"}
  <div style="width:300px;">
    {* обращаем внимание на то, как заэкранирвоана переменная *}
    {virtualform id="search" name="text" default="`$search`"}
    <input type="submit" value="Искать!">
  </div>
{wackoformclose}


Здесь выводим все контакты. Обратите внимание на то, как сделана проверка на первую и последнюю итерацию цикла, на пустой массив и на то, как сделаны ссылки, переходы по которым будут проходить через AJAX

{foreach from=$contacts item=contact name=contactbook}
  {* в первой итерации цикла выводим шапку таблицу *}
  {if $smarty.foreach.contactbook.first}
    <table width="100%">
    <tr>
      <td width="20%"><b>Имя</b></td>
      <td width="20%"><b>Фамилия</b></td>
      <td width="20%"><b>Телефон</b></td>
      <td width="20%"><b>E-mail</b></td>
      {if $canedit == "1"}
        <td></td>
        <td></td>
      {/if}
    </tr>
  {/if}

  <tr>
    <td>{$contact.name}</td>
    <td>{$contact.sname}</td>
    <td>{$contact.phone}</td>
    <td>{mailto address="`$contact.email`"}</td>
    {if $canedit == "1"}
      <td>{ajxhref text="<img src='`$rooturl`images/additional/edit.png' />" 
                   elements="divcontactbook" params="editid=`$contact.id`"}</td>
      <td>{ajxhref text="<img src='`$rooturl`images/additional/drop.png' />" 
                   elements="divcontactbook" params="delid=`$contact.id`" }</td>
    {/if}
  </tr>

  {* в последней - закрываем таблицу *}
  {if $smarty.foreach.contactbook.last}
    </table>
  {/if}
{foreachelse}
  {* если массив оказался пуст - выводим сообщение *}
  Ничего не найдено
{/foreach}


Ещё одна форма – в ней производится и редактирование, и добавление контактов

{* если имеем право редактировать *}
{if $canedit == "1"}
  <br /><br />
  {ajxformopen id="e" actref="divcontactbook"}
    {* с помощью этого поля определяем, новая это запись или редактирование старой *}
    {virtualform id="nid" name="hidden" default="`$editcontact.id`" }
    <table>
      <tr>
        <td>Имя     </td><td>{virtualform id="editname"  name="text" default="`$editcontact.name`" }</td>
      </tr>
      <tr>
        <td>Фамилия</td><td>{virtualform id="editsname" name="text" default="`$editcontact.sname`"}</td>
      </tr>
      <tr>
        <td>Телефон</td><td>{virtualform id="editphone" name="text" default="`$editcontact.phone`"}</td>
      </tr>
      <tr>
        <td>E-mail </td><td>{virtualform id="editemail" name="text" default="`$editcontact.email`"}</td>
      </tr>
    </table>
    <input type="submit" value="Отправить!">
  {wackoformclose}
{/if}

2. Экшн для вывода Smarty


<?
    
// для листалки нужно определить к-во контактов на страницу и точка начала
    
if($max==0$max=10;
    
$start = (int)$_REQUEST['start'];

    
// подключаем собственный класс
    
$CBServ $this->srvFactory("ContactBook");
     
// работа со смарти. сначала создадим смарти-объект
    
$smarty $CBServ->newSmarty();

    
// можем ли мы редактировать и добавлять?
    
if ($this->HasAccess("editCB")){
        
$smarty->assign('canedit'"1");
    }

    
// удаляем контакт
    
if ($id = (int)$_REQUEST['delid']){
        
$CBServ->DelContactById($id);
    }

    
// редактирование - пока только вернём значения для вставки в поля ввода
    
if (($id = (int)$_REQUEST['editid'])&&(!$_REQUEST['editname'])){
        
$smarty->assign('editcontact'$CBServ->GetContactById($id));
    }else{
        
$smarty->assign('editcontact', array(
                            
"id"    => "",
                            
"name"  => "",
                            
"sname" => "",
                            
"phone" => "",
                            
"email" => "",
                             )
                );
    }

    
// а вот теперь нам прислали контакт. хм... а он новый или старый?
    
if ($_REQUEST['editname']){
        
$info['id']     = (int)$_REQUEST['nid'];
        
$info['name']     = $_REQUEST['editname'];
        
$info['sname']     = $_REQUEST['editsname'];
        
$info['phone']     = (int)$_REQUEST['editphone'];
        
$info['email']     = $_REQUEST['editemail'];
        
// тут и определим
        
if ($info['id']){
            
// раз есть id, значит старый
            
$CBServ->EditContact($info);
        }else{
            
// а если нет, то новый
            
$CBServ->AddContact($info);
        }
    }

    
// формируем список контактов для отображения.
    // тут есть небольшая оптимизация. можно убрать условие и оставить только первую часть,
    // то есть всегда искать по пустому запросу
    
if ($text $_REQUEST['search']){
        
$contacts $CBServ->SearchContacts($text$max$start);
        
$crows $CBServ->GetContactsCount($text);    // для листалки нужно знать, сколько всего результатов
    
}else{
        
$contacts $CBServ->GetAllContacts($max$start);
        
$crows $CBServ->GetContactsCount();    // аналогично
    
}

    
// выстроим ссылки для листания
    
for($i=0;$i*$max<$crows;$i++) {
        
$link[$i]['start'] = $i*$max;    // это будут точки старта
        
$link[$i]['text']  = (($i+1)*$max>$crows?$crows:($i+1)*$max);    // а это - текст ссылки
      
}

    
// передадим шаблону значения переменных
    
$smarty->assign('contacts'$contacts);
    
$smarty->assign('links'$link);
    
$smarty->assign('search'$text);
    
// и выведем результат выполнения шаблона
    
echo $smarty->fetch('ContactBook.txt');
?>

3. Класс расширения


Пример правильной архитектуры – вся обработка данных и работа с БД происходит в классе расширения. Таким образом, при изменении структуры таблицы нам придётся внести минимум правок. Кроме того, код становится более логичным и понятным за счёт небольших размеров каждого файла – не больше 100 строк каждый.


<?php
class Service_ContactBook extends XcBase {

    var 
$_kernel;

    function 
Service_ContactBook($kernelLink) {
        
$this->_localname 'ContactBook';
            
$this->XcBase($kernelLink);
            
$this->_kernel $this->srvMainKernel();
    }

    function 
onInstall($params) {
        
$query "CREATE TABLE ".$this->_db->config["table_prefix"]."contactbook (
                    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
                    name VARCHAR(25),
                       sname VARCHAR(25),
                    phone VARCHAR(13),
                    email VARCHAR(50)
                 )"
;
            
$this->_kernel->Query($query);
            return 
true;
    }

    function 
onUninstall($params) {
        
$this->_kernel->Query("DROP TABLE ".$this->_db->config["table_prefix"]."contactbook");
         return 
true;
    }

    
// возвращает $max контактов по алфавиту, начиная со $start
    
function GetAllContacts($max$start="0"){
            if (!
$start$start="0";
            return 
$this->_kernel->LoadAll("SELECT * FROM  ".$this->_db->config["table_prefix"]."contactbook
                            ORDER BY `sname` ASC  LIMIT "
.$start." , ".$max);
    }

    
// запрашиваем контакт по id
    
function GetContactById($id){
            return 
$this->_kernel->dbGetById("contactbook",$id);
    }

    
// удаляем контакт по id
    
function DelContactById($id){
            
$this->_kernel->Query("delete from ".$this->_db->config["table_prefix"]."contactbook  
                           where id = '"
.$id."'");
        }

    
// добавляем контакт
    
function AddContact($info){
            
/*
            эта функция - хороший пример использования специальных функций ядра,
            занчительно укорачивающих код.
            */
        
$this->_kernel->insertInto("contactbook",$info);
    }

    
// редактируем контакт. id возьмём из $info
    
function EditContact($info){
            
$this->_kernel->Query('UPDATE '.$this->_db->config["table_prefix"].'contactbook SET
                          '
.$this->_kernel->dbConstructSetArray($info).' WHERE `id` = '.$info['id']);
    }

    
// ищем по всем полям и возврщаем ровно одну страницу результатов
    
function SearchContacts($text$max$start=0){
        if (!
$start$start="0";
        
$query "SELECT * FROM ".$this->_db->config["table_prefix"]."contactbook WHERE
                name  like '%"
.quote($text)."%' OR
                sname like '%"
.quote($text)."%' OR
                phone like '%"
.quote($text)."%' OR
                email like '%"
.quote($text)."%' ORDER BY `sname` ASC LIMIT $start , $max";
        return 
$this->_kernel->LoadAll($query);
    }

    
// получим количество результатов выполнения поискового запроса. нужно для листалки
    
function GetContactsCount($text=""){
        
$resc $this->_kernel->LoadSingle('SELECT count(*) FROM '.$this->_db->config["table_prefix"]."contactbook 
                WHERE
                name  like '%"
.quote($text)."%' OR
                sname like '%"
.quote($text)."%' OR
                phone like '%"
.quote($text)."%' OR
                email like '%"
.quote($text)."%'");
        return 
$resc["count(*)"];
    }

    
// обычная функция создания смарти
    
function NewSmarty(){
        
$mythis $this->_kernel;
        
$sm $mythis->NewSmarty();
        
$def $mythis->getSiteDataPath().'data/'.$this->_localname.'/';
        
$sm->template_dir $def.'templates/';
        
$sm->compile_dir $def.'templates_c/';
        
$sm->config_dir $def.'config/';
        
$sm->cache_dir $def.'cache/';
        
$sm->plugins_dir[] = $def.'plugins/';
        return 
$sm;
    }
}
?>

Живой пример

Поиск


Ничего не найдено


Имя
Фамилия
Телефон
E-mail

Скачать


Файлы, доступные на данной странице:
2012-02-03 00:14:51    (6 Кб)  contactbook.zip Расширение ContactBook


 
Подразделы
Раздел не содержит подстраниц.


Комменты