28
Sep
Posted by Chris Hartjes in PHP. 1 Comment
In my spare time I’ve been banging away at writing the required unit tests for the Zend_Service_Audioscrobbler component that Derek and I had started. I finished all the unit tests for the user based functions, which is a nice milestone. Then I decided to go back and actually read the comments made from the proposal. Oops. I discovered there were a bunch of changes that the folks at Zend said needed to be made in order to accept them. I agree with most of them. To save you the trouble of scrolling all the way to the bottom, here they are:
Zend Comments
The proposal is approved on the condition that the following issues are addressed by the proposal author.
Public properties make the set* methods redundant. Ideas for resolution:
* Change the properties to be protected and using the existing set* methods along with new corresponding get* methods.
* Override __get() and __set(), storing properties in a protected array.
Another option would be to pass the “properties” as method arguments:
< ?php
$as = new Zend_Service_Audioscrobbler();
$profileInfo = $as->userGetProfileInformation(’BigDaddy71′);
$relatedArtists = $as->artistGetRelatedArtists(’LCD Soundsystem’);
// …
?>
No underscores within variable names and compliance with other coding standards.
What is the reason that setDate() and getInfo() methods are designated private? Should they not be inherited and accessible by subclasses, and if so, why not?
We should leverage Zend_Date as it becomes available for date-specific operations.
How do Zend_Service_Audioscrobbler and the Audioscrobbler web services support limiting the number of records returned by a request?
The API presented causes extra effort to programmatically select functionality, due to the practice of essentially embedding options into the method names. Usually function names accept parameters to select between different, related behaviors. For example, the proposal shows:
public function userGetRecentWeeklyArtistChart()
public function userGetRecentWeeklyAlbumChart()
public function userGetRecentWeeklyTrackChart()
public function userGetPreviousWeeklyArtistChart()
public function userGetPreviousWeeklyAlbumChart()
public function userGetPreviousWeeklyTrackChart()
Using class constants having string values we could nicely refactor the above list of methods to something like:
getChart($type, $recent = true)
Similarly, what about:
// source = ‘user’ | ‘artist’
// type = ‘artists’ | ‘albums’ | ‘tracks’ | etc.
getTop($source, $type)
All very sensible, so I’ve got some refactoring work to do.
27
Sep
Posted by Chris Hartjes in Chris' Brain. No Comments
To make up for the lack of posting, go read this amazing post about Good Agile, Bad Agile. One of the most interesting things I’ve read in a while.
26
Sep
Posted by Chris Hartjes in Chris' Brain, PHP. 22 Comments
Many thanks to the CakePHP mailing list for pointing out some really dumb errors I made along the way getting this stuff to work. It turns out that case-sensitivity does actually matter at time.
Okay, for a project at work I was asked to add graphs to some of the reports I'd already created. So I looked around for solutions for graphing in PHP and stumbled upon PHP/SWF Charts as a solution. Basically, it comes in two parts: a Flash movie that generates the charts for you and a PHP library that sends data to the Flash movie to create those great charts.
So, first thing I did was download the package from the PHP/SWF Charts site. I then dumped everything into a /graphs directory in my web root. Why? Well, that's the only way I could get the thing working and I am a disciple who worships at the altar of Get It Done because there are other things I'd rather deal with. I'm sure one of the CakePHP people who runs across this tutorial can correct things for me so it's all inside the framework itself.
Now, that the library is unzipped and in it's own directory, we go and start altering the code I need to make this work. First thing I did was add a subdirectory to my app/views directory called graphs and added in users.thtml
PHP:
-
<?php
-
vendor('charts');
-
$chart['chart_data'] =
array($header,
$member_data,
$visitor_data);
-
$chart['chart_type'] = 'stacked area';
-
$chart['axis_category'] =
array('size' =>
9);
-
$chart['chart_grid_h'] =
array('thickness' =>
1);
-
$chart['chart_grid_v'] =
array('thickness' =>
1);
-
SendChartData($chart);
-
?>
This code will pass the info I've passed to my view to the flash component. This is the part that will spit out the chart, but I also had to add in some code to the main view for the report itself so the graph will show up
PHP:
-
<div align = "center">
-
<br /><br />
-
Users Online For Entire Network For Last 24 Hours
-
<br /><br />
-
<?php vendor("charts") ?>
-
<?php echo InsertChart
('/verticalscope_stats/img/charts.swf',
"/graphs/charts_library",
'/verticalscope_stats/graphs/users/' .
uniqid(rand(),
true),
800,
250,
'FFFFFF') ?>
-
</div>
As you can tell, I omitted a step above. When I downloaded the charts package I stuck the charts.swf Flash movie in app/webroot/img so I can find it later. The uniqid stuff is to make sure it doesn't get cached by your browser.
Okay, so now here's the code I created to pull results from our database, munge the data and pass it over to the view:
PHP:
-
class GraphsController extends AppController
-
{
-
var $name = 'Graphs';
-
var $uses =
array('OnlineUser');
-
-
public function users()
-
{
-
// create graph for charts based on users online for the past 24 hours
-
-
-
-
-
-
-
-
$this->OnlineUser->recursive = -1;
-
$temp = $this->OnlineUser->findBySQL("SELECT MAX(ou_date) as max_ou_date FROM online_users");
-
$max_ou_date = $temp[0][0]['max_ou_date'];
-
$result = $this->OnlineUser->findAll("DATE_SUB('$max_ou_date', INTERVAL 1 DAY) <= ou_date");
-
-
foreach ($result as $data) {
-
// Now we have to find the top value for each hour within
-
// all the data for an hour
-
-
$site_id = $data['OnlineUser']['site_id'];
-
-
if (!
isset($members[$site_id][$hour])) {
-
$members[$site_id][$hour] = 0;
-
}
-
-
if ( $members[$site_id][$hour] <$data['OnlineUser']['members']) {
-
$members[$site_id][$hour] = $data['OnlineUser']['members'];
-
}
-
-
if (!
isset($visitors[$site_id][$hour])) {
-
$visitors[$site_id][$hour] = 0;
-
}
-
-
if ( $visitors[$site_id][$hour] <$data['OnlineUser']['visitors']) {
-
$visitors[$site_id][$hour] = $data['OnlineUser']['visitors'];
-
}
-
-
}
-
-
// Phew, that's a lot of dating munging. Okay, now we need to cycle through
-
// the raw data and create totals for each hour
-
-
$visitor_data =
array( );
-
-
foreach ($members as $site_id => $member) {
-
foreach ($member as $hour => $count) {
-
-
if (!
isset($member_count[$hour])) $member_count[$hour] =
0;
-
-
$member_count[$hour] += $members[$site_id][$hour];
-
}
-
}
-
-
foreach ($visitors as $site_id => $visitor) {
-
foreach ($visitor as $hour => $count) {
-
if (!
isset($visitor_count[$hour])) $visitor_count[$hour] =
0;
-
-
$visitor_count[$hour] += $visitors[$site_id][$hour];
-
}
-
}
-
-
$header[] = "";
-
$member_data[] = "Members";
-
$visitor_data[] = "Visitors";
-
-
foreach ($member_count as $hour => $count) {
-
$header[] = $hour;
-
$member_data[] = $count;
-
$visitor_data[] = $visitor_count[$hour];
-
}
-
-
$this->set('header', $header);
-
$this->set('member_data', $member_data);
-
$this->set('visitor_data', $visitor_data);
-
$this->layout = 'ajax';
-
}
-
}
-
-
?>
So, I think that's all you need in order to get your code working and talking nicely with PHP/SWF charts. I'll go over this stuff again to look for any errors and clear up anything that looks confusing.
20
Sep
Posted by Chris Hartjes in Uncategorized. 1 Comment
...until the stuff broke when I moved it into production. *sigh*.
I was going to post a tutorial on how to get PHP/SWF Charts to work with CakePHP. Everything is working okay on my iBook, but when I moved it up to the production server the graphs stop working and I get an error that is not reported on my iBook. CakePHP reports that it's missing some default layout for AJAX, which is weird considering it's exactly the same code running in both environments. Smarter people than me will tell me the answer, I'm sure.
15
Sep
Posted by Chris Hartjes in Uncategorized. 1 Comment
Well, I made it through the conference in one piece (except for the head cold I picked up from my oldest daughter, and has spread to my wife as well). I also noticed I'm getting lots of love on the web from Cal Evans over at DevZone and some nice posts from the folks over at PHPDeveloper.org. I wasn't looking for this kind of exposure but it sure is nice.
So I as wrap up my day with some organzing of future projects and taking another stab at using Eclipse and the Zend PHP plugin for it (I'd love to use Komodo but can't afford to pay for a copy of it) I have some thoughts on what I saw and the people I talked to.
By far, the most informative session for me was the one Ilia Alshanetsky gave on migrating to PHP 5.2 from PHP 4 or PHP 5.0/5.1. That will be used as ammunition in a discussion with my boss about what version of PHP to use when we start doing are site reorganization for the forum sites. I also enjoyed some cool chats with John Coggeshall about Zend Framework and his ZFApp tool which he has asked me to help him do some work on (once he gets a repository for it created). He was gracious enough to let me take a look at it before he gave his talk today and it's a very interesting tool. I look forward to getting a chance to analyze his code and figure out how the heck he did it all.
I also got to meet some people that I had been following online but never gotten to meet before: Cal, John, Sebastian Bergman (we had an interesting little chat about efforts to integrate Selenium with PHPUnit3 and a tool under development called SmartFrog), Paul M. Jones (of Solar and Savant fame). The big upshoot to this conference was that I got a chance to give a talk that was well received, so I'm definitely going to submit this same proposal to other PHP conferences since the talk should have a decent shelf-life. Anyhow, that's it for me about php|works.
Recent Comments