Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > e4xu

Всякие разные штуки сомнительной полезности сделанные в свободное от работы время.
Оценить эту запись

Генерация AS3 классов с помощью... PHP!

Запись от wvxvw размещена 26.05.2010 в 17:55
Обновил(-а) wvxvw 26.05.2010 в 21:03

Мы с другом обсуждали как же лучше сделать шаблонизатор для AS3. Пробовали несколько разных подходов. Либо используя флексовый компилятор, либо альтернативные библиотеки типа Metaas. А вчера вдруг в голову пришла мысль. А ведь PHP же на самом деле может быть использован как универсальный инструмент для постройки шаблонов! Он и работать будет поживее чем Java библиотеки (в смысле обработки строк - ну все-таки это же Си-шная программа, которая восновном под это и заточена!), и, в принципе, знаком каждому, а даже если и нет, то абсолютно не сложный в изучении. Документации - валом, устанавливается - практически где угодно, сложность установки - практически нулевая. И все это бесплатно, тоесть даром!
Сегодня с утра решил попробовать воплотить идею в жизнь, и вот результаты:
(На все про все ушло около часа работы, даже меньше, пожалуй)

Итак, задача:
Нужно создать AS3 класс в точности соответствующий описанию таблицы в базе данных, так называемый business object или value object. Генерить их вручную - удовольствия никакого, да и плюс ко всему, ошибки могут быть, а потом еще их апдейтить нужно, если что-то в базе поменялось. Вобщем, нудная, рутинная работа.

Решение:
Пишем шаблон на PHP, который загружает описание нужной нам таблицы, и создает из него AS3 исходник, который мы потом можем использовать в нашем проекте.

Пререквизиты:
У вас установлем MySQL сервер и PHP. Для Windows в PHP инсталяции вообще никаких изменений делать не нужно, просто найдите где находится php.exe.
У вас есть готовая таблица в базе, ну что-то в этом духе:
(Генерилось Workbench'ем)
Код:
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

CREATE SCHEMA IF NOT EXISTS `Pproject` DEFAULT CHARACTER SET utf8 ;
USE `Pproject`;

-- -----------------------------------------------------
-- Table `Project`.`Uploads`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `Project`.`Uploads`;

CREATE  TABLE IF NOT EXISTS `Project`.`Uploads` (
  `path` VARCHAR(256) NOT NULL ,
  `type` ENUM('image', 'video', 'text', 'folder') NOT NULL ,
  `width` SMALLINT NULL DEFAULT NULL ,
  `height` SMALLINT NULL DEFAULT NULL ,
  `created` DATETIME NOT NULL ,
  `modified` DATETIME NULL DEFAULT NULL ,
  `author` VARCHAR(32) NOT NULL ,
  `notes` TEXT NULL DEFAULT NULL ,
  PRIMARY KEY (`path`) ,
  INDEX `author` (`author` ASC) ,
  CONSTRAINT `author`
    FOREIGN KEY (`author` )
    REFERENCES `Project`.`Users` (`un` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8;



SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
А вот и шаблон:
Код:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$con = mysql_connect('localhost', 'root', '123123');
mysql_select_db('Project', $con);
$desc = mysql_query("DESCRIBE  {$argv[1]};");
$type_re = '/^\w+/';
$var_declarations = array();
$const_declarations = array();

while ($row = mysql_fetch_array($desc))
{
   $matches = array();
   preg_match($type_re, $row['Type'], $matches);
   $type =  $matches[0];
   $as3_type = "";
   switch ($type)
   {
      case 'text':
      case 'varchar':
         $var_declarations[$row['Field']] = 'String';
         break;
      case 'smallint':
         $var_declarations[$row['Field']] = 'int';
         break;
      case 'datetime':
         $var_declarations[$row['Field']] = 'Date';
         break;
      case 'enum':
         $var_declarations[$row['Field']] = 'String';
         $matches = array();
         preg_match('/\(([^\)]+)\)/', $row['Type'], $matches);
         $members = explode(',', $matches[1]);
         
         foreach ($members as $match => $key)
         {
            $val = trim($key, "'");
            $const_declarations[strtoupper($val)] = $val;
         }
         break;
   }
}
?>
package tld.local.database
{
   public class <?php print $argv[1];?>
   {
   <?php foreach($const_declarations as $var => $type) {?>
   public static const <?php print $var;?>:String = "<?php print $type;?>";
   <?php }?>
   
   <?php foreach($var_declarations as $var => $type) {?>
   /**
       * This property is generated from database.
       */
      private var _<?php print $var;?>:<?php print $type;?>;
   
      public function get <?php print $var;?>():<?php print $type;?> { return this._<?php print $var;?>; }
   
      public function set <?php print $var;?>(value:<?php print $type;?>):void
      {
         if (this._<?php print $var;?> === value) return;
         this._<?php print $var;?> = value;
      }
      
   <?php }?>
      
      public function <?php print $argv[1];?>() { super(); }
   }
}
Сделаный на скорую руку, просто для примера, сами понимаете, возможностей у вас тут гораздо больше.

Запускаем и тестируем:
Код:
C:\xampp\php>php test.php Uploads
Из командной строки.

Получаем вот такой результат:
Код AS3:
package tld.local.database
{
        public class Uploads  {
                public static const IMAGE:String = "image";
                public static const VIDEO:String = "video";
                public static const TEXT:String = "text";
                public static const FOLDER:String = "folder";
 
                /**
                 * This property is generated from database.
                 */
                private var _path:String;
 
                public function get path():String { return this._path; }
 
                public function set path(value:String):void
                {
                        if (this._path === value) return;
                        this._path = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _type:String;
 
                public function get type():String { return this._type; }
 
                public function set type(value:String):void
                {
                        if (this._type === value) return;
                        this._type = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _width:int;
 
                public function get width():int { return this._width; }
 
                public function set width(value:int):void
                {
                        if (this._width === value) return;
                        this._width = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _height:int;
 
                public function get height():int { return this._height; }
 
                public function set height(value:int):void
                {
                        if (this._height === value) return;
                        this._height = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _created:Date;
 
                public function get created():Date { return this._created; }
 
                public function set created(value:Date):void
                {
                        if (this._created === value) return;
                        this._created = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _modified:Date;
 
                public function get modified():Date { return this._modified; }
 
                public function set modified(value:Date):void
                {
                        if (this._modified === value) return;
                        this._modified = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _author:String;
 
                public function get author():String { return this._author; }
 
                public function set author(value:String):void
                {
                        if (this._author === value) return;
                        this._author = value;
                }
 
                /**
                 * This property is generated from database.
                 */
                private var _notes:String;
 
                public function get notes():String { return this._notes; }
 
                public function set notes(value:String):void
                {
                        if (this._notes === value) return;
                        this._notes = value;
                }
 
 
                public function Uploads() { super(); }
        }
}
Результат выведется в консоль, но, опять же, никто вам не мешает перенаправить вывод в файл, равно как сгенерить нужные папки для пакеджей, и даже запустить компилятор, если необходимо потестировать результат!

Планы на будущее:
Сделать плагин к FlashDevelop, который бы использовал PHP в качестве шаблонизатора, что позволило бы, например, генерацию классов из UML, баз данных, или просто отдельных шаблонов.
Всего комментариев 13

Комментарии

Старый 26.05.2010 19:52 koIIImarik вне форума
koIIImarik
 
Аватар для koIIImarik
Мне очень нравится ваш энтузиазм, и даже сам как-то заражаешься им, читая статью.

Но, пожалуйста, объясните, какая практическая польза от этого? Данная вещь будет просто создавать классы на основе информации в БД? Нам ведь всё-равно, если информация обновилась в БД нужно будет создавать новый класс и т.п. Не проще ли создавать классы, которые будут работать с PHP->MySQL и брать оттуда информацию?

В общем, был бы благодарен, если бы вы привели пример какого-то проекта где данное изобретение было бы полезным и нужным.
Старый 26.05.2010 20:39 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Это более "по-научному" называется ORM - object - relational mapping. Смысл обычно в том, что базами данных и клиентской частью занимаются разные люди, и между ними как-то надо наладить контакт, чтобы не получалось вариантов, когда ваше приложение ожидает получить от базы информацию, которая в ней не хранится. Кромe того, по мере того как идет рабoта над приложением, в БД тоже приходится делать изменения, и если вы в коде получателя результатов от базы не проапдейтите соответствующую информацию - потом будут ошибки.
Как можно применить именно этот пример - допустим, вы пользуетесь AMFPHP или его зендовской версией. Вам понадобится создавать 2 набора классов если вы хотите сохранить типизацию при пересылке данных. Тоесть прийдется делать муторную работу два раза, но, что еще хуже, как правило эти самые классы просто отражают то, что находится у вас в таблице. Тоесть, вам по сути нужно постоянно следить за синхронизацией SQL, PHP, AS3, и все люди, все делают ошибки, кроме того, это просто механическая операция на которую не хочется тратить время.

Другой пример использования, абсолютно не связаный с базами данных:
Вы сделали шаблон проекта в ФД, но некоторые вещи из этого шаблона иногда нужно генерить, а иногда нет (например вы хотите прямо при создании проекта указать сколько на сайте будет страниц, а может даже сразу и разметить страницы исходя из "мастера"). В ФД, конечно есть шаблоны, но создавать файлы по условию он не умеет, кроме того, возможности по вводу информации и ее последующей обработки шаблоном ограничены. Т.е. вы не сможете опционально включить блок текста в файл, например. Естесственно, что в этом отношении в PHP куча возможностей в отличие от простого поиска и замены в ФД.

Еще вариант. Вы спланировали проект в каком-нибудь UML редакторе и хотите сразу получить весь "скелет" проекта уже сразу в виде AS3 файлов. Опять же простеньким поиском-заменой тут не обойтись, надо будет парсить схему и на ее основе генерить чего там наптоектировали
Обновил(-а) wvxvw 27.05.2010 в 02:13
Старый 26.05.2010 23:21 Aloran вне форума
Aloran
A почему именно php? почему не java. Раз уж я работаю с FD, то у меня java машина уже стоит. При применении php мне еще и Апач ставить придеться... А зачем лишняя возня...
Старый 27.05.2010 02:06 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
А при чем тут Апач? PHP для виндовса это обычое консольное приложение. В данном случае мы его используем просто как продвинутый парсер для строк Под Линуксом PHP можно даже для ГУИ использовать потому что там очень много чего из консоли можно легко сделать / вызвать А не Java потому что PHP во много раз быстрее именно в этом аспекте и памяти занимает гораздо меньше. Пока JRE подымется, PHP уже отработает и закроется
Старый 27.05.2010 09:04 alexcon314 вне форума
alexcon314
Цитата:
Сделать плагин к FlashDevelop, который бы использовал PHP в качестве шаблонизатора, что позволило бы, например, генерацию классов из UML, баз данных, или просто отдельных шаблонов
Вот и я подумал, зачем нужен пхп? .NET-а мало? В связке с ФД? Притянули за уши . И вообще, если речь идет о шаблонах - почему не XSLT?.
Потом, мускул - это тоже частности. Правильнее юзать простые хмл-файлы как основу шаблона. А уж хмл этот, если сильно надо, можно генерить с использованием базы, но опять же без "левых" пхп, если речь идет об ФД-плагине.
Практическая ценность такой штуки эмм... как бы сказать... видимо это будет достойной фичей для разработчиков, занимающихся конвеерной штамповкой приложений. Особенно, если они стахановцы . Удобно: там винтик подкрутил, тут гаечку ослабил - и вот тебе конвеер выдал новое"особенное" приложение. Следующий!
Старый 27.05.2010 11:48 Котяра вне форума
Котяра
 
Аватар для Котяра
Есть такая штука как google protoBuf.
Кроме, собственно, бинарного протокола, для всех языков (см. список.)
существуют генераторы, которые из .proto файлов генерируют коды классов на необходимых языках.
.proto файлы можно, как-раз, генерить из базы данных, а дальше - уже готовые решения.
А вообще - генератор удобен, когда из 1 прототипа ( .proto файлы или запись в базе данных) генерятся классы на разных языках. Использовать только для генерации классов 1 языка? Не очень понятна выгода, хотя она тоже наверное есть в каких то случаях.
PS. Кстати, тот же, Realaxy Editor, работает по похожему принципу. Кодим во внутренних сущностях MPS(RE), а потом выгоняем в AS файлы, причём Дембицкий, как-то обмолвился, что ничто- не мешеат сделать свой парсер выгоняющий в другой язык.
Кроме того есть такой язык OCaml заточенный под создание компиляторов/ трансляторов/ генераторов. С помощью его можно не только простые классы данных генерить но и вещи посложнее))
Обновил(-а) Котяра 27.05.2010 в 12:05
Старый 27.05.2010 14:37 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
alexcon314:
Дадада, я хочу посмотреть на то как вы будете писать XSL шаблоны для генерации.... массивов например Не, серьезно, XSL(T) да, позволяет сделать то же самое, но какими усилиями! Ксати сказать, MSVS не использует ни капли XSL для генерации своих шаблонов - поищите инфу по *.tt файлам и T4.
Мускул был выбран исключительно для примера, я же говорю, что возможности этим не ограничиваются совершенно.
К сожалению, кроме штамповки есть и еще другие задачи, где ФД шаблонов не хватает. Примеры: у меня есть много шаблонов, которые подразумевают создание трех файлов одновременно вместо одного - List<T>, ListIterator<T> и ListEvent<T> - удобнее раз кликнуть и создать все три, чем кликать 3 раза и вводить всю ту же самую инфу.

Котяра:
Еще раз - создание бизнес объектов это часный случай. Да, я знаю про Protobuf, и про OCaml - фишка в том, что первый заточен исключительно под генерацию специфическиx типов объектов, т.е. это не язык шаблонов. OCaml я просто не знаю, и все мои попытки собрать HaXe компилятор, который на нем написан под виндой закончились провалом, скорее всего изза того, что я как-то не так чего-то установил или настроил. Как бы это не может претендовать на звание простого решения для шаблонизатора... как часный случай, для человека, который с этим языком дружит - возможно, но не для меня. Кроме того, Lisp - замечательный инструмент для таких вещей которому всякие XSLT и MPS и в подметки не годились, но, опять же, надо уметь им пользоваться, и предлагать его в качестве простого решения для написания шаблонов - ну как бы обречено
ЗЫ. Realaxy пока что очень тормозной. Если быстро печатать, то вы быстрее файлы напечатаете, чем сгенерите...

ЗЫЫ. А еще PHP потому что решение независимое, и если нужно вдуг сделать удаленно, или на другой машине (том же Макинтоше) - нет проблем.
Обновил(-а) wvxvw 27.05.2010 в 14:40
Старый 27.05.2010 15:32 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
А вообще у меня когда то давно мысля была, что бы PHP генерил класс, который на серваке компилиться через Flex SDK и отправляет нам готовую свфку. Но тут подумал что даже если такое и возможно реализовать, то нагрузка на сервак будет нереальная =)
Старый 27.05.2010 17:36 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Зависит от объемов, но в целом да, если MXMLC компилировать, то тормоза обеспечены. С другой стороны - HaXe компилятор в 7 раз быстрее примерно, не учитывая время нужное на запуск JRE... так что там еще можно подумать...
Старый 27.05.2010 17:46 alexcon314 вне форума
alexcon314
wvxvw, наверно, я не понял юмора. Когда я читаю твои посты, то у меня создается впечатление, что сижу в землянке под массированным арт-налетом и курю.
Все приплел.. и т4 и мсвс и даже маки удаленные, лисп еще фик знает с чем... ужас. К чему все это было сказано?
Вообще, я имел в виду что-то типа вот такого:
http://www.rsdn.ru/article/dotnet/codegen.xml
Дешево и сердито.
Не, ну если тебе нравится изобретать велосипеды, то оно, конечно похвально.. только смысл?
За пхп:
Люди, юзающие ФД, однозначно сидят на винде с .NET-ом, нафик им сдался твой пхп?
Удаленно генерить классы на разных машинах - это вообще не в тему, хотя бы потому, что под такие дела проще "вдруг" найти свободно удаленную машину с нетом, чем с пхп на борту (речь не о серверах) или будешь сначала пхп удаленно ставить?. Опять же, нафига он там сдался?
пхп -серверный язык, писать на нем для десктопа (вы ведь для десктопа кодогенератор изобрели?) - неразумно, да, файлик ты из него распарсишь, запишешь, а если больше потребуется? А ведь потребуется..
Цитата:
К сожалению, кроме штамповки есть и еще другие задачи, где ФД шаблонов не хватает. Примеры: у меня есть много шаблонов, которые подразумевают создание трех файлов одновременно вместо одного - List<T>, ListIterator<T> и ListEvent<T> - удобнее раз кликнуть и создать все три, чем кликать 3 раза и вводить всю ту же самую инфу.
Это я вообще не понял про что. В смысле, что за аргумент такой?
Старый 27.05.2010 18:30 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Да, в том то все и дело, что вот когда потребуется больше, то PHP порвет всякие XSLT как тузик грелку. Ну серьезно ведь... Я пользовался генераторами документации, один написаный на PHP, а другой, всем извесный ASDocs - разница по времени - небо и земля. ASDoc, как сам понимаешь, основан на XSLT.
Люди, которые используют ФД скорее всего веб-програмисты, и поэтому PHP у них почти наверное есть, а даже если нету, то уж точно не в новинку. (Еще плюс - ФД тебе PHP файл и подсветит как надо, и аутлайн покажет, вобщем, удобно). Кроме того, написать на нем шаблон в разы проще и читается это понятнее чем XSLT. PHP ведь по сути и задумывался, как текстовый процессор / шаблонизатор, и это как раз то, что он делает лучше всего.
Зачем генерить классы на разных машинах - я сейчас работаю в маленькой команде, и у нас есть 4 AS3 программиста, двое из них на маках. Поэтому мне бы очень подошло решение, которое можно помимо ФД использовать и в другом месте.

По поводу List<T> и остальных -
http://code.google.com/p/e4xu/source...es/List.as.fdt
http://code.google.com/p/e4xu/source...istCell.as.fdt
http://code.google.com/p/e4xu/source...stEvent.as.fdt
http://code.google.com/p/e4xu/source...terator.as.fdt
вот. Есть значит у меня такой темплейт. И мне все эти четыре класса надо всегда все вместе создавать. Т.е. для того, чтобы использовать List<T>, мне нужно 4 раза кликнуть "New" выбрать нужный темплейт и ввести одни и те же параметры. Не очень много работы, но напрягает то, что нужно делать одно и то же по нескольку раз.

Да, ну и кроме того... а подключись ка базе данных из XSLT? А прочитай файл с диска из XSLT? А создай тред новый? А загрузи файл с другого компьютера? Тебе ведь кроме XSLT прийдется писать еще кучу утилит вокруг него, чтобы добится желаемого результата, а в PHP ты получаешь все в одном флаконе - дешево и сердито
Обновил(-а) wvxvw 27.05.2010 в 18:39
Старый 28.05.2010 00:38 alexcon314 вне форума
alexcon314
В моих рассуждениях первично .NET, XSLT на подхвате.
Скорость, думаю, тут не на первых ролях, и чтобы пхп порвал .NET?.. не думаю. Гибкость, юзабельность... это большее значение имеет. Ну, а "в одном флаконе" - соглашусь, убедил.
Я понял - пхп выбран именно как "капец какая популярная штука, его не знают только лентяи и имбицилы, а еще в фд можно пхп писать!")).

Я тоже писал шаблонизатор своего рода (не связано с АС никак, прикладная вещь; правда, интегрировал с цинком, и, кстати, да, мускул был источником "сырых" данных), и вобщем-то .NET+XSLT меня очень порадовал. Да, по-первости трудновато, согласен. Но потом я никуда больше не лазил. Возможностей туча, от добра добра не ищут. Но.. Твоя правда, ФД для таких изысканий не пригоден.
В базу не залезешь, да, и с диска не возьмешь, но на то и обертка нетовская.
(Да почему же не залезешь и не возьмешь?? Екстенжн, на том же нете написанный в шаблон пихнул и лазий,бери)), но это чисто из принципа возражение).

Цитата:
Да, в том то все и дело, что вот когда потребуется больше, то PHP порвет всякие XSLT как тузик грелку.
Я имел в виду не фичи языка как текстового процессора, а возможности работы со сторонними приложениями и интеграции в систему вообще, если уж замахиваться как положено. С нетом на десктопе не пхп тягаться. Вот представь, захотел ты с фд сдружиться.. как это на пхп сделать? Я не знаю..
Ну ладно, будем считать спор исчерпан). Время покажет. Выложишь - посмотрим.
Я надеюсь, ты не все уже выложил))?
ЗЫ. Так вышло, что я давно уже не веб программист, потому и взбрыкнул, наверно.. так что ты извини, если что..))
Обновил(-а) alexcon314 28.05.2010 в 00:49
Старый 28.05.2010 01:41 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Ну, как бы пост в чем-то и задумывался, как провокация Просто бытует такое мнение, что PHP - гадость для нубов, а он оказался отнюдь не таким плохим...
Что до интеграции в FD - а легко! Запускаем PHP и читаем из stdout. PHP вполне способен на минимальное взаимодействие типа запросить ввод пользователя, так что можно... но не в этом суть. Проблема с XSLT в том, что он не самодостаточный, вокруг него еще нужно много чего дописать / догрузить, чтобы сделать его по-настоящему полезным. Очень жаль в этом отношении, что наш AS3 компилятор такой тормоз, что задействовать его в генерации шаблонов, ну практически и тяжело, и бесперспективно...
Да, еще, такой момент - я знаю всего одну библиотечку для AS3, которая использует XML-подобный кодогенератор - забыл, как называется, генерит классы событий, команд и сервисов для Cairngorm. (Ну, это за исключением Realaxy, о которой уже говорилось). Код, который оно генерит выглядит мерзко до непристойности. Задействовано в нем куча всего, и Maven и AntRL... и в итоге гора родила мышь. Т.е. вот даже тот пример, который я запостил оно бы не смогло сгенерить, а даже если бы и смогло, его бы еще потом пришлось бы руками доделывать.

И, да, продолжение следует А то как же!

PS. Ах, да, забыл, и есть еще конечно Fiber адобовский... еще один случай, когда гора родила мышь... Задумка на 5+, а реализация на хилую троечку.
 

 


Часовой пояс GMT +4, время: 01:16.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.