Pull to refresh

JS-PHP MVC интерфейс — cобираем всё вместе

Reading time 5 min
Views 7.3K
Для начала я хочу поблагодарить m007, который подал идею, как можно упростить Programmer-friendly интерфейс взаимодействия Клиент(JS)-Сервер(PHP), что и поспособствовало написанию этой статьи.

Данная статья является заключительной, в которой я объединю JS-Шаблоны, PHP Model-controller, и добавлю Динамическое создание UI методов на JS (некоторые идеи которого были взяты из статьи m007). Тем самым мы получим на выходе неплохой и удобный фундамент для создания своих AJAX приложений.

Динамическое создание методов на JavaScript

Для начала хочу обратить ваше внимание, что все наши методы лежат в PHP-библиотеке. Каждый метод можно вызвать, передав определенные параметры в стиле JSON. И чтобы вызвать PHP-метод из JS, я предлагал в прошлой статье использовать функцию server_exec. Но можно это сделать более удобно и
информативно для программиста.
m007 предложил вызывать функции прямо из JS, то есть вместо server_exec(«database_func(...);»,function(){...}) использовать в JS database.func(...).

В PHP, для не объявленных функций, есть метод __call. В JS такого метода нет, но можно предварительно подгрузить методы из PHP-библиотеки и динамически добавить их в JS-класс.

Для этого в PHP-класс UserInterface (см. прошлую статью) был добавлен метод, который при ‘пустом’ запросе выводил все зарегистрированные методы.
На Javascript написан класс PHPUIclass, который является интерфейсом для UserInterface. В этом классе описан метод обработки `пустого` запроса (спасибо DmitryBaranovskiy за приведение кода в порядок):
this.add=function(res){
      var methods=eval('{' + res.responseText + '}');
      for (var index in methods)
        that[methods[index]] = (function (name) {
          return function () {
            request.push('"' + name + '":' + that.methods(Array.prototype.slice.call(arguments)));
            if (!timer)
              timer=window.setTimeout(function(){
                ajax_load(url, «method={»+that.getrequest(request)+"}", that.ajax_run, true);
              },0);
          };
        })(methods[index]);
    }
* This source code was highlighted with <font size='1'
color='gray'>Source Code Highlighter
.
Эта функция вызывается, когда PHP-библиотека возвращает названия зарегистрированных методов UI (ответ на ‘пустой’ запрос). Исходя из этих данных, этот метод создаёт внутри своего класса новые методы, которые используют для вызова public-методов PHP-библиотеки.

При запуске метода, происходит кодирование входящих параметров (request.push('"'+methods[index]+'":'+that.methods(Array.prototype.slice.call(arguments)))) и установка нулевого таймера на функцию для отсылки запроса. Думаю, что некоторых читателей этот момент удивил. По этому я остановлюсь на нём поподробнее.

Javascript не имеет потоков и весь код выполняет последовательно. Состояния у него всего два – выполнение кода и ожидание прерывания. Прерывания могут прийти, например, от таймера (по таймауту), от AJAX запроса (при смене статуса) и т д. При этом запускается состояния выполнение кода, который не прерывается, пока не дойдёт до конца.
Именно для этого я использую нулевой таймер, который запустит выполнение функции отсылающей запрос на сервер, после окончания выполнения основного кода. Сделано это для того, чтобы отсылать всё одним инкрементированным запросом, состоящим из всех вызываеммых функций и обрабатывать результаты последовательно.

Теперь можно перейти к обработке результатов запроса. Так как обработчик будет вызван не сразу – то это будет функция или несколько функций, которые необходимо вызвать, когда придет ответ.
Этим занимаются методы run и ajax_run. Первый добавляет функции на запуск после получения ответа. Функции должны иметь вид function(data). А функция ajax_run занимается их запуском.
this.run=function(eee){
  func.push(eee);
}

this.ajax_run=function(req){
  var ret=eval('('+req.responseText+')');
  for (var i in func)
   if (func[i])
     func[i](ret);
  request=[];
  func=[];
  timer=false;
}
* This source code was highlighted with <font size='1'
color='gray'>Source Code Highlighter
.
В результате мы получаем модифицируйщийся класс, в зависимости от установленных методов в PHP. И взаимодействие с ним выглядит очень удобно:
//Инициализация класса удаленной работы с файлами.
/* Синхронный запрос на вызов FileManager.php.
Получение методов dir,save,read.
Динамическое создание функций. */
var File=new PHPUIclass('FileManager.php');

//Вызов удалённых функций
/* Установка таймера и формирования запроса */
File.save(«edited.txt»,«Отредактированная часть файла»);
File.read(«save.log»);

File.dir();

//Установка функций для получения результатов запроса.
/* Добавление функции для обработки запроса read */
File.run(show_file);

/* Добавление функции для обработки запроса dir */
File.run(show_dir);

//Конец выполнения скрипта, а значит выполнение POST-запроса по Timeout(0) и возвращение результатов в show_file и show_dir
* This source code was highlighted with Source Code Highlighter.
Ещё один пример, как воспользоваться результатом функции для запуска другой:
function show_file(file){
  //…
}

function show_error(error){
  // ...
}

function check_file(result){
  if (result.ERROR && result.ERROR.checkfile)
    show_error(result.ERROR.checkfile);
  else{
    // Всё прошло нормально?
    // Тогда ещё один запрос, уже на чтение.
    File.read(result[«filename»]);
    File.run(show_file);
  }
}

//Вызов удалённых функций
File.checkfile(«edited.txt»);

File.run(check_file);
* This source code was highlighted with Source Code Highlighter.
Но в этом случае будет происходить два запроса. Этого избежать можно несколькими способами. Один из способов — это реализовать вызов необходимой функции с возвратом пряма в PHP.
function checkfile($filename){
  global $UImethod;
  if (file_exists($filename))
   return $UImethod->read($filename);
  else
   return array(«ERROR» => array(«checkfile»=>$filename));
}
Теряется модульность, но в данной реализации Javascript библиотеки, пока это единственный выход. Возможно в будующем я усовершенствую её, при необходимости.

Пример

А вот — простой пример. File-viewer с возможностью редактировать файлы.

PHP:
UI.php основной класс UserInterface — подключается в библиотеку.
mod.fileview.php библиотека для чтения-записи файлов — функции read и save.
mod.dirview.php библиотека для чтения дириктории — функция dir.
mod.backup.php библиотека для формирования save.log — функции read,save,dir.
FileManager.php основной файл, который включает в себя все модули и запускает обработчик запроса.

Javascript:
PHPUI.js основной класс, который занимается подключением к интерфейсу UserInterface в php.
skin.js — класс работы с шаблонами.
index.html — загрузка шаблонов, вывод файлов.

HTML:
manager.skin — Шаблоны
manager.css — CSS
rus.xml — русский язык.

Рабочий пример

Послесловие

Плюсы:
— Удобство программирования и создания новых методов для JS-интерфейса
— Ясность и прозрачность кода
— Универсальность методов
— Возможен вызов функций с неопределенным количеством параметров
Минусы:
— Нет проверки на параметры методов. Возможны простейшие ошибки при создании кода. Но для этого можно в PHP-функциях проверять пришедшие параметры (например для DEBUG-MODE). В случае не верных параметров, выводить alert(«ERROR»).

p.s. кстати, модель этого проекта является MVC.
Tags:
Hubs:
+20
Comments 53
Comments Comments 53

Articles