8 Replies Latest reply on Mar 16, 2009 10:13 AM by Newsgroup_User

    Turning queries into session variables

    CFmonger
      Hello;
      I am trying to learn about session variables for more stability in an application I am writting. I am still not sure of how this works and was hoping someone can show me so I can get the idea.

      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">&lt; Previous Records</a></cfif>

      <cfif startRowNext lte totalRows><a href="#CGI.script_name#?startRow=#startRowNext#" class="nav">Next Records &gt; </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">&lt; Previous Records</a></cfif>

      <cfif startRowNext lte totalRows><a href="#CGI.script_name#?startRow=#startRowNext#" class="nav">Next Records &gt; </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">
      <cfparam name="url.id" type="integer" default="0">
      <cfparam name="variables.CategoryID" type="integer" default="#url.id#">
      <cfparam name="variables.Name" default="">
      <cfparam name="variables.Description" default="">
      <cfparam name="variables.MYFile" default="">


      <cfif url.id GT 0>
      <cfquery name="categRec" dataSource="#APPLICATION.dataSource#">
      SELECT Name, Description, MYFile, CategoryID
      FROM Categories
      WHERE CategoryID = <cfqueryparam value="#URL.ID#" cfsqltype="cf_sql_integer">
      ORDER BY Name
      </cfquery>

      <!--- if the record was found, store the values --->
      <cfif categRec.RecordCount EQ 1>
      <cfset variables.CategoryID = categRec.CategoryID>
      <cfset variables.Name = categRec.Name>
      <cfset variables.Description = categRec.Description>
      <cfset variables.MYFile = categRec.MYFile>
      </cfif>
      </cfif>
      <head>
      </head>
      <body>
      <cfoutput>
      <form action="ProjectCat-Action.cfm" method="post" name="content" id="content"
      enctype="multipart/form-data">
      <input type="hidden" name="ID" value="#variables.CategoryID#">
      <input type="hidden" name="oldimage" value="#variables.MYFile#">

      <input type="text" name="Name" class="textInputs"
      value="#variables.Name#" maxLength="510">

      <cfif len(trim(variables.MYFile)) GT 0>
      <b>Image in use:</b>#variables.MYFile#</cfif>

      <input name="MYFile" type="file" id="MYFile">

      <input name="Description" type="text" class="textInputs"
      value="#variables.Description#" size="50" maxLength="510">
      </cfoutput>
      <input type="submit" class="formButtons" name="cat_OK" onclick=";DisableButton(this);" value=" OK ">
      <input type="submit" class="formButtons" name="cat_Cancel" value="Cancel">
      </form>

      How would I make this into session managed variables? That is where I am confused. I have session variables enabled in my application.cfc file. Now I want to manage them better.

      Can anyone help show me how to do this? Or point me to a web site that explains what I am trying to do?

      Thank you.

      CFmonger
        • 1. Re: Turning queries into session variables
          Level 7
          First of all, to make a query a session variable - just put it there.

          <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.
          • 2. Re: Turning queries into session variables
            CFmonger Level 1
            ok, that makes sense. so if I put my query into the application scope, I will be able to manage my users easier? Correct?

            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.
            • 3. Re: Turning queries into session variables
              Level 7
              CFmonger wrote:
              > ok, that makes sense. so if I put my query into the application scope, I will
              > be able to manage my users easier? Correct?
              >
              > So once the query is in the application scope, I put the rest in the same
              > scope? or not?
              >

              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.
              • 4. Re: Turning queries into session variables
                Level 7
                I forgot to add that this type of application can usual make good use of
                the newish Application.cfc and its event functions. These functions
                fire on the start and end of various events.

                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.
                • 5. Re: Turning queries into session variables
                  CFmonger Level 1
                  I do use the application.cfc I agree I like it so much better then the appication.cfm far better control of variables.

                  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?
                  • 6. Re: Turning queries into session variables
                    Level 7
                    CFmonger wrote:
                    >
                    > 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.
                    • 7. Re: Turning queries into session variables
                      CFmonger Level 1
                      how do you mean?
                      I have the public side, and a directory I lock people out of, you need to log in. This is the area I am going to set it up with the sessions for modifying content.

                      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
                      • 8. Re: Turning queries into session variables
                        Level 7
                        CFmonger wrote:
                        > how do you mean?
                        > I have the public side, and a directory I lock people out of, you need to log
                        > in. This is the area I am going to set it up with the sessions for modifying
                        > content.
                        >
                        > 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?