Page 1 of 5

Building Example Pager Class

Posted: Sun Feb 05, 2006 7:09 pm
by Christopher
In this thread (viewtopic.php?t=43622) was a discussion Pagers (one of the comon questions around here). I found a few that are regularly referenced here and commented on them. There may be others around as well. I have one as well but it is too complex to use as an example. I had suggested that we build a fairly simple, solid, "better practices" example that we can refer people to when they ask Pager questions.

I think I can summarize my thoughts in just a few points:

- Build a class something like jcart's pagination class.
- Allow for multiple formatters such as jspro2's create_pagination()
- Make it database independent
- Probably it will end up as a couple of classes

So I am wondering if others are interested, especially jspro2 and jcart whose code could be used as a base. We could do the design/coding session right in this thread so people could see the process. Anyone interested?

Posted: Sun Feb 05, 2006 7:18 pm
by feyd
I think it's definitely a worthy excersize, and would allow newcomers to get a feel for TDD among other concepts. Although we may need/want to have a separate thread that does explanations, but maybe not, maybe we coudl do them here.

As some may know, the Revival Corp may get a build of MediaWiki up very soon as a ~new version of what PHPComplete was originally, a site where newcomers to php can not only learn the basics, but become more aware of all the fun issues we often deal with. So the explanations, along with the thought processes could also be translated there once we get rolling here. Just something to keep in mind. :)

Posted: Sun Feb 05, 2006 9:46 pm
by Christopher
feyd wrote:I think it's definitely a worthy excersize, and would allow newcomers to get a feel for TDD among other concepts. Although we may need/want to have a separate thread that does explanations, but maybe not, maybe we coudl do them here.
I agree, though as there seem to be few TDDers here I though we could just design it stepwise without the tests to show the issues and thought-processes behind each step of the design. I think that's what helps most.

I was hoping for a small group of coders like you, jspro2 or jcart to go through the process with. If there is no one else interested, maybe you can "mentor" / "peer-review" me through the process.
feyd wrote:As some may know, the Revival Corp may get a build of MediaWiki up very soon as a ~new version of what PHPComplete was originally, a site where newcomers to php can not only learn the basics, but become more aware of all the fun issues we often deal with. So the explanations, along with the thought processes could also be translated there once we get rolling here. Just something to keep in mind. :)
Sounds cool.

Posted: Mon Feb 06, 2006 3:14 pm
by Christopher
Hey feyd, it seems there were not takers for this so are you interesting in proceeding? If so we can either just jump in and go back and forth, or do it pair programing style where we take roles of the the driver and observer (switching occasionally if you like). Either way we could start with a statement something like this:

"Implement a PHP class or classes that allow arrays and DB records to be displayed paged in various ways on website. It should be as flexible as possible while meeting the goal that code is simple enough for newbies to use, understand and learn from. "

Posted: Mon Feb 06, 2006 3:30 pm
by John Cartwright
Hey arborint,
I hadn't come across this thead until now, but I am definantly interested.
I am a bit busy with other stuff at the moment, so if your not in a rush to produce anything quality then count me in :)

Posted: Mon Feb 06, 2006 3:56 pm
by feyd
I'm definitely in. Maybe we should wait a little bit for us to firm up about the Wiki so we can do the whole thing there? We still need to figure out integration with the user tables and junk.. so it may be worthwhile to just start it here for now. Since I'm not the best at object oriented stuffs, I may take a bit of a backseat, letting you guys run wild while I inject possible questions and explainations about things at various points that may be confusing the newcomers.

Posted: Mon Feb 06, 2006 5:06 pm
by Christopher
feyd wrote:I'm definitely in. Maybe we should wait a little bit for us to firm up about the Wiki so we can do the whole thing there? We still need to figure out integration with the user tables and junk.. so it may be worthwhile to just start it here for now. Since I'm not the best at object oriented stuffs, I may take a bit of a backseat, letting you guys run wild while I inject possible questions and explainations about things at various points that may be confusing the newcomers.
Great. I think starting here and having at least one pass through the design would be good. This forum will be more interactive than a wiki and we can write a cleaned-up narrative of this converstation for the wiki if we come up with something worthwhile.

It is also quite possible that when we have gone through once we will not be compeletly happy with the result so another pass (all of us being smarter then) may be needed. Or we may find that we need two separate pagers: a really simple pager and a fully functional pager, because we can't meet all of our requirements with one. Who know at this point.

Since Jcart is in maybe we can get going. As I recall with pair programming, they say that three programmers one two computers is a better "pair" it ends up, plus three can vote on features easier.

Posted: Mon Feb 06, 2006 5:20 pm
by Christopher
Jcart wrote:Hey arborint,
I hadn't come across this thead until now, but I am definantly interested.
Excellent. I'm glad you found it.
Jcart wrote:I am a bit busy with other stuff at the moment, so if your not in a rush to produce anything quality then count me in
I am busy as well, but I think we can take our time and see how it goes.

One question I have since you are involved is whether we should refactor your class or start from scratch? I would favor starting from scratch for a couple of reasons, the main one being that your class is very nice and makes a reasonable set of design tradeoffs -- so I think it stands on its own as a good solution. If we build something with a slightly different spin, then there will be two classes around that people can choose from.

Part of it depends on whether you and feyd agree with my proposal to create clearer dependencies by separating, for example, the database query, request processor/values calculator, and the HTML outputter(s). So what are your thoughts?

Posted: Mon Feb 06, 2006 5:34 pm
by John Cartwright
Yes I would definantly start from scratch for a couple reasons.

1) That class I wrote was basically a quick solution, and was specifically designed with my needs in mind. I would prefer to use a better example of OOP principles.
2) There could be better seperation of the layers, as you mentioned.
3) It would be educational for everyone else as to why we make certain decisions.

I really like the idea of creating two working examples on how to approach this problem.. so we can really focus on OOP programming, and not specifically what the program is. So in one version, we could create a class much like the one I did -- improved mind you -- that tackles all of the task in one class.. we all know this is generally not good OOP programming, but it gets the job done. Then, in our next version focus much more on seperation of design pattern.

Posted: Mon Feb 06, 2006 6:16 pm
by Christopher
Jcart wrote:Yes I would definantly start from scratch for a couple reasons.

1) That class I wrote was basically a quick solution, and was specifically designed with my needs in mind. I would prefer to use a better example of OOP principles.
2) There could be better seperation of the layers, as you mentioned.
3) It would be educational for everyone else as to why we make certain decisions.
Great. It sounds like we are starting out in the same page.
Jcart wrote:I really like the idea of creating two working examples on how to approach this problem.. so we can really focus on OOP programming, and not specifically what the program is. So in one version, we could create a class much like the one I did -- improved mind you -- that tackles all of the task in one class.. we all know this is generally not good OOP programming, but it gets the job done. Then, in our next version focus much more on seperation of design pattern.
I agree. I think a single, simple class that just does the basic Use Cases well and makes it easy for a newbie to get the thing running is in the spirit of PHP.

I would actually suggest that we build it full OO first and then combine into a single class once we have a fuller understanding of the implementation. The full OO version is going to be clearer design-wise. So which way is it? Feyd? Our first vote? ;)

Posted: Mon Feb 06, 2006 7:20 pm
by feyd
I like both ideas, however going the full OO way, seem sot make more sense. We'll refactor and refactor as we go along, so things will solidify in the end. Some UML diagrams may be helpful. Maybe a crash course in UML would be a good side bit. hmm... so many things to add onto the list of things or the Wiki :)

Posted: Mon Feb 06, 2006 10:52 pm
by Christopher
feyd wrote:I like both ideas, however going the full OO way, seem sot make more sense. We'll refactor and refactor as we go along, so things will solidify in the end.
Well, in true Agile fashion if we don't have a certainity we will kick that decision down the road a little.
feyd wrote:Some UML diagrams may be helpful. Maybe a crash course in UML would be a good side bit. hmm... so many things to add onto the list of things or the Wiki :)
So Feyd had added doing UML diagrams AND adding UML support to the Wiki to his apparently empty plate! ;)

OK ... Lets get started. Here are some parts and some rambling thoughts:

1. Get Request parameters. This is pretty simple, but I think we could improve over many designs by not hard coding the paramter name.

2. Deal with data records. Feyd said that the system he uses can page any kind of data -- which makes sense. Our goal should be that kind of independence. So we should allow array data to be paged. But what the most commonly requested Use Case is for something that manages the LIMIT clause of an SQL query.

3. Do the calculations to determine the start and end record numbers for the page based on the page number. We need to determine what data values we want to make available and how (var or method?) and what settings we have (e.g. number of records per page). Also if we support both arrays and DB then we need to decide where to deal with zero or one based.

4. Output HTML. We want this to be separate because there are many ways to show the paging links. We will need to decide what the output of the default outputter is. And we need to decide what links to support next/prev, first/last. As a second example we can adapt jshpro2's create_pagination() function.

Dependencies (I think):

Pager --> Request
Pager --> Data Mgr
Outputter --> Pager

Posted: Mon Feb 06, 2006 11:55 pm
by feyd
I'm seeing a pluggable system.

Input handling
An input handling class could be employed to allow a user to customize how the inputs are processed and found. For example, an implementation of the interface could use pathinfo to build the information bits needed by the main class. This class should also have a URL generation function for the links created (for use by the output), since that leads to the input characteristics it'll look for.

Data interface
Having a data interface would allow implementations for both DB and array based handling of information. Special cases for the main class would be then handled by the implementation as it is handling the actual data fetches, wherever they may come from. A default of an array handler would probably be best since it's the most generic.

Page numbering callback
Having an callback (with defaults, of course) for creating the page numbering display would allow for simple customization.

Output
After trimming and various processing by the main class, which under my idea would really just be a sequencial delegator, all the information collected by the various outputs from the above systems would be passed to this class. This class determines final appearance and output (or not) of the actual paging. It may be XML, XHTML, RSS, or C.. who-knows?

Posted: Tue Feb 07, 2006 1:13 am
by Christopher
feyd wrote:I'm seeing a pluggable system.
Starting to look like a framework. This is always a struggle for me because what you or I might consider a bare bones system looks very complex to new PHP programmers.
feyd wrote:Input handling
An input handling class could be employed to allow a user to customize how the inputs are processed and found. For example, an implementation of the interface could use pathinfo to build the information bits needed by the main class. This class should also have a URL generation function for the links created (for use by the output), since that leads to the input characteristics it'll look for.
We could do a Request class, but I'm not sure it gets us much and it adds a bunch of code that newbies have to wade through. I was thinking that intval($_GET[$this->page_parameter]) might do for this pass. I use a Request class in my own code so I definitely like the idea -- I just worry about complexity.
feyd wrote:Data interface
Having a data interface would allow implementations for both DB and array based handling of information. Special cases for the main class would be then handled by the implementation as it is handling the actual data fetches, wherever they may come from. A default of an array handler would probably be best since it's the most generic.
At a minimum it just needs to tell us the Total Rows. We need to decide if we want to fetch data internally or have the application responsible for dealing with the rows.
feyd wrote:Page numbering callback
Having an callback (with defaults, of course) for creating the page numbering display would allow for simple customization.
I'm not clear on what you mean by "callback" but in OO/pattern speak it sounds like Decorator. My guess is you want the programmer to provide formatting code that is called to render each link. Sounds good, but it is really not clear to me yet how this should be implemented.
feyd wrote:Output
After trimming and various processing by the main class, which under my idea would really just be a sequencial delegator, all the information collected by the various outputs from the above systems would be passed to this class. This class determines final appearance and output (or not) of the actual paging. It may be XML, XHTML, RSS, or C.. who-knows?
I like the idea of being able to support different output renderers. The thing that is not clear to me is whether we should render the whole thing or just provide methods that can create the various links and let the application render everything else. Jcart's class (here) does the latter which is was along the lines of what I was thinking about. But maybe we should go farther?

Here is a quick hack of a pseudo-implementation based on the dependencies I listed above to show generally what I am thinking:

Code: Select all

// create a data object that has the interface needed by the Pager object
$datasource = new PagerArrayDatasource($myarray);
// create pager using values from datasource and request parameters
$pager = new Pager($datasource);
// create Outputter that gets its values from Pager object
$output = new PagerHTMLOutputter($pager);
$output->render();
// Outputer might also might have specific methods getPrevLink(), getNextLink(), getCurrentPage(), getTotalPages()

Posted: Tue Feb 07, 2006 1:51 am
by feyd
arborint wrote:Starting to look like a framework. This is always a struggle for me because what you or I might consider a bare bones system looks very complex to new PHP programmers.
my post was directed at end goal points, not just first pass. Yes, my end goal would resemble, if not be, a framework of sorts. Obviously a complete framework is outside the boundries of this excersize, but one can push towards it. ;) It probably does go over the heads of a newcomer, which is why it's version 3 or 4 not 1. :)
arborint wrote:We could do a Request class, but I'm not sure it gets us much and it adds a bunch of code that newbies have to wade through. I was thinking that intval($_GET[$this->page_parameter]) might do for this pass. I use a Request class in my own code so I definitely like the idea -- I just worry about complexity.
It's perfectly fine to use the basic straight-forward intval() et al for first, maybe even second passes. It certainly can get complex, but that is up to the implementation of the request class. The paging class should only need to talk with 1 to maybe 3 functions from it, of which should overall be fairly simple in implementation depending on how far gone one goes down OOP lanes ;)
arborint wrote:At a minimum it just needs to tell us the Total Rows. We need to decide if we want to fetch data internally or have the application responsible for dealing with the rows.
True, the most basic would give total rows and "here's the data."
arborint wrote:I'm not clear on what you mean by "callback" but in OO/pattern speak it sounds like Decorator. My guess is you want the programmer to provide formatting code that is called to render each link. Sounds good, but it is really not clear to me yet how this should be implemented.
I'm using PHP's definition of callback in this instance (http://php.net/language.pseudo-types#la ... s.callback.)
arborint wrote:I like the idea of being able to support different output renderers. The thing that is not clear to me is whether we should render the whole thing or just provide methods that can create the various links and let the application render everything else. Jcart's class (here) does the latter which is was along the lines of what I was thinking about. But maybe we should go farther?
Both should be possible using a Fascade to allow any number of choices in output, including none at all (shunting the data to a separate object for later rendering by the application.)
arborint wrote:Here is a quick hack of a pseudo-implementation based on the dependencies I listed above to show generally what I am thinking:

Code: Select all

// create a data object that has the interface needed by the Pager object
$datasource = new PagerArrayDatasource($myarray);
// create pager using values from datasource and request parameters
$pager = new Pager($datasource);
// create Outputter that gets its values from Pager object
$output = new PagerHTMLOutputter($pager);
$output->render();
// Outputer might also might have specific methods getPrevLink(), getNextLink(), getCurrentPage(), getTotalPages()
That's roughly what is in my head for the initiation. :) Although I might put that into a function to simplify and make sure the sequence in performed in proper order.. ;)