Next Framework

Быстрее, чем обычно.

Оглавление

Предупреждение

Next Framework НЕ предназначен для использования начинающими разработчиками.

Как и любой другой фреймворк или язык программирования, для ответственного решения задач требуются вполне известные профессиональные навыки. Хорошие посты на эту тему есть в Клубе CodeIgniter.

Если вы являетесь начинающим разработчиком, и УЖЕ имеете некоторый опыт, вы можете изучить библиотеки Next Framework в качестве примеров удачного решения задач.

Совет: НЕ беритесь за выполнение проекта по договору, если у вас нет честного исключительного понимания устройства программы, которую вы намереваетесь создать, и обещаете сделать это кому-то в какой-то конкретный срок.

Лучше потратьте хотя бы пару месяцев на обучение и эксперименты. Работа не под давлением (в том числе имеется в виду давление обстоятельств) приятна, и позволяет полноценно изучать, пробовать и экспериментировать. Когда совесть чиста, и сомнения не гложут, сон будет крепким и полноценным. А это очень позитивно сказывается на возможности и эффективности обучения.

Что такое Next Framework

Next Framework (NF) — это высокоуровневый фреймворк, набор библиотек, которые позволяют разрабатывать веб-приложения:

NF включает в себя компоненты для решения наиболее частых задач:

NF не привязан к какому-то конкретному дизайну, и позволяет легко менять шаблоны и язык — дизайн и локализацию приложений в том числе на лету.

Почему использование Next Framework является удачным решением

NF является всего-лишь оберткой над CodeIgniter и jQuery. Использование jQuery не является обязательным.

По состоянию на 2016 год используются новейшие версии CodeIgniter 3.x и jQuery 2.x, что дают исключительную безопасность, высокую производительность, а также большой класс решаемых задач.

NF не привносит принципиально ничего нового в CodeIgniter и jQuery, потому что действует на более высоком уровне, чем эти замечательные фреймворки. CodeIgniter и jQuery работают на функциональном уровне, и решают низкоуровневые задачи, в том числе функциональную логику приложения. NF является высокоуровневым, и обеспечивает работу непосредственно с интерфейсом и бизнес-логикой приложения.

Таким образом, в бэкграунде остается мощь, простота и безопасность CodeIgniter и jQuery, а NF, благодаря своей парадигме, лишь привносит комплект «готовых решений» для решения наиболее частых задач веб-программирования и мобильных приложений с серверной частью.

Каким образом Next Framework обеспечивает безопасность приложения

Компоненты NF представляют собой библиотеки для выполнения реальных задач бизнес-логики. Каждая из библиотек максимально проста, и всесторонне протестирована. Таким образом, не допускаются сбои и уязвимости внутри библиотек.

NF также предоставляет каркас для разработки бизнес-логики приложения, и встроенные средства аналитики. При разработке бизнес-логики в соответствии с рекомендациями, изложенными в этом руководстве, получение каких-либо уязвимостей исключается.

Таким образом, использование Next Framework повышает безопасность приложения. Выполняя рекомендации, разработчик не должен тратить дополнительное время для обеспечения безопасности там, где нормативы уже выполнены. Это снижает вероятность появления ошибок вследствие невнимательности разработчика, и снижает общую стоимость приложения за счет того, что большую часть работы не нужно выполнять просто потому, что она уже выполнена.

Каким образом Next Framework обеспечивает высокую производительность и устойчивость к высоким нагрузкам

Высокая производительность обеспечивается благодаря комплексу мер.

Таким образом, Next Framework делает максимум работы для того, чтобы снизить фактическую нагрузку на сервер.

За счет чего Next Framework позволяет разрабатывать приложения быстрее

Почему Next Framework? Название, назначение и историческая справка

С момента появления Ruby on Rails появилось немало фреймворков и новых языков программирования, которые позволяли решать старые задачи более эффективно, чем обычно. Под эффективностью в первую очередь подразумевается снижение фактических затрат при разработке. В первую очередь речь идет о временном ресурсе, поэтому все удачные фреймворки ориентированы на более высокую скорость разработки при их использовании.

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

Таким образом, фактическое увеличение эффективности не было значительным. Другие улучшения более касались теоретических задач, нежели чем практики, и поэтому фактическая ценность также невелика.

Например, при освоении двух популярных фреймворков, которым нет 3 лет от роду на момент написания этого материала, нужно потратить в несколько раз большее время, чем для освоения CodeIgniter. При этом работать с полученным материалом ничуть не легче, и зачастую фактическая стоимость (измеренная во временных затратах и в деньгах) полученного приложения выше, чем при использовании CodeIgniter.

Более красивый, более модный, более эффектная структура — но это дольше разрабатывается, дороже стоит, и сложнее сопровождается? Автор этих строк и множество его коллег озадачиваются вопросом «а зачем это надо?».

В противоположность этому при разработке NF не ставилась цель заново переделывать то, что уже работает и обладает определенными потребительскими характеристиками. Вместо этого задачей было дальнейшее улучшение технического процесса и фактических характеристик продуктов. Поэтому NF является всего-лишь надстройкой над CodeIgniter и jQuery, и на низком уровне не привносит ничего лишнего, кроме некоторых улучшений производительности и персистентности данных, описанных в этом руководстве.

Название Next Framework, буквально означающее «следующий фреймворк», подчеркивает то, что этот продукт не повторяет уже созданное. Задачей Next Framework было дальнейшее развитие технологии программирования. Он ориентирован на решение новых, актуальных задач.

Разработка NF не была отдельным проектом до какого-то времени. Концепция фреймворка существовала задолго до его появления. Автор принимал участие в разработке десятков разнообразных веб-приложений. Любой программист знает, как его удачные решения «кочуют» в виде библиотек от одного проекта к другому, и постепенно улучшаются.

Также развивалась и коллекция библиотек автора. В 2013 году появилась идея концепции действий, в течение двух дней был создан прототип на CoffeeScript, который позволил понять, что реализация концепции возможна. Разработка NF, как самостоятельного проекта, началась в начале 2014 года.

Далее началась большая «черная полоса». Сейчас код NF красив, минималистичен и аскетичен. Простые библиотеки делают то, что нужно, наиболее эффективным образом, не падают и не допускают ошибок. Но для того, чтобы этого достичь, понадобилось 2 года работы. NF стоит несколько дороже, чем автор полагал на момент начала работы над этим проектом. Универсализация, как хороший дизайн — незаметна, но ее отсутствие бросается в глаза, создает большие проблемы, и по факту она стоила огромных денег.

Промежуточные версии библиотек NF имели размер свыше 1000-2000 строк каждая, количество этих библиотек было в несколько раз больше, чем сейчас. В процессе разработки и нескончаемых экспериментов и улучшений количество библиотек и их размер изрядно уменьшились. При этом они делают все, что требуется.

Автор очень признателен Мартину Фаулеру за его труды.

Стратегия разработки приложений с Next Framework

NF позволяет разрабатывать приложения любым из современных способов гибкой разработки.

По умолчанию существует как минимум два варианта стратегии разработки.

Таким образом, Next Framework позволяет разрабатывать приложения с произвольным подходом к этапности.



Тактика разработки приложений с Next Framework

Вернитесь еще раз к прочтению этой главы после изучения справки по компонентам.

Таким образом, для действительно быстрой и беспроблемной разработки приложения с Next Framework, как и с любым другим фреймворком или языком программирования, необходимо подготовиться:

Естественно, делать толстую документацию — не обязательно, если этого от вас не трубет заказчик. Множество прекрасных программ было создано, при этом их рабочая документация умещалась на 1-3 листах тетради.

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

Что нужно сделать?

Как показывает опыт, отношение количества кастомных обработчиков к базовым библиотекам NF не превышает 1/5.

Использование Next Framework совместно с другим кодом CodeIgniter или другими приложениями или фреймворками

Есть несколько простых и доступных способов для такого использования.

Устройство фреймворка

К сожалению, компоненты фреймворка не являются слабосвязными. Это позволило сделать их код минималистичным, и даже изящным. Зато слабосвязной является бизнес-логика. Никто не ограничивает вас в функциональности и других свойствах приложений, которые вы создаете.

Вы можете получить массу преимуществ, выполняя соглашения (см. раздел «Соглашения» этого руководства). Если вы выполняеете соглашения — фреймворк будет выполнять большой объем работы за вас, и вам придется писать еще меньше кода. И, как следствие — меньше времени понадобится на его отладку и дальнейшее сопровождение.

Точкой входа является виртуальный фронт-контроллер. Это буквально файл application/contrullers/virtual.php, который захватывает все HTTP-запросы, и направляет их в библиотеку NF_Action application/libraries/nf_action.php.

Библиотека NF_Action подыскивает декларацию действия, которое необходимо выполнить, в конфигурации бизнес-логики приложения. В найденном элементе конфигурации ищет свойство handler, указывающее на обработчик, который необходимо вызвать для выполнения данного действия. Если обработчик не входит в число базовых компонентов NF, в конфигурации действия должен быть указан параметр handler_library, в который помещается название библиотеки, в котором находится нужный обработчик.

Результат выполнения обработчика возвращается клиенту HTTP (например, в браузер), или в различные API, включая внутренние API (обмен данными в формате ассоциативных массивов и объектов) и внешние API (JSON, JSONP, XML, XML/RPC и т. д.).

Название действия, запрашиваемого через HTTP, должен быть указан в первом сегменте URI. В других сегментах указываются дополнительные данные. Например, идентификатор, слаг, смещение для пагинации и другие необходимые сведения.

Для необязательного получения SEO-оптимизации можно генерировать ссылки с опциональными данными в URI. Например, «расширения файлов» .php, .html, .png, .pdf и другие, использование ЧПУ слагов и тому подобное.

Действия

Понятие действий является ключевым понятием данного высокоуровневого фреймворка. Изначальное действие — это то, что совершает, может или хочет совершить пользователь, при работе с программой.

Например, получить элемент, список, создать, редактировать, удалить или восстановить что-либо, и тому подобное.

Все действия, которые выполняет программа, описываются в конфигурации бизнес-логики приложения.

Контекстные действия

Контекстные действия вызываются из шаблонов, с помощью специального тега {context.action_name}, где action_name — название действия, которое нужно выполнить. Также контекстные действия могут быть указаны в параметрах callback, tags, и других параметрах для различных обработчиков.

Примечание. Действия, указанные в параметрах success и cancel не могут быть контекстными, так как напрямую доступны клиенту через HTTP.

Контекстные действия, в сочетании с адаптивным доступом, являются основным средством для построения фактической бизнес-логики приложения.

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

Например, если нам нужно получить список постов конкретного пользователя в блоге.

Таким образом, в конфигурации бизнес-логики приложения должно быть определено два действия:

Другой пример — добавление или редактирование элемента.

При этом после добавления или редактирования элемента нужно произвести рекалькуляцию (пересчет) счетчиков в родительских сущностях, и некоторые специальные действия, например автоматическую отправку личных сообщений автору записи родительской сущности («получен ответ на заказ», «отправлен новый комментарий» и т. п.).

Создаются два действия.

Другие примеры будут приведены ниже.

Для того, чтобы защитить контекстные действия от вызовов напрямую клиентом, нужно в их конфигурацию добавить параметр context_only со значением TRUE.

Адаптивный доступ

Если действие оперирует одним конкретным элементом, имеющимся или идентифицированным и хранящимся в БД, возможно использовать функцию адаптивного доступа.

Адаптивный доступ позволяет изменять правила доступа к действию в зависимости от свойств элемента, с которым работает данное действие.

Адаптивный доступ работает по принципу «скорее нет, чем да». Таким образом, вы можете указывать несколько правил адаптивного доступа. Приоритет отдается наиболее строгому из указанных правил. Таким образом, если получен отказ — действие не будет выполнено.

Адаптивный доступ, в сочетании с механизмом контекстных действий, является основным средством для построения бизнес-логики приложений.

Правила адаптивного доступа указываются в параметре adaptive_access, в виде массива, каждый из элементов которого является ассоциативным массивом, со следующими элементами.

Пример:

'adaptive_access' => array(
	array(
		'mode' => 'administrator',
		'rules' => array('user.blocked' => TRUE),
	),
),

Это правило запретит просмотр всем, за исключением администратора, в случае, если пользователь был заблокирован.

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

Структура файлов конфигурации бизнес-логики приложения

Файлы конфигурации бизнес-логики приложения размещаются в директории application/config/appconfig/.

Для того, чтобы файл игнорировался, переименуйте его так, чтобы имя начиналось с прочерка _.

Каждый файл представляет собой условный модуль. В каждом файле сосредоточены действия, которые оперируют только с одной сущностью.

Если вам нужно выполнить действия, связанные с несколькими сущностями, разбейте это действие на несколько, и разместите в разных файлах. В 80% случаев этого делать не придется, как как фреймворк самостоятельно выполняет множество действий за программиста. Примерно в 20% это нужно делать, потому что приложения отличаются друг от друга, и это нормально.

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

$config['settings'] = array(
	'module' => 'user',
	'entity' => 'user',
	'views' => 'user/',
	'pagination' => 32,
	'header' => 'index/header',
	'footer' => 'index/footer',
);

Разные модули могут работать с одной сущностью.

В разных модулях могут быть указаны разные поля сущности. В этом случае они будут слиты (объединены в единую таблицу). Это позволяет делать приложения более модульными.

Поля сущности декларируются в массиве entity:

$config['entity'] = array(
	'title' => array(
		'type' => 'string',
		'rules' => 'trim|required', 

		'title' => '{lang.title}',
	),
	'descr' => array(
		'type' => 'fulltext',
		'rules' => 'trim|required', 

		'title' => '{lang.description}',
	),
	'image' => array(
		'type' => 'image',
		'rules' => 'trim',
		'title' => '{lang.poster}',
		'default_value' => '',
		'fileuploader' => 'poster_uploader',
		'template' => 'nf/values/name/bg',
	),
	'rating' => array(
		'type' => 'integer',
	),
	'online' => array(
		'type' => 'integer',
	),
	'total_users' => array(
		'type' => 'integer',
	),
	'topic_count_active' => array(
		'type' => 'integer',
	),
);

Подробное описание свойств полей сущностей смотрите в соответствующем разделе данной документации.

К каждой таблице будут добавлены поля, указанные в параметре default_tables_fields в файле application/config/nf.php. Обычно это типичный набор полей: первичный идентификатор, признак активности («не удалено»), дата создания, дата последней модификации.

Связывание сущностей

Связывание сущностей осуществляется посредством добавления в дочерние сущности полей, содержащих идентификаторы родительских сущностей. Это требование является обязательным.

В сущности, с которым связано дочернее действие, должно быть поле с указанием идентификатора родителя. При этом используется соглашение об именовании: {parent_entity}_id, где {parent_entity} — имя родительской сущности. Это требование является обязательным.

Также есть следующие дополнительные возможности.

В родительскую сущность можно добавлять поля, содержащие сведения о дочерних сущностях — их количество, и последний добавленный элемент. Используются следующие соглашения:

Где {child_entity} - имя таблицы в СУБД, содержащей дочернюю сущность.

NF самостоятельно обслуживает такие поля, инкрементирует и декрементирует поля счетчиков при добавлении, редактировании, удалении и восстановлении элементов. Для поля {child_entity}_last NF будет искать последний добавленный элемент, при удалении - последний неудаленный элемент.в

В дочернюю сущность можно добавлять поле {parent_entity}_is_active, где {parent_entity} - имя таблицы в СУБД, содержащей родительскую сущность. При удалении и восстановлении родительского элемента (при котором происходит изменение значения is_active) NF будет самостоятельно записывать свойство родительского элемента в дочерние записи. Эту денормализацию можно использовать для ускорения выборок.

Приемы работы

Связывание действий «Элемент»—«Элемент»

Два действия, оба типа «Элемент» (Item), но они работают с разными сущностями. Одно действие является родительским по отношению к другому.

Такая связь реализуется системой из двух простых действий:

  1. В сущности, с которым связано дочернее действие, должно быть поле с указанием идентификатора родителя. При этом используется соглашение об именовании: {parent_entity}_id, где {parent_entity} — имя родительской сущности.
  2. В шаблоне (указывается в параметре template родительского действия), указывается дочернее действие, через оператор context. Также есть возможность непосредственно выводить свойства родительского элемента — NF самостоятельно найдет его и получит из кеша NF_Entity.

Пример.

Родительский элемент

Массив настроек

$config['settings'] = array(
	'module' => 'parent', // *
	'entity' => 'parent_entity', // **
);

* не принципиально, используется для более удобног формирования ссылок и идентификации модуля в служебных целях

** название таблицы в СУБД, например 'forum_div'.

Действие

$config['actions']['parent_item'] = array(
	'access' => 'all',
	'handler' => 'item',
	'template' => 'parent/item.php'
);

Содержание файла application/views/parent/item.php:

{.title}
{context.child_item}

Параметр $entity передается автоматически, из массива настроек модуля. В данном случае он будет содержать значение 'parent_entity'.

Потомок

Массив настроек

$config['settings'] = array( 'module' => 'child', // * 'entity' => 'child_entity', // ** );

* не принципиально, используется для более удобного формирования ссылок и идентификации модуля в служебных целях

** название таблицы в СУБД, например 'forum_topic'.

Поля сущности

$config['entity'] = array(
	'title' => array('type' => 'string'),
	'parent_entity_id' => array('type' => 'pid'), // *
);

* - важно, используется соглашение об именовании ключей на родительские сущности.

Действие

$config['actions']['child_item'] = array(
	'access' => 'all',
	'handler' => 'item',
	'template' => 'child/item.php'
);

Содержание файла child/item.php не принципиально, в нем могут содержаться сведения из таблицы 'child_entity' и других связанных аналогичным образом сущностей.

Связывание действий «Элемент»—«Список»

Два действия, родительское типа «Элемент» (Item), дочернее типа «Список» (Listing). Действия работают с разными сущностями. Одно действие является родительским по отношению к другому.

Такая связь реализуется системой из трех простых действий.

  1. В сущности, с которым связано дочернее действие, должно быть поле с указанием идентификатора родителя. При этом используется соглашение об именовании: {parent_entity}_id, где {parent_entity} — имя родительской сущности.
  2. В шаблоне родительского действия (item) указывается ссылка на контекстное дочернее действие (listing), через оператор context. Например: {context.child_listing_context}.
  3. В параметре filters дочернего действия (со списком) указывается критерий для выборки '{parent_entity}_id' => 'pid'.

NF самостоятельно подставит первичный идентификатор родительского элемента вместо ключевого значения 'pid'.

Пример.

Родительский элемент

Массив настроек

$config['settings'] = array(
	'module' => 'parent', // *
	'entity' => 'parent_entity', // **
);

* не принципиально, используется для более удобного формирования ссылок и идентификации модуля в служебных целях

** название таблицы в СУБД, например 'forum_div'.

Действие

$config['actions']['parent_item'] = array(
	'access' => 'all',
	'handler' => 'item',
	'template' => 'parent/item.php'
);

Содержание файла application/views/parent/item.php:

{.title} {context.child_item_listing}

Параметр $entity передается автоматически, из массива настроек модуля. В данном случае он будет содержать значение 'parent_entity'.

Потомок

Массив настроек

$config['settings'] = array(
	'module' => 'child', // *
	'entity' => 'child_entity', // **
);

* не принципиально, используется для более удобного формирования ссылок и идентификации модуля в служебных целях

** название таблицы в СУБД, например 'forum_topic'.

Поля сущности

$config['entity'] = array(
	'title' => array('type' => 'string'),
	'parent_entity_id' => array('type' => 'pid'), // *
);

* - важно, используется соглашение об именовании ключей на родительские сущности.

Действие

$config['actions']['child_listing_context'] = array(
	'access' => 'all',
	'handler' => 'listing',
	'filters' => array('parent_entity_id' => 'pid'), // *
	'template' => 'child/listing_context.php'
);

* позволяет формировать условие выборки SELECT * FROM `child_entity` WHERE `parent_entity_id` = {pid}.

NF самостоятельно подменит ключевую фразу pid на идентификатор родительского элемента.

Можно указывать и другие дополнительные параметры для управления выборкой, в соответствии с разделом «Listing» настоящего руководства.

Содержание файла child/item.php не принципиально, в нем ДОЛЖЕН присутствовать форматированный список {listing} {/listing}, внутри которого могут содержаться произвольные сведения из таблицы 'child_entity' и других связанных сущностей.

Быстрый обзор библиотек и моделей

Код библиотек документирован комментариями.

NF_Action

Содержит два метода — make_action() и get_action(), которые позволяют выполнять действие и получать его конфигурацию. В обоих методах выполняется соответствующая рутина.

NF_Template

Работает с шаблонами. Выполняет кеширование.

NF_Item

Позволяет показать один элемент. В том числе один элемент списка.

NF_Listing

Позволяет показывать список элементов.

NF_Add

Типовой сценарий для добавления элементов.

NF_Edit

Типовой сценарий для редактирования элементов.

NF_Trigger (и псевдообработчики enable и disable)

Позволяет переключать бинарные состояния свойств элементов.

NF_Fileuploader

Интерфейс для загрузчика файлов Fineuploader.

Image_processing

Интерфейс для обработки изображений.

NF_Pass_login

Типовой сценарий для авторизации через почту и пароль.

NF_Search

Простой интерфейс для поиска по поисковому кешу.

PM

Библиотека для функции личных сообщений.

Низкоуровневые библиотеки и модели

NF_Entity

Большая библиотека для работы с данными в БД.

NF_Agreement — соглашения

Напоминалка для соглашений. Позволяет NF_Entity выполнять больше рутинных действий за программиста.

NF_Button

Делает кнопки.

NF_Imagick

Интерфейс для php5-imagick

NF_Install и NF_Install_scenario

Установка вебаппа.



NF_Online

Отмечает пользователя онлайн.

NF_Set_id

Интерфейс для записи идентификаторов и временных меток.

NF_Template_generate

Разбирает большие шаблоны на маленькие.

NF_Template_processing

Предпросмотр и список файлов тем

NF_Value

Подбирает значения для отображения и формы числительных.

NF_Webapp

Набор алисасов, чтобы не писать параметр handler_library для наиболее часто используемых библиотек.

NF_Appconfig

Загружает конфигурацию вебаппа, разбирает настройки, сущности и действия.

NF_Identifier

Извлекает идентификаторы и элементы.

NF_Installed

Сообщает, что вебапп установлен.

NF_Search_cache

Формирует поисковый кеш.

NF_User

Простая авторизация. Поддерживает куки, а также другие способы авторизации.

NF_User_auth

Содержит функцию «Выход».

Живой интерфейс NF_Update

Подготавливает пачки данных для живого JS-интерфейса.

Вопросы и предложения

Можно направить на адрес: arint, потом традиционный знак и arint.ru