Wednesday, December 14, 2011

Class File PHP

I sent a few hours and came up with a Class file that would represent my counter:

id = $id;

//get recs from db
$rec = $this->getRec();
$totalCount = $this->getCounterTotal();

//update instance vars
$this->counterName = $rec->name;
$this->counterValue = $totalCount;
}

private function getRec(){

$rec = mysql_query("
SELECT id, name
FROM tablename
WHERE id = $this->id
");

return mysql_fetch_object($rec);
}

private function getCounterTotal(){
//select and count recs equal to id
$rec = mysql_query("
SELECT COUNT(id) AS count, date
FROM tablename
WHERE counterid = $this->id AND active
");

$row = mysql_fetch_object($rec);
return $row->count;
}

// accessors
public function getCounterName() {
return $this->counterName;
}

public function getCounterValue() {
return $this->counterValue;
}

//mutators
public function incrementCounter() {

//update db
mysql_query("
INSERT INTO tablename
(counterid)
VALUES
($this->id)
");

//var_dump($this->id);
//break;

}


public function resetCounter(){
//get recs for the counterid
mysql_query("
UPDATE tablename
SET active = 0
WHERE counterid = $this->id
");

//var_dump($this->id);
//break;
}

public function getAllRecs(){
$recs = mysql_query("
SELECT c.name AS name, a.date AS date, a.schoolid AS schoolID, a.active AS active

FROM tablename a
join tablename c on c.id = a.counterid

ORDER BY date DESC
");

return $recs;
}

}

?>

While building my class file, I used a test.php file along with it to test it. A common practice when building bus. classes. Once the class was complete, I completed the DB table.

I ended up creating two tables:

tablename
tablename_associations

The tablename includes an id and a name for the counter.

Most of the data storage is in the associations table, where i am storing the id, the date of the request and a boolean col representing if the col is active in the current count, since it can be reset.

Next, I build an administration page that would allow whoever we gave access to it to reset each of the counters. Also on the admin. page is a report of each of the requested counts: see below






Now came the trickiest part of all. The problem I ran into next, was my new learning of the week. When using AJAX, which is essentially the XMLHTTPRequest object , that you CAN NOT remotely call a page on another server. This is know as the same server policy. This was a big problem since the server that was serving up the counter requests was NOT THE SAME as the server that was hosting the class(s) and db that were storing the counter. I had no way to reconcile this since I did not own the client server, only the serving server.

Hmmmm, what to do next??

This post got me started to what my option would be, which was basically two

1 - create or use a proxy server to fool the client and server into thinking they were the same domain
2 - use a different javascript notation called JSON, that would allow you to inject a script.

Neither of these options seems too trivial, after about a day of reading up on the two, i choose option 2., JSON.

Here is the JSON enabled call from the client side:

function getCounterJSON(param){
$.getJSON('http://domainName/path/view.php?callback=?','counter=' + param ,function(res){
document.getElementById(param).innerHTML = '&nbsp&nbsp&nbsp' + res.counterValue + ' views';
});

}

Here is the view.php page and its callback function.

//VERY sneaky JSON javascript object notation callback function - working around the security *blocks when ajaxing from one domain to another - which is illegal.
{
echo $_GET['callback'] . '(' . "{'counterValue' : $counterValue}" . ')';
}

Here is the rest of the view.php page preceding the callback function.

//CounterBase creates the objects $marks, $attendance, $progress
include_once 'CounterBase.php';

//check to see if someone is requesting to update a specific counter
$counter = $_GET['counter'];
$counterValue = 0;

//var_dump($_GET['counter']);
//break;

if ($counter == 'marks') {
$counterValue = $marks->getCounterValue();
}elseif($counter == 'attendance'){
$counterValue = $attendance->getCounterValue();
}elseif($counter == 'progress'){
$counterValue = $progress->getCounterValue();
}

counters, javascript, JSON and PHP



I have a customer that forwarded me an email that said "can we create Linkcounters on our web page?" My first thought was, its not the 90's, people don't use counters anymore. So I did a little research, about 5 minutes, and found a couple web sites that create counters for you. Like this one and this one. I send a email back with links to these sites and said something like, its pretty easy.

Then I got an email from my boss who said, "James, I think they want you to do it for them". So, I spent about 1/2 hr and documented the steps necessary to create a counter using one of the two sites, mailed the steps to my customer and waited. Here is a copy of my email with the steps:

Ellie, follow these steps for each page you want to insert the counter code on.
go to e-zeeinternet.com site
1 - enter the page URL, like https://siteURL , into the Page Counter that it will be placed on:
2 - choose Numbers of digits to show
3 - Choose pageviews
4 - Choose No, twice
5 - Select the counter style you prefer
6 - scroll to bottom of page, click Get Counter Code
7 - copy the contents from the box
8 - using an html editor, open the page specified in step 1
9 - paste the code into the location where you want counter to appear
10 - save the page
11 - reload the page and you should see the counter
you can edit the code a bit, to remove the text, for example.
I tested out on an html page on this end and works fine.
james

Next, I got an email from a guy down the hall who supports this customer I had just emailed. She emailed her contact, the guy down the hall, when she received this message from me.

Toby, the guy down the hall, said "james, i tried doing something like this before, but i don't know where to put the code. the plot thickens"...

Once I spoke with Toby further, I found out that the customer wants to track the # of times 3 specific links are clicked in their existing system. After clarifying a couple other issues, Toby gave me access to his test server and away I went back to my corner of the world to see about creating counters for the 3 links.

I googled a bit for "creating web counters" and found almost all javascript solutions, many of which used cookies to store information for a user. Cookies was a good solution, at least initially. You can see the alert() in the functions as debugging options. This was enjoyable, tinkering around in javascript until I got the code working.

Javascript Cookies

The basic premise of the cookie is a way for the browser to remember or persist information about the user when they come to a web page. Great, perfect, if the requirement was for user to keep their own counters.

Three requirements I was solving:

1 - adding a call to the incrementCookieCount function when the user clicked on a specific link.
2 - call the getCookieCount function for the 3 links requested, outputting the value of the cookie next to the link.
3 - creating a link that would allow the user to reset the cookie count, when they wanted. This would basically delete the cookie and recreate it, setting its count back to 1.

This was great, all this counting and incrementing and displaying and resetting was just fun, and I was able to do it all right in the client side browser. I was very proud once I got everything working. I showed my customer, he was excited bla bla...

Here is how I was calling the increment function:

if(data_type == 2){
//alert('attendance ' + data_type);
incrementCookieCount('attendance');
}else if(data_type == 3){
incrementCookieCount('marks');
}else if(data_type == 8){
incrementCookieCount('progress');
}


Here is how I was displaying the count:

getCookieCount('progress');


Here are the functions:

function incrementCookieCount(cookieName){
//alert('');
var count = GetCookie(cookieName)
if(count == null) {
SetCookie(cookieName,'1')
return 1
}else{
var newcount = parseInt(count) + 1;
DeleteCookie(cookieName)
SetCookie(cookieName,newcount,exp)
return count
}
}

function getCookieCount(cookieName){
//alert('');
var count = GetCookie(cookieName)
if(count == null) {
SetCookie(cookieName,'1')
return 1
}else{
var newcount = parseInt(count);
DeleteCookie(cookieName)
SetCookie(cookieName,newcount,exp)
return count
}
}


//these are like private functions, not called directly by the client.

function GetCookie (name) {
var arg = name + "=";
var alen = arg.length;
var clen = document.cookie.length;
var i = 0;

while (i < clen) {
var j = i + alen;
if (document.cookie.substring(i, j) == arg)
return getCookieVal (j);
i = document.cookie.indexOf(" ", i) + 1;
if (i == 0) break;
}
return null;
}

function SetCookie (name, value) {
var argv = SetCookie.arguments;
var argc = SetCookie.arguments.length;
var expires = (argc > 2) ? argv[2] : null;
var path = (argc > 3) ? argv[3] : null;
var domain = (argc > 4) ? argv[4] : null;
var secure = (argc > 5) ? argv[5] : false;
document.cookie = name + "=" + escape (value) +
((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
((path == null) ? "" : ("; path=" + path)) +
((domain == null) ? "" : ("; domain=" + domain)) +
((secure == true) ? "; secure" : "");
}


var expDays = 30;
var exp = new Date();
exp.setTime(exp.getTime() + (expDays*24*60*60*1000));

function DeleteCookie (name) {
var exp = new Date();
exp.setTime (exp.getTime() - 1);
var cval = GetCookie (name);
document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
}


function resetCookie(param) {
//alert('resetting cookie... ');
//var name = "marks";
var exp = new Date();
exp.setTime (exp.getTime() - 1);
var cval = GetCookie (param);
document.cookie = param + "=" + cval + "; expires=" + exp.toGMTString();
}


function getCookieVal(offset) {
var endstr = document.cookie.indexOf (";", offset);
if (endstr == -1)
endstr = document.cookie.length;
return unescape(document.cookie.substring(offset, endstr));
}

This is what the web page looked like with my code in place:






This is what the output looked like from the web page.








When I checked the layout in another browser, it hit me, that the solution I had created was not the one being asked for. This solution would give every user in each unique browser their own counters. What I needed was a solution that would persist outside of any browser and user.

I would need a server side solution, and a database that would store the counter information, persist and read/reset. Hmmmmm

I turned toward PHP, since I had a PHP server available and a mySQL database that could store the data.

Step one: Create a class that would represent the counter, using PHP.

Step two: Build a persistence mechanism for the counter data.

Step three: Modify the javascript to read PHP class file(s).

Step four: Use an AJAX technique to call the counter update and increment functions, while outputting their results in the html page. This would be tricky, but I had done similar things using AJAX and Jquery in the past.

Continued in next post.....



Thursday, October 8, 2009

OOP, Beans, Gateways, Services

Today - i went into a very old part of an application and revised some very old bus. logic. I am giving a facelift to part of a web site and while looking at a view page decided i would change a little logic. There was a call to the database in one of the view pages, since the beans being served up via the application to the view did not have all the data needed. This is a little lazy, to put a call to the db in a view, but understandable, especially if you do not have alot of background in MVC, Gateway, DAO, Front end controller design patterns, not to mention OOP.

After of a bit of consternation about what to do and finding another place in a related view file where i needed a bit more data, i decided to do it right. That meant going into the domain and finding the bean and dao responsible for getting and setting the data for the bean.

First, i needed to be sure i could add the little "bits" of data needed before adding them to the bean and dao. The data i wanted to add was from another database on the same server. No server linking needed! I spent a few minutes looking up how to do this and added the code to the read function of the dao that joined the existing table to a new one in onther db.

Next i added the getter and setter methods to the bean, reloaded the controller - since they cache my beans (since im using Coldspring and machii) - a couple MVC / oop frameworks.

Finally, i added the call to the new bit of data now being server up by the bean and whalla - im in busniess - logic all where it should be.

amen

Wednesday, September 2, 2009

object programming coldfusion

I just spend about 3 hrs trying to figure out where a piece of output was coming from. This is a bit of a rant against object oriented programming, at least in CF. First off, the resome i was looking for this piece of code is to analyze a program area in the application. For some users, who have alot of data, this list that is build and displayed to the user takes way too long to build. Sometimes in excess of 60 seconds. I think it has caused us to change the loop time out setting in the administrator.

This application is build in a framework called machii. Machii is capable enough framework, a bit heavy, meaning a lot of overhead and files that comprise the framework. Machii makes it easy enought to know where to begin looking for the problem. Follow the event, look for listeners that are calling into a service layer of some sort - follow the service layer into a gateway or DAO object - throw in another framework, coldSpring, and you can get pretty confused pretty fast. Thats a different story.

I traced down into the machii event and found the listener calls and the view files that appeared to be responsible for outputting this slowly developing content. The view files did not have much content in it - just a mysterious call to an XML function. My investigation then took me in another direction, until i found where the content was getting gathered, not displayed. The output is stored in a group of Objects and then xmlized by another function. Hmmmmm, is there a really compelling reason why this content was not simply being returned as a query object? Light, easy... But not object pure. I think this may be a case of the developer being a bit of a OOP purist and treating CF like Java. And why are we xmling the result? What is the gain here? More overhead and complexity. Perhaps its a case of "we may need this later in this portable format"...rather than YAGNI or KISS. Anyway, this feels like alot of overcooking to me. It took me way too long to find this class that was extending a base view event class - to just find about 15 lines of code responsible for actually outputting content.

Bottom line - private functions in cfcs should not be outputting anything. Let the cfcs do their job of getting data and making decisions about what to do - leave the view files to outputting the results.

OOP is good, in the right places, but not always in every situation.

Thursday, April 2, 2009

OO birds eye view

OO - think in terms of objects

OO - think in terms of data and functions together in a single entity

OO - think in terms of reference, not value

OO - think in terms of encapsulation (self sufficiency)

OO - think in terms of

OO - think in terms of singleton -vs- transient

OO - think in terms of state of an object

OO - think in terms of security (accessors and modifyers) - getters / setters

Software Architecture (MVC)

think in terms of layers

think in terms of separation of concerns

think in terms of maintenance

think in terms of clarity

think in terms of sessions

Desing Patterns

think in terms of DAOs, Gateways, Beans

think in terms of anti pattern (3- 1) - not every entity needs its own service, gateway and DAO

a service should serve more than just a single DAO and Gateway.

think in terms of doctor - patient (a doctor has many patients)

think of singletons -vs- transients

singletons application wide, transients user wide

transients (have state)
singletons (no state)

*for the singletons (many users using a single instance) think in terms of varing
every variable in it. these are objects stored in application scope.

Frameworks

think in terms of maintenance

thinks of tradeoffs

think of consequences

think of payoff (work up front, payoff later)

think of overhead

think of consistency - predicatability


OO programming from domain to presentation layer

I am always trying to get a better handle on OO programming techniques. I come from that produral background and i think it is always influencing the way i see layer and communication.

If i can think of the objects as two types
singletons - only one copy exists per session per user - these have no state
(these are DOA's, Gateways, Services)

transient - have state and need to keep the state while living in memory
(these are beans or value objects)

In my main application that i support, this means

transient objects or beans that have state (specific data associated with them) are
assessments
standards (performance indicators)
resources

Each of these beans is updated when a new one is selected.

For each user a set of each is created (assesment, resourse, standard) value bean. They are created in the service that is used to communicate with them.

There is only a single service object (a singleton) that is created once when the application starts. The singleton is placed in a application scope and is then accessible to every user who comes to the site. They all share the same instance of the object or class. There is no race concerns because the application (coldFusion) takes care of the threading.

So - one instance of the services for all the users who come to the site. A collection of objects for each user when they initially hit a part of the site that uses the service for those objects.

Also in the service, besides the instantiating of the transient objects, are the rules for when to call the other singletons. The service is the big DOG. It knows about the other services and the other singleton and transient objects. If you looked into the init() of the service.

Again - think like this

- whenever you have data to persist for a value object
- ensure a copy of it exists in memory
- use the DAO to get the updated data (if reading from table)
- use the Form or URL parameters if updating to a table)
- update the current bean in memory
- pass a reference to the bean from the service into the DAO/Gateway when necessary
- pass a reference back to the presentation layer when feasible.

I dont think rules like this are always adviseable, some times it just makes sense to pass by value and not reference. But, in the spirit of OO - think like this by default and work from that position.

I did this in a couple view pages i was recently working on. The the user clicked on a resource or assessment or standard, if the request was to view something - then i would go to the service who who use the id and existing reference to the value object, and pass them both into the DAO gto get the details from the DB. If the request was a update, then i would use the updated values in the form fields and pass them along into the service and update the current bean using the arguments passed in and then pass back a reference to the value (bean) object. now in my presentation layer im referencing the bean that is in memory. Im not actually going back into the db (which is a no no from a MVC perspective) - but referencing the value bean via the object passed along. Encapsulationa and OO techniques!

Im not sure if this is really the smartest way to go about this, but it is my attemp to continue to push out OO concepts and challenge myself to learn to think in terms of Objects and encapsulation.

cheers
What i started to do recently, in the spirit of OO, is to return the pointer or reference to the presentation layer.













Tuesday, February 3, 2009

3rd party editors - usability

Ive build a utlility application that uses a 3rd party editor called Fckeditor. Its a popular editor, that is implemented in each of the major platforms, java, coldfusion, asp, etc..

I brought it into play originally for another utlitity application that i was working on. Each of the two utilities are about feeding data to a relational db.

Each of the two utilities needs to upload files as part of their jobs. Lots of text, with images needed as well as other upload types. the challenge is that each utility needs to store the uploads in different places. I could, i suppose use different implementations, meaning give each utility its own set of core files (thats about 400 total) - seems a little overkill. What im looking to do is dynamically inform the path where the editor will upload the images to.

Ive dug into the editor a bit and found the upload configuration file that is defining the path where the uploads are going. Now i need to figure out the smartest way to inform the editor where it being used from and pass that variable into the configuration file to dynamically set the userpath.

If this gets too hairy, i can always use plan A, each utility having its own implementation of the fckeditor core files.....but i really dont want to do that.

stay tuned

Im back - im thinking i may try to scale down the size of the fckeditor core files - since alot of them are for implementations that i am not using. Then each Utility could have its own version of the core files. Then, each would have its own

fckeditor.editor.filemanager.upload.cfm.config.cfm

and i could set one where it is now and the other where it needs to be, including the dynamic updating still needed.
Resources path = userfiles/image
assessments path = assessment/assessmentID/

perhaps...i need to continue my heavy lifting around this before moving into a implementation.

Im thinking about creating a utility helper CFC where i could set a session variable or application and use that to inform the assessments *dynamic portion. In the assessments app, im using a framework where i could use a build in plug in point to instantiate the helper object upon application startup. "bootstrapping".