This may be better off at BlogCFC.com, but I've had a few requests for this lately so I thought I'd post it here.
One of the undocumented features of BlogCFC is the ability to pass in configuration information to the CFC. Normally you tell the CFC to load data from the INI file. However, you may want to create a completely dynamic setup. For example, maybe you want x.foo.com and y.foo.com to both run BlogCFC and both use one physical folder.
This is rather simple - but you have to pass a structure that contains all the keys that would normally be in the INI file. Here is an example I'm using on a real site now (unreleased to the public though). First - here is the code that sniffs the server name to grab the name of the blog, in this case it is based on the first part of the URL. If we were using x.foo.com and y.foo.com, the blog names would be X and Y.
<cfset blogname = listFirst(cgi.server_name,".")>
<cfapplication name="_blog_#blogname#" sessionManagement="true" loginStorage="session">
Next I create a structure with all values that exist in a normal INI file:
<cfset instance = structNew()>
<cfset instance.dsn = dsn>
<cfset instance.owneremail="blog@blog.com">
<cfset instance.blogurl = "http://#cgi.server_name#/blog/index.cfm">
<cfset instance.blogtitle = "#blogname# Blog">
<cfset instance.blogdescription = "#blognme# Blog">
<cfset instance.blogDBType="MYSQL">
<cfset instance.locale="en_US">
<cfset instance.users = "">
<cfset instance.commentsFrom = "">
<cfset instance.mailServer = "">
<cfset instance.mailUsername = "">
<cfset instance.mailPassword = "">
<cfset instance.pingurls = "">
<cfset instance.offset = "0">
<cfset instance.allowtrackbacks = false>
<cfset instance.trackbackspamlist="lots of bad words here">
<cfset instance.blogkeywords = "">
<cfset instance.ipblocklist = "">
<cfset instance.allowgravatars = true>
<cfset instance.maxentries = "10">
<cfset instance.usecaptcha = false>
Once you have the structure populated, you then pass it to the CFC:
<cfset application.blog = createObject("component","org.camden.blog.blog").init(blogname,instance)>
That's it. Obviously you may need to tweak your instance settings. For example, you may have special logic for the users value. Anyway, let me know if this doesn't make sense.
Archived Comments
How would you keep the blog name persistent if you don't have multiple sub domains?
The use of cgi.server_name was arbitrary. You can base it on anything really.
How about adding a virtual directory if you have permissions?
Nick, it shouldn't matter. The idea is - one code base - and SOME kind of logic to determine current blog. You could even say, if it is morning, load the morning blog. It is up to you.
But how do you keep the blogname constsiant?
Blog A has
http://blog.com
<cfset blogname="blogA">
blogb has
http://blog.com
<cfset blogname="blogB">
how do it know when you're in blog B as you can't use the application or session scope?
Am i missing the point?
I think you may be. :) THe point is that YOU determine the blog name and settings. Your code does it all and the passes it to the blog and also makes the cfapplication tag dynamic as well.
Raymond,
It looks like the latest version (5.6.001) of BlogCFC includes the dynamic application and blog name logic, but not the instance vars. Would you mind commenting on this and how and if the latest version (5.6.001) of BlogCFC would change your approach, here?
I'm not quite sure what you mean. I don't use the feature itself in the code you unzip. It is supported - but not used. I certainly did not remove the feature though. It is still there.
I was referring to the following in the Application.cfm:
<!---
The prefix is now dynamic in case 2 people want to run blog.cfc on the same machine. Normally they
would run both blogs with the same org, and use different names, but on an ISP that may not be possible.
So I base part of the application name on the file path.
Name can only be 64 max. So we will take right most part.
--->
But, now that I look at again it looks like it works with multiple installs of the application.
Where would you suggest injecting the code for the Dynamic Instances, say in the root Application.cfm?
Additionally, I was thinking of making an instance table keyed on some server value and running a query to grab all the instance vars after sniffing out the server value, and then creating a new instance structure and setting all the vars like you seggest, but from the query values.
Any comments are appreciated.
Yes, I do it in Application.cfm. Your idea seems ok. THis is why I built in the support - so you could make it based on anything.
Raymond:
Does this "Dynamic Instances" approach break your administrator settings tool?
I'm thinking I'll need to re-write or override setProperty in Blog.cfc, unless I keep all the instance definitions in blog.ini.cfm.
I'm thinking I'll override setProperty to update my instance table in the DB instead of blog.ini.cfm.
How's you administrator settings tool working in your "real site"
Any comments are greatly appreciated.
Thanks,
--Mike M.
I recently added a setting that would hide the settings page from the admin. You would want to use this for multiserver blogs so that folks can't edit the settings.
Hi Ray,
I have implemeted this functionality into my site and it seems to be now working to a point. I have downloaded and installed the latest blog version, added in the instance definitions to the Application.cfm file and some some tweaking on the settings to get it to load.
So i have one folder with the client dir in it, within this folder i have placed the org dir. I have one db schema (Oracle).
I tested this by firstly hardcoding the blogName var, this worked fine, an instance of the blog was created, i then logged into the admin this also worked fine and was able to add an entry and a category, all hunky dory.
The next step is to make the blog selection dynamic, so i thought the easy way is to create a blogselection.cfm page which passes a variable in blogName into the app via a url variable.
This seemed to work until i got to the admin, i passed the blogName var again to load the admin page, and tried to click onto add a new entry and it came back with blogName undefined.
OK i know exactly what it is doing here, its looking for the blogName variable again as the Application.cfm file has been hit again on trying to access the add entry page.
How can i get around this, everytime a page is called in the admin its looking for the blogName var, first thoughts were perhaps trying to store it in a session variable. Is this the best way to do this or can you suggestsomething else?
Any help appreciated.
Matt
Hi Ray,
Its amazing what you can do with a little persistance.
I have managed to solve my above issue for my requirement.
I decided to use a session variable to hold the blogName and basically created a page with a link to blog1 and blog2.
Depending on what link was clicked, the session variable stores the blogname and so creates the instance for that blog.
OK it may not be the best solution but it seems to be working for what i need.
thankyou for the ideas and the application.
Matt
Glad you got it working. I was sleeping so thats my excuse for not helping earlier. :0
I'm trying to set up the dynamic instances in version 5.8.001. I created a new file called index_new.cfm:
(Please Note the DB information has been XXX'd out)
<!---Sets the Blog to the Server Name--->
<cfset blogname = "Development Blog 2">
<cfapplication name="_blog_#blogname#" sessionManagement="true" loginStorage="session">
<!---INI Structure---><cfset instance = structNew()>
<cfset instance.dsn = "xxxxxxxxx">
<cfset instance.username = "xxxxxxxx">
<cfset instance.password = "xxxxxxxx">
<cfset instance.owneremail="j.harvey@swidigital.com">
<cfset instance.blogurl = "http://localhost/blogcfc/index_new.cfm">
<cfset instance.blogtitle = "#blogname# Blog">
<cfset instance.blogdescription = "#blogname# Blog">
<cfset instance.blogDBType="MSSQL">
<cfset instance.locale="en_US">
<cfset instance.users = "">
<cfset instance.commentsFrom = "">
<cfset instance.mailServer = "xxxxxxxxxxx">
<cfset instance.mailUsername = "j.harvey">
<cfset instance.mailPassword = "jch1701">
<cfset instance.pingurls = "">
<cfset instance.offset = "0">
<cfset instance.allowtrackbacks = true> <!---True or False--->
<cfset instance.trackbackspamlist="lots of bad words here">
<cfset instance.blogkeywords = "">
<cfset instance.ipblocklist = "">
<cfset instance.allowgravatars = true><!---True or False--->
<cfset instance.maxentries = "10">
<cfset instance.usecaptcha = false><!---True or False--->
<!---Pass the Populated Structure to the CFC--->
<cfset application.blog = createObject("component","org.camden.blog.blog").init(blogname,instance)>
When I go to run the page, it comes up blank. Do I need to load these variables in the index.cfm?
Well, you should be using index.cfm, not index_new.cfm. Switch to that and let me know.
I tried doing it on the Index.cfm Page, and i just get the default blog, not the second one I'm trying to invoke.
Right - but the idea is to use ONE file base, not one file per blog. You need to keep things in index.cfm as it is an important file to the code base.
Ok, I've tried placing the Multiple Instances code in my application.cfm file and running the website. Now I get the following error:
Context validation error for tag cfif.
The start tag must have a matching end tag. An explicit end tag can be provided by adding </cfif>. If the body of the tag is empty you can use the shortcut <cfif .../>.
The error occurred in C:\Inetpub\wwwroot\blog_dev\blogcfc\Application.cfm: line 64
62 :
63 : <!--- By default we cache a lot of information. Allow reinit=1 in the URL to restart cache. --->
64 : <cfif not isDefined("application.init") or isDefined("url.reinit")>
65 :
66 : <!--- load and init blog --->
The code i did in my application.cfm looks like this:
<cfsetting enablecfoutputonly="true" showdebugoutput="false">
<!---
Name : Application.cfm
Author : Raymond Camden
Created : Some time ago
Last Updated : April 13, 2007
History : Reset history for version 5.7
: Added comments, and Scott P's pod manager cfc (rkc 4/13/07)
Purpose : Blog application page
--->
<cfset setEncoding("form","utf-8")>
<cfset setEncoding("url","utf-8")>
<!--- Edit this line if you are not using a default blog --->
<!---<cfset blogname = "Default">--->
<!---
The prefix is now dynamic in case 2 people want to run blog.cfc on the same machine. Normally they
would run both blogs with the same org, and use different names, but on an ISP that may not be possible.
So I base part of the application name on the file path.
Name can only be 64 max. So we will take right most part.
--->
<!---<cfset prefix = hash(getCurrentTemplatePath())>
<cfset prefix = reReplace(prefix, "[^a-zA-Z]","","all")>
<cfset prefix = right(prefix, 64 - len("_blog_#blogname#"))>
<cfapplication name="#prefix#_blog_#blogname#" sessionManagement="true" loginStorage="session">--->
<!---Multiple Instances Code Invokation--->
<cfset blogname = listFirst(cgi.server_name,".")>
<cfapplication name="_blog_#blogname#" sessionManagement="true" loginStorage="session">
<cfset instance = structNew()>
<cfset instance.dsn = BlogDB>
<cfset instance.owneremail="j.harvey@swidigital.com">
<cfset instance.blogurl = "http://#cgi.server_name#/blog_dev/blogcfc/index.cfm">
<cfset instance.blogtitle = "#blogname# Blog">
<cfset instance.blogdescription = "#blognme# Blog">
<cfset instance.blogDBType="MSSQL">
<cfset instance.locale="en_US">
<cfset instance.users = "admin">
<cfset instance.commentsFrom = "">
<cfset instance.mailServer = "xxxxxxxxxxxx">
<cfset instance.mailUsername = "xxxxxx">
<cfset instance.mailPassword = "xxxxxx">
<cfset instance.pingurls = "">
<cfset instance.offset = "0">
<cfset instance.allowtrackbacks = false>
<cfset instance.trackbackspamlist="lots of bad words here">
<cfset instance.blogkeywords = "">
<cfset instance.ipblocklist = "">
<cfset instance.allowgravatars = true>
<cfset instance.maxentries = "10">
<cfset instance.usecaptcha = false>
<cfset application.blog = createObject("component","org.camden.blog.blog").init(blogname,instance)>
<!---End of the Multiple Instance--->
<!--- Our exception template. --->
<cferror type="exception" template="error.cfm">
<cfinclude template="includes/udf.cfm">
<!--- By default we cache a lot of information. Allow reinit=1 in the URL to restart cache. --->
<cfif not isDefined("application.init") or isDefined("url.reinit")>
<!--- load and init blog --->
<cfset application.blog = createObject("component","org.camden.blog.blog").init(blogname)>
<!--- Root folder for uploaded images, used under images folder --->
<cfset application.imageroot = application.blog.getProperty("imageroot")>
<!--- locale related --->
<cfset application.resourceBundle = createObject("component","org.hastings.locale.resourcebundle")>
<!--- Path may be different if admin. --->
<cfif findNoCase("admin/", cgi.script_name) or findNoCase("xmlrpc/", cgi.script_name)>
<cfset theFile = expandPath("../includes/main")>
<cfset lylaFile = "../includes/captcha.xml">
<cfset slideshowdir = expandPath("../images/slideshows/" & application.imageroot)>
<cfelse>
<cfset theFile = expandPath("./includes/main")>
<cfset lylaFile = "./includes/captcha.xml">
<cfset slideshowdir = expandPath("./images/slideshows/" & application.imageroot)>
</cfif>
<cfset application.resourceBundle.loadResourceBundle(theFile, application.blog.getProperty("locale"))>
<cfset application.resourceBundleData = application.resourceBundle.getResourceBundleData()>
<cfset application.localeutils = createObject("component","org.hastings.locale.utils")>
<cfset application.localeutils.loadLocale(application.blog.getProperty("locale"))>
<!--- load slideshow --->
<cfset application.slideshow = createObject("component", "org.camden.blog.slideshow").init(slideshowdir)>
<!--- Use Captcha? --->
<cfset application.usecaptcha = application.blog.getProperty("usecaptcha")>
<cfif application.usecaptcha>
<cfset application.captcha = createObject("component","org.captcha.captchaService").init(configFile="#lylaFile#") />
<cfset application.captcha.setup() />
</cfif>
<!--- clear scopecache --->
<cfmodule template="tags/scopecache.cfm" scope="application" clearall="true">
<cfset majorVersion = listFirst(server.coldfusion.productversion)>
<cfset minorVersion = listGetAt(server.coldfusion.productversion,2)>
<cfset cfversion = majorVersion & "." & minorVersion>
<cfset application.isColdFusionMX7 = server.coldfusion.productname is "ColdFusion Server" and cfversion gte 7>
<!--- Used in various places --->
<cfset application.rootURL = application.blog.getProperty("blogURL")>
<!--- per documentation - rooturl should be http://www.foo.com/somethin... --->
<cfset application.rootURL = reReplace(application.rootURL, "(.*)/index.cfm", "\1")>
<!--- used for cache purposes is 60 minutes --->
<cfset application.timeout = 60*60>
<!--- how many entries? --->
<cfset application.maxEntries = application.blog.getProperty("maxentries")>
<!--- TBs allowed? --->
<cfset application.trackbacksAllowed = application.blog.getProperty("allowtrackbacks")>
<!--- Gravatars allowed? --->
<cfset application.gravatarsAllowed = application.blog.getProperty("allowgravatars")>
<!--- Load the Utils CFC --->
<cfset application.utils = createObject("component", "org.camden.blog.utils")>
<!--- Load the Page CFC --->
<cfset application.page = createObject("component", "org.camden.blog.page").init(dsn=application.blog.getProperty("dsn"), username=application.blog.getProperty("username"), password=application.blog.getProperty("password"),blog=blogname)>
<!--- Load the TB CFC --->
<cfset application.textblock = createObject("component", "org.camden.blog.textblock").init(dsn=application.blog.getProperty("dsn"), username=application.blog.getProperty("username"), password=application.blog.getProperty("password"),blog=blogname)>
<!--- Do we have comment moderation? --->
<cfset application.commentmoderation = application.blog.getProperty("moderate")>
<!--- Do we allow file browsing in the admin? --->
<cfset application.filebrowse = application.blog.getProperty("filebrowse")>
<!--- Do we allow settings in the admin? --->
<cfset application.settings = application.blog.getProperty("settings")>
<!--- load pod --->
<cfset application.pod = createObject("component", "org.camden.blog.pods")>
What am I doing wrong? I haven't been able to get the multiple instances to run for anyhting.
CF:7.02
Windows IIS5.4 (win XP Pro)
Well the error is pretty clear. You opened a CFIF someplace that you didn't close. Just start tracking through your code to see which one you forgot.
That's the thing ray, There's no <cfif> tag that I've modified, it only occurs when I add the (instance) codes above to the Application.cfm file...
If I remove them, It works ok.
If you pasted the entire code above -then that isn't the complete file. There is a problem with some blogcfc files and Dreamweaver. Are you using Dreamweaver to edit the files? If so - it is cropping the files because it doesn't like a character in the file. Redownload - and edit with Notepad.
I only pasted the code upto where I had added the multiple-instance code.
I have the complete Application.cfm, and each and everythime, without fail, when I add the instance code to the application.cfm (client/application.cfm) I get the CFif error, and to get the blog back ot funcitonal status I have to extract the original application.cfm and reupload it unmodified.
That is truly odd. So you scanned the file, and you see no missing </cfif>s? Maybe you can send me your file via email.
On On it's way
Hey Ray, quick question.
I recently deployed BlogCFC using multiple instances with subdomains and it works great!
My question is, how can I go about assigning a custom enclosure directory for each instance?
I've got custom image root directories working, but it seems all the enclosures go to the same place. Thanks!
Given that your subdomains are your 'primary keys', I'd just set the enclosure dir to "enclosures/" + subdomain. Be sure to make the dir if it doesn't exist.
Ray, where do I set the enclosures dir? I don't see a setting for it, did I miss something?
You don't set it - the code does. Look in Application.cfm. You would modify it there.
Sorry if I'm dense, Ray, but I had looked through Application.cfm and did not see anything to customize the "enclosures" directory, would you give me a line # hint? :)
I was wrong. It is actually defined in
/admin/entry.cfm
when you try to save a file:
<cfif isDefined("form.enclosure") and len(trim(form.enclosure))>
<cfset destination = expandPath("../enclosures")>
<!--- first off, potentially make the folder --->
<cfif not directoryExists(destination)>
<cfdirectory action="create" directory="#destination#">
</cfif>
I should move that in v6. Anyway, you would need to fix that, and fix the links in index.cfm:
Line 145: <cfif len(enclosure)><cfoutput><img src="#application.rooturl#/images/disk.png" align="middle" title="#rb("download")#" height="16" width="16"> <a href="#application.rooturl#/enclosures/#urlEncodedFormat(getFileFromPath(enclosure))#">#rb("download")#</a> | </cfoutput></cfif>
And possibly in RSS as well. Yep, blog.cfc:
<enclosure url="#xmlFormat("#rootURL#/enclosures/#getFileFromPath(enclosure)#")#" length="#filesize#" type="#mimetype#"/>
Sorry!
Ray, thank you very much for pointing those out, it was very helpful! Now I've got it pretty much working as desired, glad to hear you're going to change that for v6!
On another note, a question about the <more/> and <textblock> tags... When using a RTE, such as fckeditor, these tags stop working, the code is being rendered out literally as text, what's the best way to handle these in RTE? thx
Sorry, but this is exactly why I hate RTEs. ;) If you search the BlogCFC forums, you will find other people working with RTEs. I know some folks have got it working.
I hear ya, Ray... I'm like you, back in my day we coded our own html in snowstorms uphill both ways...