I am working on a Mura plugin that uses a mura tag to pull in a component and use it on the page. Essentially my plugin needs to call $.dspObject('component',Arguments.componentid). Since the mura scope isn't available within the plugin method then I am guessing that I need to pull in a component bean, but I have no idea how to do that.
<cffunction name="showPlayer" access="public" output="false" returntype="String">
<cfargument name="component" type="string" required="true" hint="The ID of the component that contains the playlist." />
<!--- Create the body content --->
<cfsavecontent variable="bodycode">
<cfoutput>#$.dspObject('component',Arguments.component)#</cfoutput>
</cfsavecontent>
</cffunction>
That is a very stripped down version of the method (the full eventHandler can be found on GitHub.
So how would I rewrite my code to pull the component bean out (or whatever I need to do for it)?
There are several ways possible:
<cfargument name="$">
OR
var $=application.ServiceFactory.getBean(“muraScope”);
OR
var $=getServiceFactory().getBean(“muraScope”);
OR
var $=getBean(“muraScope”);
See MuraCMS Programmers Guide and cfobject.cfc
Related
I recently installed ColdFusion 2018 at work and have been frustrated by the inability to get scope working correctly. As usual I put all my .cfcs into the /CFC folder, and none of them will execute without a blank application.cfm file in that folder. I have tried extending application, including application, proxy extending application, moving the CFCs to the root folder only gets me syntax error on JSON. I have read every article that I can find for the past two weeks and I am still unable to understand why scope will not work. It seems I can set session variables within the /CFC folder, but they are not available outside the folder? I have not worked with CF for a few years, but consider myself versed, and for the life of me cannot get this working. its probable that I am missing the forest due to trees, but if anyone would be willing to assist, I would be grateful.
instantiated object;
application.SessionMgr = CreateObject(this.obj,'CFC.SessionMgr').init('session');
proxy call;
cfajaxproxy cfc="CFC/SessionMgr" jsclassname="SessionMgr";
return is correct;
var s = new SessionMgr();
var setReport = s.setValue('ReportID', document.getElementById('cboReportKey').value);
alert(setReport);
however even manually setting session.ReportID = 7 will not persist outside the folder.
here is the SessionMgr.init
this is the init;
<cffunction name="init" access="public" returntype="SessionMgr" output="no" hint="I instantiate and return this object.">
<cfargument name="scope" type="string" required="yes">
<cfargument name="requestvar" type="string" default="SessionInfo">
<cfset var scopes = "application,Client,Session">
<cfif Not ListFindNoCase(scopes, arguments.scope)>
<cfthrow message="The scope argument for SessionMgr must be a valid scope (#scopes#)." type="MethodErr">
</cfif>
<cfset variables.scope = arguments.scope>
<cfset variables.requestvar = arguments.requestvar>
<cfset updateRequestVar()>
<cfreturn this>
</cffunction>
and the setValue fn
<cffunction name="setValue" access="remote" hint="I set the value of the given user-specific variable." returntype="string">
<cfargument name="variablename" type="string" required="yes">
<cfargument name="value" type="any" required="yes">
<cfset var val = arguments.value />
<cfset SetVariable("#arguments.variablename#", val) />
<cfset r = Evaluate(arguments.variablename) />
<cfreturn r />
</cffunction>
ok, after trying everything, heres the solution. extending by proxy doesnt work for this situation, tried that. What finally worked was creating an application.cfc IN the /CFC folder and stripping out all functional components from the /root application.cfc and simply ensuring the application name was the same in the stripped down version in /CFC folder as the /root cfc name. This apparently psuedo extends all the functionality from the /root application.cfc and makes everything available to the framework in the /CFC folder. Thanks to everyone here helping to get me to think outside my wheelhouse and resolving this issue.
I am learning Framework1 and tried to do a simple ColdFusion program to insert data into database after submitting a form.
My simple form person.cfm is in views/main
<form name = "savePerson" action="#buildurl('person')#" method="post">
In the form action I put controller person.cfc
I have person.cfc in controllers folder with code in the component
<cffunction name="person">
<cfif isDefined("rc.savePerson")>
<cfset variables.services.person.savePerson()>
</cfif>
</cffunction
and SQL insert statement in person.cfc with function name = savePerson in the services folder.
Application.cfc has code
function setupApplication() {
var bf = new framework.ioc( "services" );
setBeanFactory( bf );
}
When I submit the form I get the error below
Original exception in onRequest
The action person.person failed.
Element SERVICES.PERSON is undefined in a Java object of type class [Ljava.lang.String; referenced as ''
(Expression)
but there is a person.cfc in controllers, services. I don't know if I need a beans folder.
My question is what should I write for form action and how Framework1 will call the file in services folder to run insert statement via controller?
I have a feeling you might be missing get/set to the Person Service. Also make sure you've got the service declared in the beans.xml.cfm
controllers/person.cfc
<cffunction name="setPersonService" access="public" output="false">
<cfargument name="personService" type="any" required="true" />
<cfset variables.personService = arguments.personService />
</cffunction>
<cffunction name="getPersonService" access="public" returntype="any" output="false">
<cfreturn variables.personService />
</cffunction>
assets/config/beans.xml.cfm
<bean id="personService" class="myapp.services.Person" singleton="true">
</bean>
Edit: Oh I just realised this question was answered on the FW/1 groups
I am new to Mura and have a lot of existing code that I am trying to utilize. I have a globalFunction.cfc file that has a lot of functions that I need to have access to for the existing code. Previously I always extended my application.cfc to the global function so they where always there. With Mura I am not sure where to include it and still keep the installation "upgrade safe".
Any suggestions are appreciated.
In your [site]/includes folder is an Application.cfc. I believe that is the one you are looking to have extend your globalFunction.cfc. It is update safe.
Lance,
You can just put any functions you're wanting to use throughout your site in your eventHandler or contentRenderer files in your theme's folder. These are update safe, and depending on how you're wanting to use them, you can use one for display and the other for function.
EventHandler Ex:
<!--- PAGE - Default --->
<cffunction name="onPageDefaultBodyRender" output="true" returntype="any">
<cfargument name="$">
<cfif $.getcontentID() neq "00000000000000000000000000000000001">#$.dspInclude('/themes/MYTHEME/display_objects/bodies/dsp_body_default.cfm')#</cfif>
</cffunction>
ContentRenderer Ex:
<cffunction name="removeLinks" returntype="string" access="public">
<cfargument name="str" default="" required="true">
<cfset str=reReplace(str, "<[[:space:]]*[aA].*?>(.*?)<[[:space:]]*/[[:space:]]*a[[:space:]]*>","\1","all") />
<cfreturn trim(str) />
</cffunction>
The EventHandler here just puts out an different body if its on the home page, where the contentRenderer removes any links if i use $.removeLinks(MYURLSTRING).
HTH
I am looking to migrate from a custom framework to Coldbox.
The application has 3 datasources
Core
Common
Site
The Core datasource stores information about the sites, the common datasource stores shared information, like the states table, and the Site datasource stores the data relevant to the website.
The Site datasource is changed per request based on the URL of the request, allowing each site to be sandboxed into its own database.
From my testing it seems that the DatasourceBeans generated by Coldbox and used in it's autowiring are stored/cached in the application scope. This is what I'm thinking to do, but the change to the datasource is persisted across requests.
In Coldbox.cfc
datasources = {
Core = {name="DSNCore", dbType="mssql", username="", password=""},
Common = {name="DSNCommon", dbType="mssql", username="", password=""},
Site = {name="", dbType="mssql", username="", password=""}
};
and
interceptors = [{
class="interceptors.Website",
properties={}
}];
Interceptor named Website.cfc
<cfcomponent name="Website" output="false" autowire="true">
<cfproperty name="dsncore" inject="coldbox:datasource:Core">
<cfproperty name="dsn" inject="coldbox:datasource:Site">
<cffunction name="Configure" access="public" returntype="void" output="false" >
</cffunction>
<cffunction name="preProcess" access="public" returntype="void" output="false" >
<cfargument name="event" required="true" type="coldbox.system.web.context.RequestContext">
<cfargument name="interceptData" required="true" type="struct">
<cfset var q="" />
<cfdump var="#dsn.getMemento()#" label="DSN before change" />
<cfquery name="q" datasource="#dsncore.getName()#">
SELECT
Datasource
FROM
Websites
WHERE
Domain = <cfqueryparam cfsqltype="cf_sql_idstamp" value="#cgi.http_host#" />
</cfquery>
<cfscript>
dsn.setName(q.Datasource);
</cfscript>
<cfdump var="#dsn.getMemento()#" label="DSN after change" />
<cfdump var="#q#" label="Results of query" /><cfabort />
</cffunction>
</cfcomponent>
Is there any way to do this in a way that I can use the Coldbox autowire datasource beans?
Honestly, this is just the way I thought I would do it, if anyone has any other ideas on how to get my model to use NON-hardcoded different datasource per request, I would love to understand the framework better.
This question also extends to ORMs. Is there a way for, say, Transfer to use a different datasource per request? What if the databases can have potentially different schemas? Lets say that one database has been updated to a newer version, but another still uses an older version and I essentially have some if statements in the code to provide enhanced functionality to the updated database.
You may be reading these questions and thinking to yourself "You shouldn't do that." Well i am, so please no answers saying not to do it. If you have ideas on better ways to have single codebase attached to different databases then I'm all ears though.
Another way you could do it is by using the requestStartHandler in Coldbox.cfc
<!---config/Coldbox.cfc--->
requestStartHandler = "Main.onRequestStart"
<!---handlers/Main.cfc--->
<cffunction name="onRequestStart" returntype="void" output="false">
<cfargument name="event" required="true">
<cfquery name="q" datasource="#dsncore.getName()#">
SELECT
Datasource
FROM
Websites
WHERE
Domain = <cfqueryparam cfsqltype="cf_sql_idstamp" value="#cgi.http_host#" />
</cfquery>
<cfset rc.dataSource = q.Datasource />
</cffunction>
Then you just have your dataSource stored in the Request Collection becuase onRequestStart will fire on every Request.
I'm trying to see if there is a way to split a CFSAVECONTENT tag across the onRequestStart() and onRequestEnd() functions in Application.cfc to save the generated HTML of any .cfm page in the application to a variable.
Adding <cfsavecontent variable="html"> to onRequestStart() and adding </cfsavecontent> to onRequestEnd() isn't allowed since the tag must be closed in the function.
Is this even possible to do? I'm trying to avoid hard coding the CFSAVECONTENT this into every .cfm page of the site.
Thanks!
Alex,
You could do something like this in OnRequest (untested, but should work).
<cffunction name="onRequest" returnType="void">
<cfargument name="thePage" type="string" required="true">
<cfsavecontent variable="html">
<cfinclude template="#arguments.thePage#">
</cfsavecontent>
<!--- do whatever you want with the html variable here (for example, output it) --->
<cfoutput>#html#</cfoutput>
</cffunction>
I realize this has an accepted answer already, but another way to accomplish this without using cfinclude would be to use the getPageContext() object in onRequestEnd() to nab the generated content:
<cffunction name="onRequestEnd" output="yes">
<cfargument type="string" name="targetPage" required="true" />
<cfset var html = getPageContext().getOut().getString() />
<!--- Manipulate the html variable. --->
<cfoutput>#html#</cfoutput><cfabort />
</cffunction>
The <cfabort /> is important here because if you don't abort the request, the CF engine will output the generated content again and it will end up sending two copies of the output along.
I've used this method to apply site-wide changes to content on sites in a crunch where finding every instance of the original content wasn't practical or timely enough. It can also be used to send the generated content out to a translation service if needed before being returned to the end-user.