I want to make the part of my application that updates info into sessions. I
want the sessions to control the usage of the section. So if user a is logged
in, no one else can make changes to the area until they log out. Somethign like
that, or they can log in, but can't make changes if another user is.
I realize some of this is controled by islogged in and the session started by
the logged in user. How do I make my application into a session managed app?
Here is some code, just some of the code in my app, I will show you what I am
doing, I don't think it is right.
this is the start page:
<cfset preappendURL = "../">
<cfset pageType = "admin">
<cfquery name="catMan" datasource="#APPLICATION.dataSource#">
SELECT Categories.Name AS ViewField1, Categories.CategoryID
FROM Categories
</cfquery>
<cfset rowsPerPage = 6>
<cfparam name="URL.startRow" default="1" type="numeric">
<cfset totalRows = catMan.recordCount>
<cfset endRow = min(URL.startRow + rowsPerPage - 1, totalRows)>
<cfset startRowNext = endRow + 1>
<cfset startRowBack = URL.startRow - rowsPerPage>
<head>
</head>
<body>
<cfoutput>
Displaying [B]#URL.startRow#[/B] to [B]#endRow#[/B] of [B]#totalRows#[/B]
Records.
<cfif startRowBack GT 0><a href="#CGI.script_name#?startRow=#startRowBack#"
class="nav">< Previous Records</a></cfif>
<cfif startRowNext lte totalRows><a
href="#CGI.script_name#?startRow=#startRowNext#" class="nav">Next Records > </a>
</cfif>
</cfoutput>'
<cfloop query="catMan" startRow="#URL.startRow#" endrow="#endRow#">
<cfset class = iif(catMan.currentRow mod 2 eq 0, " 'DataA' ", " 'DataB' ")>
<cfoutput>
#ViewField1#
<a href="project-manager.cfm?CategoryID=#CategoryID#" class="nav">Edit
Projects</a>
<a href="projectCat-edit.cfm?CategoryID=#CategoryID#" class="nav">Edit
Category</a>
<form action="ProjectCat-Action.cfm" method="post">
<input type="hidden" name="ID" value="#CategoryID#">
<input type="submit" name="cat_Delete" class="formButtons" onClick="return
confirmDelete('ID','#ViewField1#')" value="Delete"></form>
</cfoutput></cfloop>
<cfoutput>
<cfset thisPage = 1>
<cfloop from="1" to="#totalRows#" step="#rowsPerPage#" index="pageRow">
<cfset isCurrentPage = (pageRow gte URL.startRow) and (pageRow lte endRow)>
<cfif isCurrentPage>
<cfoutput><font size="2" face="Verdana, Arial, Helvetica,
sans-serif">[B]#thisPage#[/B]</font></cfoutput><cfelse><cfoutput>
<a href="#CGI.script_name#?startRow=#pageRow#"
class="nav">#thisPage#</a></cfoutput></cfif>
<cfset thisPage = thisPage + 1>
</cfloop>
<cfif startRowBack GT 0><a href="#CGI.script_name#?startRow=#startRowBack#"
class="nav">< Previous Records</a></cfif>
<cfif startRowNext lte totalRows><a
href="#CGI.script_name#?startRow=#startRowNext#" class="nav">Next Records > </a>
</cfif>
</cfoutput>
</body>
There is another page that goes with this. It is the edit page. But I don't
know if we can start here to create this part into sessions.
Here is page 2:
<cfset preappendURL = "../">
<cfset pageType = "admin">
<cfset FormFieldList = "Body">
<cfif isDefined("URL.RecordID")>
<cfquery name="contentMAN" datasource="#APPLICATION.dataSource#" maxRows=1>
SELECT Content.Body, Content.Nickname, Content.title AS ViewField1,
Content.ContentID AS ID_Field
FROM Content
<cfif isDefined("URL.RecordID")>
WHERE Content.ContentID = #URL.RecordID#
</cfif>
</cfquery>
<cfif not ListFind( FormFieldList, "ContentID" )>
<cfset FormFieldList = ListAppend( FormFieldList, "ContentID" )>
</cfif>
<cfset Body_Value = '#contentMAN.Body#'>
<cfelse>
<cfset Body_Value = ''>
</cfif>
<cfquery name="info2" datasource="#APPLICATION.dataSource#" maxRows=1>
SELECT companySettings.company AS ViewField1, companySettings.companyID AS
ID_Field
FROM companySettings
</cfquery>
<head>
</head>
<body>
<cfoutput query="contentMAN">
You are Editing: #ViewField1#
<cfquery name="session.contentMAN"...>
...
</cfquery>
<cfoutput query="session.contentMAN">
...
</cfoutput>
Now I need to tell you this will not help you in your stated
requirement. Putting data into the session scope will not make your
application 'session' aware. Data in the session scope is global only
to one, individual user. No other user can see what is in any other
user's session scope. [Unless you do some strange stuff with
undocumentated and unsupported ColdFusion java objects]
To do that you need a scope that is global to all users of the
application and that is the 'application' scope. Luckily this is just
as easy to use.
<cfquery name="application.contentMAN"...>
...
</cfquery>
<cfoutput query="application.contentMAN">
...
</cfoutput>
I'll leave it to you to figure out all the logic for what data gets
stored in what scopes and what decisions your code makes based on this data.
So once the query is in the application scope, I put the rest in the same
scope? or not?
Like this:
<cfparam name="url.id" type="integer" default="0">
<cfparam name="application.CategoryID" type="integer" default="#url.id#">
<cfparam name="application.Name" default="">
<cfparam name="application.Description" default="">
<cfparam name="application.MYFile" default="">
<!--- if the record was found, store the values --->
<cfif application.categRec.RecordCount EQ 1>
<cfset application.CategoryID = categRec.CategoryID>
<cfset application.Name = categRec.Name>
<cfset application.Description = categRec.Description>
<cfset application.MYFile = categRec.MYFile>
</cfif>
</cfif>
and then this?
<cfoutput>
<form action="ProjectCat-Action.cfm" method="post" name="content" id="content"
enctype="multipart/form-data">
<input type="hidden" name="ID" value="#application.CategoryID#">
<input type="hidden" name="oldimage" value="#application.MYFile#">
and so on with the rest of this page.
But for the action part, do I make all those into the application variables as
well?
<cfquery datasource="#APPLICATION.dataSource#">
UPDATE Categories
SET
<cfif fileuploaded is true>
Categories.MYFile=<cfqueryparam cfsqltype="cf_sql_varchar"
value="#application.uploadedfile#">,
</cfif>
Categories.Name=<cfqueryparam cfsqltype="cf_sql_varchar"
value="#form.application.Name#">,
Categories.Description=<cfqueryparam cfsqltype="cf_sql_longvarchar"
value="#form.application.Description#">
WHERE CategoryID = <cfqueryparam value="#form.application.ID#"
cfsqlType="CF_SQL_INTEGER">
</cfquery>
Is that how it is done?
and thank you. I had an idea, but I am trying to decide my best way to
approach this.
That is a much bigger question and rather difficult to answer
specifically in a quick fire method such as these forums.
But in general, yes. You would put data into the application scope that
you need to be accessible in any template run by any user of this
application. Your code can then access this data when necessary and
make appropriate decisions base on what the data is.
What this data is and how it is used is up to you as the developer to
decide. But I don't think it needs to be much more then something that
says userA is engaged.
Then the working code can make the decision that since userA is engage,
other uses can not access the code to the restricted functionality until
userA disengages. Be aware that with the nature of HTTP web requests, a
browser never goes backs and tells a server that the user has left. All
the server can do, is wait for a specified time for a new request, and
if one never arrives, assume the user has left.
Once you have the mechanism to know a user is accessing this feature and
to shut out others, then the actual work of editing and updating the
data can be done in the local scope. You do not need to put all the
data into the application scope. Just enough of it to be able to make
the appropriate decisions in your code.
So this type of application will make a use of various variable scopes
including the application scope for information available to all users,
the session scope for information available to all requests by that user
and the local scope for data needed just for this request.
P.S. If you need a even more global scope there is the server scope
where you can put data so it is available to all requests of all users
of all applications running on the ColdFusion server.
onApplicationStart - when an Applicaiton first starts a good place to
initialize application scope data.
onSessionStart - when a user first access an application for a new
session a good place to initialize session data and|or update
application data about this user.
onRequestStart - when a new request is started. A good place to
initialize request variables. Note can not initialize local variables
unless the onRequest function is also defined which has serious pros and
cons. Also can update session and or application data about the start
of this request.
onRequestEnd - when the request is done. A good place to do something
when each request finishes.
onSessionEnd when the session times out. A good place to do something
when a user session ends.
onApplicationEnd when the application times out. A good place to do
something when an application ends if it has not been used in a certain
period of time.
The documentation has lots of great information about this feature.
this is my on app start tag.
<cffunction name="onApplicationStart" returntype="boolean" output="false">
<cfset APPLICATION.appStarted = now()>
<cfset APPLICATION.dataSource = "myDB">
<cfset APPLICATION.companyName = "My company">
<cfreturn true>
</cffunction>
Do I need to add anything else to this so I can run the "back end" in the
application scope?
Possibly, depending on how you want to structure your application.
My application.cfc is in the main directory, I don't have ownership of my
server, so I had to use a proxyapplication.cfc to lock out the back end. All
variables are running fine from teh application.cfc in the main directory to
the one in the private folder.
Is that the structure I need? How would I write that in this area if I am
right?
CFmonger
First of all I do not understand your reference to proxyApplication.cfc
and you not having ownership of your server? Why do you need to use
proxyApplicaiton.cfc? Are you not able to upload files to your web
server web root directories?
I *CAN NOT* tell you what structure you need. The answer to that
depends on what exactly *YOUR* requirements are for *YOUR* application.
If you care to write these requirements into a reasonably detailed
document and pay somebody somewhere between $50 and $150(US) an hour the
y would be happy to work out exactly what you need.
You could also attempt to post such a document to a list such as this,
but I would not hold out much hope of it generating many free responses.
The solution to your requirement might be as simple as putting a new
Applicaiton.cfc file in the sub directory that will contain the code of
this administration function. It might be a great deal more intricate
and complicated then that. I don't know, I don't know what your
application needs to do. Quick fire forums like this are not well
suited for such lengthy and detailed discussions.
We are most happy to offer specific answers to specific issues vexing
our fellow developers. But some work on your end needs to be apparent.
P.S.
Why do I have this strange feeling of channeling Adam?