Как определить контекст, в котором находится объект ColdFusion?
Итак, учитывая, что у меня есть экземпляр этого компонента:
foo.cfc
<cfcomponent>
<cffunction name="locateMe">
<cfreturn "I don't know where I live!">
</cffunction>
</cfcomponent>
И этот другой компонент, fooParent.cfc:
<cfcomponent>
<cfset this.foo = createObject("component", "foo")>
</cfcomponent>
Скажем, я создаю экземпляры "foo" несколькими разными способами:
<cfset myStruct = {}>
<cfset myStruct.foo = createObject("component", "foo")>
<cfset myFoo = createObject("component", "foo")>
<cfset myFooParent = createObject("component", "fooParent")>
<cfoutput>
#myStruct.foo.locateMe()#<br>
#myFoo.locateMe()#<br>
#myFooParent.foo.locateMe()#<br>
</cfoutput>
Как и ожидалось, это выдает:
I don't know where I live!
I don't know where I live!
I don't know where I live!
Что я хочу знать, что я могу сделать в foo.cfc, который расскажет мне что-нибудь (что-нибудь!) о контексте, в котором он вызывается? Поскольку все в конечном итоге живет (по крайней мере) в какой-то области, и все области являются своего рода объектом, я говорю, что мне действительно хотелось бы каким-то образом определить содержащийся объект изнутри экземпляр объекта. В конечном счете, какой-то способ построения foo.cfc, так что что-то вроде этого может быть моим результатом, из моего примерного фрагмента выше:
I live within a "class coldfusion.runtime.Struct" instance!
I live within a "class coldfusion.runtime.VariableScope" instance!
I live within a "component cfjunk.fooParent" instance!
Если каждое из этих значений можно определить, проверив результат, передав getMetaData
фактическую содержащую ссылку на объект.
Обновление Как было предложено Micah в комментариях, я добавил к этому тег Java, так как я подозреваю, что он может быть прав в том, что решение может заключаться в использовании Java для самоанализа.
Update
Вместо того, чтобы оставлять это как то, что кажется чисто академическим обсуждением, позвольте мне объяснить, зачем мне это нужно.
Я использую CFWheels ORM с включенными для возврата ссылок на мои данные следующим образом:
var user = model("User").findOne(where="id=123", include="AuthSource", returnAs="object");
Это вернет мне объект, который я могу ссылаться так:
user.id // property of the "User" model
user.reset() // method on the "User" model
user.AuthSource.id // property of the "AuthSource" model
user.AuthSource.authenticate(password) // method on the "AuthSource" model
Теперь, в моем методе "AuthSource.authenticate", я хотел бы узнать о объекте "Пользователь", в котором я содержался. В противном случае мне придется вызвать функцию следующим образом:
user.AuthSource.authenticate(user, password) // note the redundancy in the use of "user"
Я должен быть в состоянии полагаться на то, что я вызываю метод в модели AuthSource через объект User и фактически читаю с этого объекта из этого метода.
Ответы
Ответ 1
Это было очень долгое время с тех пор, как я сделал coldfusion, так что простите мой псевдокод, но я думаю, что то, что обычно делается в подобных случаях, заключается в том, что родитель отправляет экземпляр самой себя ребенку, когда он создает экземпляр ребенок. Это используется во многих шаблонах проектирования ООП, где два объекта должны взаимодействовать друг с другом в обоих направлениях, а не только родительские методы вызова для дочернего элемента.
поэтому ваш дочерний класс будет определен как нечто подобное:
<cfcomponent>
<cffunction name="init">
<cfargument name="parentParam" required="yes" type="object">
<cfset this.parent = parentParam >
<cfreturn this>
</cffuncton>
<cffunction name="locateMe">
<cfreturn "I belong to #this.parent.className# !">
</cffunction>
<cffunction name="doOtherStuff">
<cfreturn "I do stuff with my parent: #this.parent.className# !">
</cffunction>
</cfcomponent>
а затем, когда вы его используете...
<cfset myParent.child = createObject("component", "Object").init(myParent) />
#myparent.locateMe()#
#myparent.doOtherStuff()#
parentParam будет обязательным параметром в методе конструктора под названием "init", поэтому у ребенка всегда есть ссылка на его родителя. Тогда все ваши методы могут использовать this.parent, чтобы делать с ним вещи. В моем примере кода я делаю # this.parent.className #, но понятия не имею, что объекты coldfusion обладают таким свойством. Вероятно, вы можете использовать какое-то отражение или мета-программирование, чтобы сделать то же самое.
Обратите внимание: из того, что я собираю, у coldfusion нет поддержки для встроенных конструкторов, поэтому я показываю, что вы - лучшая практика сообщества на этом сайте:
http://www.iknowkungfoo.com/blog/index.cfm/2007/8/22/Object-Oriented-Coldfusion--1--Intro-to-Objectcfc
Мне жаль, что вы делаете колфлюс, кстати...;)
Ответ 2
Я удалил все предыдущие, поскольку это не помогло. Следуя вашим последующим комментариям, следующее предложение, которое, я полагаю, может быть более похоже на то, что вы пытаетесь сделать.
// Object
<cfcomponent displayname="Object">
<cffunction name="init">
<cfargument name="username" type="string">
<cfscript>
variables.username = arguments.username;
variables.authSource = CreateObject('component','AuthSource').init();
</cfscript>
<cfreturn this>
</cffunction>
<cffunction name="authenticate">
<cfargument name="password" type="string">
<cfreturn variables.authSource.authenticate(variables.username,arguments.password)>
</cffunction>
</cfcomponent>
<cfcomponent displayname="AuthSource">
<cffunction name="init">
<cfreturn this>
</cffunction>
<cffunction name="authenticate">
<cfargument name="username" type="string">
<cfargument name="password" type="string">
.... DO STUFF ...
<cfreturn ...>
</cffunction>
</cfcomponent>
<cfscript>
objUser = CreateObject('component','Object').init('SomeUserName');
// Authenticate
objUser.authenticate('SomePassword');
</cfscript>
Таким образом, AuthSource не нужно знать о родительском объекте, однако в то же время кому-то, кто аутентифицируется, не нужно снова вводить имя пользователя. Объект (родительский объект) имеет метод обертки для аутентификации, который добавляется в имя пользователя.
Это какая-то дополнительная помощь?
Ответ 3
Я знаю, что это не актуально прямо сейчас, но в следующей версии CF (Zeus) есть функция, чтобы сделать это http://blogs.adobe.com/coldfusion/2011/12/19/coldfusion-zeus-potr-callstack/.