LiveStreet FW - Генерация сущностей

Добрый день!

Хочу поделиться небольшим скриптом и услышать мнения)

За основу очередного своего проекта решил взять LiveStreet FW. С толкнулся с проблемой что приходится писать много однообразного кода. К примеру, я привык при разработке базы данных писать комментарии к полям таблиц. На основании этих таблиц я создаю сущности, в которых прописываю на 50% туже информацию, потому что хочу чтобы код был документирован, как в LiveStreet CMS. Чтобы упростить немного жизнь, написал следующий скрипт для генерации сущностей в LiveStreet.

Итак.
  1. Распаковываем архив и заливаем в ваш проект LiveStreet CMS или LiveStreet FW.
  2. Создаем таблицу в базе даннных на основании которой будет создаваться сущность.
  3. Идем в конфиг (config/config.php) и добавляем правило роутинга $config['router']['page']['entity'] = 'ActionEntity';
  4. Переходим по адресу yoursite.ru/entity/
  5. Заполняем форму Рис. 1.
  6. Жмем добавить Рис. 2.
  7. Сохраняем полученный файл и переносим в нужную папку.
Рис. 1.
Генерация сущностей для LiveStreet

Рис. 2.
Сгенерированная сущность Livestreet

Как работает

В папке «temp» Вашего сайта создается файл Blog.entity.class.php с приведенным ниже содержанием. Не забудьте проверить, что папка имеет права на запись.
За основу названия функций берутся названия полей. При этом если у полей есть префикс, то он не попадает в названия функций. В нашем случае это «blog_». Далее у полей все слова преобразовываются к правильному написанию и удаляются символы "_". В результате получаем функции set и get для каждого поля.

Для примера

Для примера я взял стандартную таблицу prefix_blog и прокомментировал к ней поля.В результате получилсь вот такой класс сущности. Blog.entity.class.php
<?php
/*-------------------------------------------------------
*
*   LiveStreet Engine Social Networking
*   Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
*   Official site: www.livestreet.ru
*   Contact e-mail: rus.engine@gmail.com
*
*   GNU General Public License, version 2:
*   http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/

/**
 * Сущность блог
 *
 * @package modules.Blog
 * @since 1.0
 */
class ModuleBlog_EntityBlog extends Entity {


    /**
     * Возвращает айди блога
     *
     * @return int|null
     */
    public function getId() {
        return $this->_getDataOne('blog_id');
    }

    /**
     * Возвращает кому пренадлежит блог
     *
     * @return int|null
     */
    public function getUserOwnerId() {
        return $this->_getDataOne('user_owner_id');
    }

    /**
     * Возвращает название блога
     *
     * @return string|null
     */
    public function getTitle() {
        return $this->_getDataOne('blog_title');
    }

    /**
     * Возвращает описание блога
     *
     * @return string|null
     */
    public function getDescription() {
        return $this->_getDataOne('blog_description');
    }

    /**
     * Возвращает тип блога
     *
     * @return string|null
     */
    public function getType() {
        return $this->_getDataOne('blog_type');
    }

    /**
     * Возвращает дата добавления блога
     *
     * @return datetime|null
     */
    public function getDateAdd() {
        return $this->_getDataOne('blog_date_add');
    }

    /**
     * Возвращает дата редактирования блога
     *
     * @return datetime|null
     */
    public function getDateEdit() {
        return $this->_getDataOne('blog_date_edit');
    }

    /**
     * Возвращает рейтинг блога
     *
     * @return float|null
     */
    public function getRating() {
        return $this->_getDataOne('blog_rating');
    }

    /**
     * Возвращает количество проголосовавших за блог
     *
     * @return int|null
     */
    public function getCountVote() {
        return $this->_getDataOne('blog_count_vote');
    }

    /**
     * Возвращает количество подписчиков
     *
     * @return int|null
     */
    public function getCountUser() {
        return $this->_getDataOne('blog_count_user');
    }

    /**
     * Возвращает количество топиков в блоге
     *
     * @return int|null
     */
    public function getCountTopic() {
        return $this->_getDataOne('blog_count_topic');
    }

    /**
     * Возвращает лимит рейтинга для добавления топиков
     *
     * @return float|null
     */
    public function getLimitRatingTopic() {
        return $this->_getDataOne('blog_limit_rating_topic');
    }

    /**
     * Возвращает урл блога
     *
     * @return string|null
     */
    public function getUrl() {
        return $this->_getDataOne('blog_url');
    }

    /**
     * Возвращает аватар блога
     *
     * @return string|null
     */
    public function getAvatar() {
        return $this->_getDataOne('blog_avatar');
    }

    //------------------------------------------------------------------------------
    /**
     * Устанавливает айди блога
     *
     * @param int $data
     */
    public function setId($data) {
        $this->_aData['blog_id']=$data;
    }

    /**
     * Устанавливает кому пренадлежит блог
     *
     * @param int $data
     */
    public function setUserOwnerId($data) {
        $this->_aData['user_owner_id']=$data;
    }

    /**
     * Устанавливает название блога
     *
     * @param string $data
     */
    public function setTitle($data) {
        $this->_aData['blog_title']=$data;
    }

    /**
     * Устанавливает описание блога
     *
     * @param string $data
     */
    public function setDescription($data) {
        $this->_aData['blog_description']=$data;
    }

    /**
     * Устанавливает тип блога
     *
     * @param string $data
     */
    public function setType($data) {
        $this->_aData['blog_type']=$data;
    }

    /**
     * Устанавливает дата добавления блога
     *
     * @param datetime $data
     */
    public function setDateAdd($data) {
        $this->_aData['blog_date_add']=$data;
    }

    /**
     * Устанавливает дата редактирования блога
     *
     * @param datetime $data
     */
    public function setDateEdit($data) {
        $this->_aData['blog_date_edit']=$data;
    }

    /**
     * Устанавливает рейтинг блога
     *
     * @param float $data
     */
    public function setRating($data) {
        $this->_aData['blog_rating']=$data;
    }

    /**
     * Устанавливает количество проголосовавших за блог
     *
     * @param int $data
     */
    public function setCountVote($data) {
        $this->_aData['blog_count_vote']=$data;
    }

    /**
     * Устанавливает количество подписчиков
     *
     * @param int $data
     */
    public function setCountUser($data) {
        $this->_aData['blog_count_user']=$data;
    }

    /**
     * Устанавливает количество топиков в блоге
     *
     * @param int $data
     */
    public function setCountTopic($data) {
        $this->_aData['blog_count_topic']=$data;
    }

    /**
     * Устанавливает лимит рейтинга для добавления топиков
     *
     * @param float $data
     */
    public function setLimitRatingTopic($data) {
        $this->_aData['blog_limit_rating_topic']=$data;
    }

    /**
     * Устанавливает урл блога
     *
     * @param string $data
     */
    public function setUrl($data) {
        $this->_aData['blog_url']=$data;
    }

    /**
     * Устанавливает аватар блога
     *
     * @param string $data
     */
    public function setAvatar($data) {
        $this->_aData['blog_avatar']=$data;
    }

}


25 строк бессмысленного кода

Немного критики. Сейчас я создаю свой первый сайт на LiveStreet FW и столь глубоко занимаюсь его изучением. То что код детально прокомментирован, это огромный плюс и большое спасибо автору. Но некоторые вещи мне кажутся бессмысленными.
// Распределение action
$config['router']['page']['error']         = 'ActionError';
$config['router']['page']['registration']  = 'ActionRegistration';
$config['router']['page']['profile']       = 'ActionProfile';
$config['router']['page']['my']            = 'ActionMy';
$config['router']['page']['blog']          = 'ActionBlog';
$config['router']['page']['personal_blog'] = 'ActionPersonalBlog';
$config['router']['page']['index']         = 'ActionIndex';
$config['router']['page']['topic']         = 'ActionTopic';
$config['router']['page']['login']         = 'ActionLogin';
$config['router']['page']['people']        = 'ActionPeople';
$config['router']['page']['settings']      = 'ActionSettings';
$config['router']['page']['tag']           = 'ActionTag';
$config['router']['page']['talk']          = 'ActionTalk';
$config['router']['page']['comments']      = 'ActionComments';
$config['router']['page']['rss']           = 'ActionRss';
$config['router']['page']['link']          = 'ActionLink';
$config['router']['page']['question']      = 'ActionQuestion';
$config['router']['page']['blogs']         = 'ActionBlogs';
$config['router']['page']['search']        = 'ActionSearch';
$config['router']['page']['admin']         = 'ActionAdmin';
$config['router']['page']['ajax']          = 'ActionAjax';
$config['router']['page']['feed']          = 'ActionUserfeed';
$config['router']['page']['stream']        = 'ActionStream';
$config['router']['page']['photoset']      = 'ActionPhotoset';
$config['router']['page']['subscribe']     = 'ActionSubscribe';

Из 26 строк из закономерности выделяется только одна «feed — ActionUserfeed». Надеюсь автор фрейма не воспример это как обиду, а как возможный способ оптимизации.

P.S.


Возможно я «изобрел велосипед» написав свой скрипт, но сходу я не нашел нужного мне решения.

9 комментариев

avatar
Все хорошо, только для упрощения давно появилась возможность не заполнять get/set методы у сущностей. Они обрабатываются автоматически через __call. Поэтому часто можно встретить такие «пустые» сущности — github.com/livestreet/livestreet/blob/1.0.1/classes/modules/subscribe/entity/Subscribe.entity.class.php
Единственный вариант, это когда у полей в таблице есть какой-то префикс, тогда необходимо в явном виде определить методы. Но, например, я стараюсь уже не использовать префиксы в полях таблиц, т.к. само имя таблицы обычно выполняет эту роль.

А сам код генератора лучше оформить в виде плагина, чтобы процесс установки/удаления не заключался в ручном поиске файлов по проекту и их удалению.

25 строк бессмысленного кода
если их не писать, то придется каждый раз при произвольном запросе проверят существование соответствующего файла экшена(в проверке нет ничего страшного, но экшен может быть и в любом плагине). Здесь больше вопрос удобства — видеть наглядно действующий список роутинга и быстрая возможность что-то отключить(не удаляя файл экшена).
  • ort
  • +2
avatar
Спасибо за комментарий. Постараюсь как появится время оформить в виде плагина.
Здесь больше вопрос удобства — видеть наглядно действующий список роутинга и быстрая возможность что-то отключить(не удаляя файл экшена).
Возможно я до конца еще не прочувствовал LiveStreet. Но простое переименование экшена например 12345ActionTopic.class.php, выполнит тоже самое.

По поводу полей я все-таки придерживаюсь присать префиксы. К примеру у топика, блога, пользователя может быть поле name. Когда пишешь проект один, то в сложных запрос можно постараться и написать нормальные алиасы для таблиц. Но когда пришешь совместно, то могут попасться некоторые товарищи, которые напишут вот так b.name, u.name, t.namе. Это очень усложняет читабельность кода. В случае с префиксами у них это просто не получится. Eще префиксы мне помагают сразу понимать где есть внешние ключи. Вот пример:
CREATE TABLE srv22570_shop.riff_product(
  product_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор производителя',
  product_url VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'урл продукта',
  product_title VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'Название производителя',
  product_keywords VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'Ключевые слова для производителя',
  product_description TEXT CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'Описание производителя',
  product_rating_sum INT(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Сумма всех оценок',
  product_rating_count INT(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Количество оценок',
  product_rating_itog FLOAT(4, 2) NOT NULL DEFAULT 0.00 COMMENT 'Итого средний рейтинг',
  product_views BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Количество просмотров',
  product_pod_zakaz TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Товар под заказ',
  product_hide TINYINT(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Скрыть товар',
  product_date_add TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'Время добавления товара',
  product_date_update DATETIME DEFAULT NULL COMMENT 'Время обновления товара',
  product_price_wholesale_kg FLOAT(7, 2) UNSIGNED NOT NULL DEFAULT 0.00 COMMENT 'Оптовая цена за кг',
  product_price_retail_kg FLOAT(7, 2) UNSIGNED NOT NULL DEFAULT 0.00 COMMENT 'Розничная цена 
  product_in_stock FLOAT(7, 2) UNSIGNED NOT NULL DEFAULT 0.00 COMMENT 'Вес товара на складе',
  cat_id INT(11) UNSIGNED NOT NULL COMMENT 'Идентификатор категории',
  make_id INT(11) UNSIGNED DEFAULT NULL COMMENT 'Идентификатор производителя',
  PRIMARY KEY (product_id)
)
ENGINE = INNODB
AUTO_INCREMENT = 3
AVG_ROW_LENGTH = 8192
CHARACTER SET utf8
COLLATE utf8_bin;

cat_id и make_id здесь внешние ключи.
avatar
Из 26 строк из закономерности выделяется только одна «feed — ActionUserfeed». Надеюсь автор фрейма не воспример это как обиду, а как возможный способ оптимизации.
это означает только что вы недостаточно
столь глубоко занимаюсь его изучением.
Возможно я до конца еще не прочувствовал LiveStreet. Но простое переименование экшена например 12345ActionTopic.class.php, выполнит тоже самое.
вызовет ошибку
avatar
Максим вам ответил выше, что сущности создаются автоматически, начиная с 0.5 версии.
и писать префиксы выше к полям — это дурной тон, подтверждаю комментарий выше.
avatar
вызовет ошибку
совершенно верно. Я говорил про тот случай, когда не нужно писать роутинг, а фрейм сайм будет проверять наличие контроллеров по первой части урла. Тогда чтобы отключить экшен, будет достаточно его переименовать.
писать префиксы выше к полям — это дурной тон
По этому поводу я уже высказал свое мнение по чему я это делаю.

Спасибо за подсказку про пустые сущности. Получается можно тогда не описывать эти методы если писать названия полей полностью.
avatar
Есть способы разработки с использованием ORM, в данном случае сеттеры и геттеры не прописываются и вы представляете, люди как то умудряются разрабатывать проекты в команде, без всяких шаманств и описывания полей.

Правда в ORM указываются «отношения» которые возможно облегчают различение идентификаторов, но не считаю идентификаторы большой запарой в этом вопросе.
avatar
А по поводу описывания Экшенов хочу сказать что это во первых наглядно как сказал Максим, во вторых быстро, а в третьих не ново, т.к многие фреймворки вообще описывают все пути классов вместо использования autoload, и такая опись предупреждает возможные нештатные ситуации, что в условиях проекта может стать причиной финансовых и прочих потерь.
avatar
совершенно верно. Я говорил про тот случай, когда не нужно писать роутинг, а фрейм сайм будет проверять наличие контроллеров по первой части урла. Тогда чтобы отключить экшен, будет достаточно его переименовать.
проверка на наличие файла в ФС — весьма долгое занятие по сравнению с «просто взять и запустить файл»
avatar
Чтобы не плодить темы подскажите пожалуйста как настроить вот такой роутинг в FW LiveStreet.
/nazvanie_kategorii/nazvanie_kategorii/kartochka_tovara/
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.