Использование CFC - ColdFusion компоненты
Часть 1:
Чтобы понять CFC, следует немного разобраться в том, что такое объекты. Но сперва необходимо определить - CFML не является объектно-ориентированным языком, а CFC не предоставляют все возможности ООП языков. На самом деле это не так уж и плохо. Объекты слишком долгое время были эксклюзивным свойством и синтаксическими правилами языков, что привело к излишнему их усложнению. Для разработчиков, использующих язык быстрой разработки приложений (такой как CFML), также нет причин не использовать объекты, но под другим названием - CFC.
Говоря простым языком, объекты - это многократно используемые участки кода. Они как черный ящик волшебника, который делает все, что вы только пожелаете. Такая формулировка напоминает вам о пользовательских тегах (Custom Tags) и это правильно, т.к. объекты действительно похожи на пользовательские теги, но с гораздо большими возможностями. Например в них может быть не только код (как в пользовательских тегах), но и данные. Объекты обычно имеют несколько входных значений (методов). Они имеют механизм автоматического определения, какой код должен быть обработан, в зависимости от полученных входных данных.Объекты, без изменения или удаления своего кода, могут быть адаптированы под разные нужды.
Принцип использования объектов
Почти все ColdFusion разработчики делали приложения для управления пользователями, в которых было:
- Использование <cfquery> для проверки имени и пароля пользователя;
- Использование полученных результатов запроса, чтобы узнать имя или email пользователя;
- Использование проверок уровня доступа пользователя к тем или иным возможностям приложения;
- Сохранение и чтение таких личных настроек пользователя, как, например, цвет, шрифт, язык и т.п.;
- Добавление новых пользователей и обновление информации о уже существующих;
- и т.д.
Делая такое приложение, сколько раз вам приходилось обращаться к пользователю за той или иной информацией? Сколько раз методом "копировать-вставить" вам приходилось использовать одни и те же части кода? Что произойдет, если будет изменена таблица в базе данных и сколько кода придется отредактировать в связи с этим изменением? Что, если база данных будет полностью заменена на LDAP сервер или к базе данных будут применены новые наборы правил? Сколько придется не программисту узнать о внутреннем строении приложения по управлению пользователями, чтобы просто отобразить персонализированное сообщение приветствия?
С использованием объектов, вы можете создавать свои приложения совсем по-другому. Достаточно будет создать пользовательский объект - магический черный ящик, который сам будет заботится о всех операциях с пользователями.
Для осуществления каких-либо операций над пользователем, нужно будет использовать объект с указанным ему id этого пользователя. Затем вы можете использовать примерно такие методы (функции), названия которых говорят сами за себя:
Add();
Delete();
Update;
Get();
VerifyPassword();
GetEmail();
GetColorPrefs();
GetDisplayName().
Идея заключается в том, что все операции проходят скрыто от вас внутри объектов. Вам даже не нужно беспокоиться о том, в каких таблицах находятся данные.Вы просто вызываете функцию и получаете требуемый результат.
Такая функциональность приложения возможна с использованием CFC.
Общая информация о CFC
Теперь мы знаем, что такое CFC и давайте узнаем, как их создают. А создавать их не просто, а очень просто. Для этого нужно проделать два действия:
- Создать файл с расширением .cfc (этим они отличаются от обычных шаблонов ColdFusion, которые имеют расширение .cfm);
- Использовать четыре новых для CFMX тега:
<cfcomponent> - определяет компоненту;
<cffunction> - определяет функцию (метод) внутри компоненты;
<cfargument> - определяем аргументы (параметры) функции;
<cfreturn> - возвращает значение или результат работы функции.
Помимо этих четырех тегов, CFC может содержать все, что может быть в обычном CFML файле: теги, функции, пользовательские теги, компоненты и т.д.
Создаем компоненту
В Листинге 1 приведен пример простейшей компоненты, которая осуществляет классическое определение браузера пользователя.
Это упрощенная версия файла browser.cfc. Как видите, весь код заключен между пары тегов <cfcomponent> и </cfcomponent>. Сама компонента содержит только одну функцию "IsIE", которая обозначена тегом <cffunction>. Внутри этой функции определяется переменная result и, если у пользователя браузер Internet Explorer, то эта переменная принимает значение "Yes", а если нет, то "No". Тег <cfreturn> возвращает значение переменной result.
Как этот код можно использовать? Сохраните его в файл browser.cfc и в той же директории создайте файл test.cfm, в котором будет следующий код:
<cfinvoke> - новый для CFMX тег, одним из назначений которого является вызов методов компоненты. Как видим, тег <cfinvoke> использует только имя файла (без расширения .cfc) как имя компоненты, а также метод, который следует задействовать. Чтобы получить доступ к возвращаемым данным, используем атрибут RETURNVARIABLE, который обозначает переменную, содержащую возвращаемые данные.
Попробуйте запустить этот код и посмотреть на результат.
Создаем полноценную компоненту
Теперь, когда вы знаете как работает CFC, взгляните на Листинг 2 - полная версия файла browser.cfc. Эта версия включает в себя дополнительные возможности.
Тег <cfcomponent> теперь содержит четыре метода:
- IsIE - проверяет наличие браузера IE и возвращает значение "yes" или "no";
- IsNatscape - проверяет наличие броузера Natscape и возвращает значение "yes" или "no";
- IsDreamweaver - проверяет наличие броузера Dreamweaver и возвращает значение "yes" или "no";
- Identify - проверяет наличие всех трех браузеров, возвращая "IE", если это IE, "NS" - Natscape, "DW" - Dreamweaver, а также пустую строку, если тип браузера не известен.
К каждому тегу <cffunction> добавлены два атрибута:
- returntype - определяет тип возвращаемых данных. Используется для проверки правильности возвращаемых данных (если тип данных не правильный, то получим сообщение об ошибке) и для документирования функции;
- hint - текстовое описание, используемое для документирования компоненты (об этом пойдет речь чуть позже).
Каждая функция содержит тег <cfargument>, который проверят присутствие необходимого параметра и может быть использован одним из двух способов:
- проверять наличие обязательного параметра, обозначив required="yes"; если требуемый параметр не определен, то мы получим ошибку. Дополнительно можно обозначить проверку типа требуемого параметра, указав атрибут type.
- проверять наличие необязательного параметра, обозначив required="no" и атрибут default, в котором будет указано значение параметра, если он не определен.
Во всех четырех функциях тег <cfargument> проверяет наличие необязательного параметра browser, позволяя передавать в компоненту любое его значение. Если параметр browser не определен, то ему присваивается значение CGI переменной.
Первые три функции одинаково похожи на ту, что мы рассмотрели при создании упрощенной версии файла browser.cfc, но есть еще и четвертая функция, которая отличается тем, что определяет вид браузера с помощью первых трех функций. Заметьте, что мы не копировали в четвертую функцию код первых трех, а только вызывали их, но без использования <cfinvoke>, т.к. все функции находятся в одном и том же документе.
В Листинге 3 показан код, который вызывает нашу компоненту. Вставьте его в файл test.cfm и протестируйте.
Документирование компонент
Как я уже упоминал, атрибуты hint и returntype используются для документирования компонент. Что это означает?
Допустим, что к вам попала в руки готовая компонента, созданная кем-то другим, и вам нужно просмотреть ее описание (возможности) не разбираясь в коде. Сделать это можно одним из двух способов:
- вызвать файл cfc напрямую через адресную строку браузера (например, http://localhost/path/browser.cfc). В ответ ColdFusion сгенерит хорошо оформленную страницу с описанием данной компоненты. Часть полученного описания будет взята и из атрибутов hint.
- если вы используете Dreamweave MX, то откройте панель Application/Components/ и из выпадающего меню выберите пункт CF Components. DWMX просканирует весь сайт и отобразить все найденные компоненты в виде древовидной структуры. Вы можете на любом из них щелкнуть правой кнопкой мыши и в появившемся меню выбрать определенные действия: отредактировать код, просмотреть описание и т.п.
Документировать компоненты следует не только для других людей, которые будут пользоваться ими, но и для самого себя, чтобы спустя некоторое время легко сориентироваться в них
Листинг 1:
Листинг 2:
Листинг 3:
Часть 2:
Как передать атрибут в функцию компоненты?
В рассмотренном выше примере мы говорили, что каждая функция компоненты содержит тег <cfargument>, который, в нашем случае, проверяет присутствие необязательного параметра browser. То, что параметр необязателен говорит нам о том, что мы можем передавать в эту функцию и свои значения параметра. Как это сделать?
Существует два способа передачи аргумента в функцию компоненты:
- добавить аттрибут в тег <cfinvoke>:
<cfinvoke component="browser" method="IsIE" returnvariable="result" browser="#browserid#">
- указать тег <cfinvokeargument> между тегами <cfinvoke> и </cfinvoke>:
<cfinvoke component="browser" method="IsIE" returnvariable="result">
<cfinvokeargument name="browser" value="#browserid#">
</cfinvoke>
Второй способ дает больше возможностей, т.к. тег <cfinvokeargument> может быть указан при определенных условиях или внутри <cfloop>. Тем не менее, оба варианта выполняют одну и ту же задачу и могут быть использованы по вашему усмотрению.
Альтернативные способы вызова компоненты
Тег <cfinvoke> предоставляет простой способ вызова методов компоненты. но он далеко не единственный.
Множество вызовов тега <cfinvoke> одной и той же компоненты будут осуществляться отдельно друг от друга. Это означает, что обработка кода внутри компоненты (например, определение переменных) будет происходит для каждого вызова отдельно.
Предположим, что вы создали компоненту "user", которую вы затем вызываете, чтобы получить имя и email пользователя. Ваш вызов может выглядеть так:
Заметьте, что мы передаем ID в каждом вызове, т.к. второй вызов идет отдельно от первого. К тому же, поиск компоненты user происходит тоже два раза.
Более подходящим решением в такой ситуации будет использование тега <cfobject>:
Таким образом, тег <cfobject> загружает компоненту в объект (название которого указано в атрибуте name). Затем мы вызываем методы из только что созданного объекта.
Первый вызов обращен к методу Init и передает ему параметр ID. Последующие два метода не требуют ID, т.к. используемому нами объекту он уже известен. Более того, например, получение внутри компоненты имени пользователя будет происходить также только один раз, а не при каждом ее вызове.
Тот факт, что CFC можно рассматривать как объекты, открывает перед нами еще одну интересную возможность. В отличие от пользовательских тегов (Custom Tags), объекты можно использовать внутри тегов <cfscript>. Это возможно благодаря существованию функции CreatObject(). Пример:
Как видите, компоненты можно использовать как объекты и синтаксис <cfscript> особенно полезен для тех, кто работал с объектами в других языках.
Кроме того, есть и другие методы вызова CFC файлов:
- в html формах в атрибуте action можно ссылаться на файл cfc;
- cfc файлы можно вызывать через URL, дополнительно передавая в них параметры через тот же URL;
- с помощью ActionScript (используя функции NetServices) в Flash MX можно вызывать методы компонент;
- компоненты могут использоваться как веб службы (Web services).
Хорошо написанные компоненты могут быть использованы в очень многих ситуациях. Как правило, код внутри компонент не должен быть ориентирован на какое-то конкретное приложение и зависеть от того, из какого приложения они вызываются.
Использование контейнера this
Посмотрите на обрабатываемый код - если ID пользователя передается методу компоненты при первом ее вызове, то как методы остальных вызовов уже знают этот ID?
Чтобы объяснить это, посмотрите на файл user.cfc в Листинге 1. Вы сразу заметите участок кода, который не относится ни к одной функции:
Любой код, который не относится ни к одной функции, автоматически обрабатывается при первой загрузке компоненты. Данная строка кода устанавливает метку - переменная initialized равна false. Эта переменная будет находиться внутри контейнера this - особый контейнер внутри компоненты. После того, как переменная initialized будет помещена в контейнер this, она будет доступна последующим вызовам методов этой компоненты.
Первый метод - Init, требует получения ID пользователя. Затем эта функция, используя полученный ID и тег <cfquery>, получает информацию о пользователе. Если информация получена, значит ID правильный и помещается в контейнер this, а значение переменной initialized устанавливается в значение true.
Остальные две функции возвращают данные. Функция GetFullName возвращает полное имя пользователя (объединяя его имя и фамилию). Функция GetEMail возвращает email пользователя. Оба метода сначала проверяют, равна ли переменная this.initialized true (если нет, то функцию Init еще не вызывали и информации о пользователе нет) и возвращает информацию, полученную из сохраненной переменной this.UserRec. Таким образом, для получения этих данных, не нужно каждый раз делать запрос к базе данных.
Конечно, компонента user требует доработки - возможно следует добавить операции add, update, delete, search и т.п., но это уже в ваших руках.
Продолжительность жизни компоненты
Поскольку компонента может быть загружена в стандартную переменную (контейнер variables), то также она может быть загружена и в контейнер session или application. Вот пример:
Просто, не правда ли? Теперь вы можете вызывать метод внутри объекта, который в свою очередь находится внутри контейнера session:
То же самое можно проделать и для контейнера application. Объект (и контейнер this внутри него) будет существовать пока существует контейнер.
Использование наследования
Тема наследования - это тема, требующая отдельного обсуждения, а здесь мы рассмотрим только основы.
Вы создали объект user (файл user.cfc), который проводит операции с пользователями. Теперь вам нужен объект administrator, который включает в себя все возможности объекта user плюс еще что-то. Вместо того, чтобы копировать весь код из файла user.cfc в файл administrator.cfc, вы можете создать такую компоненту:
Атрибут extends создает наследование. Таким образом, все, что внутри компоненты user будет доступно в компоненте administrator (даже контейнер this). Также внутри компоненты administrator вы можете:
- создавать дополнительные методы, доступные только внутри компоненты administrator;
- создавать в компоненте administrator методы с таким же именем, как и в компоненте user. Тем самым вы переопределите унаследованные методы.
Создание веб служб (Web services)
Веб службы являются следующим поколением в распространении компьютерных сетей. Веб службы позволяют осуществлять удаленную обработку данных, т.е. хост делает запрос удаленному серверу, который в свою очередь обрабатывает его и возвращает результат.
Веб службы не являются изобретением ColdFusion. Это технология, которую поддерживают и ColdFusion и .NET и J2EE, и которая объединяет несколько ключевых технологий, являющихся открытыми и стандартными:
- HTTP;
- XML;
- SOAP (Simple Object Access Protocol);
- WSDL (Web Services Description File);
- UDDI (Universal Description, Duscovery and Integration).
ColdFusion MX позволяет работать с веб службами невероятно просто - следует использовать уже знакомый нам тег <cfinvoke>. Не будем говорить об этом подробно, а просто рассмотрим как создавать из в ColdFusion MX.
Чтобы создать веб службу, следует всего-лишь добавить в тег <cffunction> следующее:
И все! Методы с таким атрибутом доступны с других серверов. ColdFusion позволяет получать к ним удаленный доступ и сам "на лету" генерит требуемый для этого wsdl файл.
Меры безопасности
Следует затронуть последнюю тему - безопасность. Пользовательские теги не не нуждаются в необходимых мерах безопасности, т.к. они доступны только локально. Но CFC доступны удаленно как веб службы и должны быть скрыты от неавторизированного доступа. Как это сделать?
CFC имеют две опции безопасности, которые могут использоваться как вместе, так и в отдельности:
- в каждом методе можно указать необязательный аттрибут access. По-умолчанию он равен public, что позволяет получать доступ к методам только локально (как к пользовательским тегам). Чтобы сделать компоненты доступными удаленно, то следует указать access="remote";
- методы также имеют ассоциативные роли - roles - группы пользователей. Т.е. чтобы вызвать метод, пользователь должен быть авторизирован в определенной группе пользователей. По-умолчанию никакие роли не используются, но при необходимости этот механизм может предоставлять и запрещать доступ к тем или иным методам, основываясь на информации об авторизации.
Таким образом, по-умолчанию компоненты безопасны как пользовательские теги. Но если вам нужны более строгие меры безопасности, то все в ваших руках - смотрите, изучайте, пробуйте.
Листинг1:
Заключение
Как видим, ColdFusion компоненты невероятно мощный и гибкий инструмент. Они предоставляют мощь объектов, сохраняя при этом простоту CFML, могут быть загружены разными способами и доступны как веб службы. CFC - новое средство разработки ColdFusion приложений, которое обязательно должно быть востребованным. Изучайте и используйте их, чтобы перейти на качественно новый уровень.
Источник: Using ColdFusion Components Часть1, Часть 2
© 2002-2005 г. Вадим Пушкарев