Генерация кода

С чего должно начинаться создание среднестатистического веб-приложения? «С написания моделей, контроллеров CRUD-операций и видов!» — ответят некоторые. А те, кто опытнее, ответят — «С генерации моделей, контроллеров CRUD-операций и видов». И правильно! Зачем вручную писать то, что может за тебя написать программа? Конечно, есть нетривиальные проекты, где генератор кода помочь не сможет, но в основной своей массе веб-приложения похожи на цыплят: как вылупятся — все одинаково желтые, и лишь со временем у каждого появляется индивидуальный окрас (если они, конечно, не из инкубатора).

Основные преимущества генерации в следующем:

  • Экономия времени. В зависимости от задачи, можно сэкономить до 90% времени. Самый удачный вариант, это когда нужно только задать описание модели и запустить генератор. Менее удачные — когда в код после генерации нужно вносить некоторые правки.
  • Минимизация ошибок. Человеческий фактор это — определенная вероятность появления ошибки. Компьютеры же основаны на четкой логике и совершить ошибку не могут даже при большом желании. Единственное исключение: ошибки которые допустил разработчик при написании генератора.
  • Стандартизация. Генераторы формируют код по шаблону. И если в шаблоне заложены определенные стандарты, то эти же стандарты будут присутствовать в созданном коде. Например, генератор может отсортировать методы и свойства класса в алфавитном порядке или применить какие-нибудь патерны проектирования.

Генерация кода — очень популярная вещь и найти ее можно где угодно. Самыми простыми примерами являются предопределенные шаблоны в IDE. Некоторые генераторы идут в комплекте с фреймворком, как, например, генератор Gii для Yii. Но, как это часто бывает, предложенного оказывается недостаточно. Именно по этой причине я решил написать свой генератор, с блэкджеком и шлюхами ©.

Собственно, генератор состоит из двух частей. Первая представляет собой модуль, который разбирает описание модели, вторая генерирует код по заданной схеме. Схем пока немного, и в основном они заточены под Yii. Одна из них служит для генерации моделей на базе CActiveRecord, вторя — контроллеров, третья — видов и четвертая для генерации SQL-скриптов для создания таблиц, в которых будут храниться данные моделей. Еще есть схема для обычной модели, но я ее писал больше для теста и еще не нашел ей применения. Но на основе вышеперечисленных схем, я удачно создавал базовый код, который включал в себя полноценную модель, в которой определены правила валидации (метод rules()), связи с другими моделями (метод relation()), а так же других стандартных методов (метод search(), возвращающий CActiveDataProvider, tableName(), attributeLabels() и прочее). Так же код включал контроллер CRUD операций и вид, адаптированный под twitter bootstrap. В отличие от вида, генерируемого Gii он мог содержать не только текстовые поля, но и чекбоксы, выпадающие списки и другие распространенные элементы, в зависимости от типа данных атрибута. Ну и, естественно, MySQL-скрипт, создающий таблицу со столбцами, соответствующими атрибутам модели. Чтобы понять, как использовать генератор, разберем пример:

model User scheme yii_model, yii_view_twitter_bs, yii_controller, mysql:
	required attr first_name char(100);
	attr last_name char(100);
	required attr email email;
	required attr role enum("Admin", "Editor", "Subscriber") = "Subscriber";
	attr active bool;
	collection attr posts Post;

model Post scheme yii_model, yii_view_twitter_bs, yii_controller, mysql:
	required attr title char(100);
	required attr `text` text;
	required attr status enum("Draft", "Trash", "Published") = "Draft";
	attr user User;

В примере описаны две модели: User и Post. Описание начинается с ключевого слова model. За ним идет название модели (оно же имя класса), потом идет перечисление используемых схем, а за ними, после двоеточия, описание атрибутов. Атрибуты могут иметь некоторые свойства, с них начинается определение атрибута (в примере: required, которое обозначает, что атрибут обязательный и collection — означает, что атрибут является коллекцией или иными словами — массивом, а в конкретном случае, он еще и указывает на наличие связи один ко многим). После перечня свойств (которые могут и отсутствовать) идет ключевое слово attr, а за ним имя атрибута и тип. Если уж так вышло, что имя атрибута совпало с одним из ключевых слов, его нужно взять в косые кавычки. Типы могут быть либо предопределенные, либо произвольные. Предопределенные это:

  • int, цело число;
  • decimal, дробное число, в скобках можно указать размерность, аналогично тому, как это делается в SQL;
  • char, строка, в скобках указывается размер (аналог varchar в MySQL);
  • text, текст (аналог text в MySQL);
  • bool, логическое;
  • enum, значение из заданного диапазона (аналог enum в MySQL)
  • option, то же, что и enum, но можно задать ключи для значений.

Хотя эти типы и подразумевают конкретное применение, то, как они будут интерпретированы схемами, остаются на усмотрение самих схем (по правде говоря, это касается не только типов, но и всего остального). Например, группа схем, которую я создал имеет свои предопределенные типы: email, date, time, datetime, phoneNumber, file. Не буду описывать их назначение, думаю оно очевидно. Остальные произвольные типы данные схемы интерпретируют как связи между моделями. Например, атрибут user модели Post интерпретирован как связь один к одному с моделью User по внешнему ключу user_id.

Атрибуту можно задать значение по умолчанию используя знак «=», но эта возможность доступна только для предопределенных атрибутов.

Если интересно, то, что по этому описанию создал генератор можно скачать тут. Сам генератор живет на Git Hub. Не стесняйтесь заходить, скачивать, писать в трекер.