I want to build a paginator class, but i'm not sure what the best method is. I see many different codes on the internet that confuses me.
My data is stored in a MySQL database. Do i have to give a query to my pagniator class so that it can retrieve the data out of MySQL for me (and of course it will automatically do some pagination calculations after that)? Or do i get all the data from a model first, then supply the returned array from that model to the paginator class?
In either way i'd probably have to do another query to get the "total" amount of records and pass that result to the pagninator class as a separate param.
Once i know how to get started then i know how to pick up the rest. I'm just not sure how to pass in the data to the paginator class and what kind of data.
Any idea how to build a good paginator class?
A well designed OO Paginator class should be independent of your data and your database.
It should take parameters like count, page, and per_page, and should return objects that can be used for Dependency Injection into a Model for generating queries with the appropriate LIMIT, or into a PaginationHelper class for rendering the appropriate HTML.
Example of what might be a good Paginator interface (given 10 minutes of thought in this):
/**
* Your pagination master class
*/
interface iPaginator {
public function __construct($total_count, $count_per_page, $current_page=1);
public function getPaginationLimiter();
public function getPaginationHelper();
// These return iPaginatorPage objects
public function getCurrentPage();
public function getNextPage();
public function getPreviousPage();
public function getTotalCount();
public function getCountPerPage();
public function getPageCount(); // Calculated
}
/**
* Page representation
*/
interface iPaginatorPage {
public function __construct($page_number, $start, $end);
public function getNumber();
public function getStart();
public function getEnd();
public function getCount(); // Calculated
}
/**
* Helper for rendering the UI
*/
interface iPaginationHelper {
public function __construct(iPaginator $paginator);
public function render();
}
Example of how you could integrate into your model, by extending your base model, and then having your application models extend PaginatorModel instead of Model:
class PaginationModel extends Model {
public function query($sql, iPaginatorPage $page = null) {
if (!empty($page)) {
$start = $page->getStart();
$length = $page->getCount();
$sql .= " LIMIT ({$start}, {$length})";
return parent::query($sql);
}
}
}
Check the pager implementation from Pear. It's a very nice class, simple to use and with a lots of cool features.
create class, and have function like this:
function resultset($required_filters, $table, $pagenum, $records){
$getCount='SELECT count(*) from table';
$sql="SELECT ".$required fields." FROM ".$table." LIMIT ".(($pagenum-1) * $records).",".$records;
$sqlres=...
return array($getCount, $sqlres); }
call this function as list($rescount, $arrData)=resultset(all
parameters);
and for pagination use some for loop to display page numbers...for total $rescount pages,
using get you can show current pagenum highlighted
Related
All my classes that connect to a database need to get values of custom columns from their respective tables. So instead of coding a function for each class, is there a way for me to implement a base class from which my classes extend and I can use that base class function to easily get and update data on my database (at least for simple data).
class Users extend BaseClass
{
private $table = "users";
private $columns = ["name", "email", "password"];
}
so from an outside function, I can access the email value like this
Users->where("name", "John")->getEmail();
or possibly
Users->where("name", "John")->get("email");
I could also use this method to update data to the database. The functions where should be universal so it should exist in BaseClass. (I know the database queries that I should use, what I want to know is how to call get after calling where and also possibly setting multiple where requirements).
Users->where("name", "John")->where("last_name", "Smith")->get("email");
I think you want something like this
abstract class BaseClass
{
private $where_clauses=[];
private $columns=[];
private $table='';
protected function setData($table,$cols){
$this->columns=$cols;
$this->table=$table;
}
public function where($key, $value){
$this->where_clauses[$key]=$value;
return $this;
}
public function get($col){
$sql='SELECT '.$col.' FROM '.$this->table.' WHERE';
$first=true;
foreach($this->where_clauses AS $key=>$val){
if(!$first) sql.=' AND ';
$first=false;
$sql.=$key.' = '.$val;
}
// RUN QUERY, Return result
}
}
Note that the where function returns a reference to $this, which is what let's you string the function calls together (not tested the code). This would also need some adapting to let you put two conditions on the same column.
On my site at the beginning of every script I include a "bootstrap" script which queries a few things from the database, does some calculations and then loads the variables into constants that I define one by one.
Some examples are:
define("SITE_ID", $site_id); // $site_id is pulled from a field in the database
define("SITE_NAME", $site_name);
// pulled from a field in the same row as the above
define("STOCK_IDS", $stock_ids);
//computed array of stock id integers from a different query.
//I perform logic on the array after the query before putting it in the definition
define("ANALYTICS_ENABLED", false);
// this is something I define myself and isnt "pulled" from a database
Now, I have many functions on the site. One example function is get_stock_info. And it references the STOCK_IDS constant.
What I want to do is have a class which has the above constants in it and the get_stock_info function.
Would the best approach to be have an empty class "site", create an instance of it and then afterwards define the static variables above one by one? Or is that not a good way and should I move all of of my logic which pulls from the database and calculates SITE_ID, STOCK_IDS, ANALYTICS_ENABLED etc into the constructor instead?
Ultimately I want the class to contain all of the above info and then I would be able to use class methods such as site::get_stock_info() and those methods will have access to the constants via self:: or this.
There's a lot more I want to do than that but that would give me enough to figure the rest out.
I think this approach isn't the best. You should consider not using constants as your values aren't constant. For your case it is better to have a class with classic getters methods.
Something like this:
class SiteInfo
{
private $siteId;
private $siteName;
private $stockIds;
private $analyticsEnabled;
public function __construct()
{
// Results from the database
$results = $query->execute();
$this->siteId = $results['siteId'];
$this->siteName = $results['siteName'];
$this->stockIds = $results['stockIds'];
$this->analyticsEnabled = $results['analyticsEnabled'];
}
public function getSiteId()
{
return $this->siteId;
}
public function getSiteName()
{
return $this->siteName;
}
public function getStockIds()
{
return $this->stockIds;
}
public function isAnalyticsEnabled()
{
return $this->analyticsEnabled;
}
}
I have a contract "ArticleStorage" that every storage must be subscribe to be valid for model.
True, this is not the problem, my problem is: pagination ... or "results modification", in this case at fetchAll, i want modify its behavior but without adding parameters, etc
<?php
interface ArticleStorage
{
// public function insert();
// public function update();
// public function delete();
public function fetchAll();
}
class MySQLArticleStorage implements ArticleStorage
{
public function fetchAll()
{
// SELECT * FROM `articles`;
}
}
?>
How my model works.
class ArticlesModel
{
public function __construct(ArticleStorage $storage)
{
}
}
in this case, I expect a "ArticleStorage" but do not know which "Storage" was given, true ... and i want to paginate or apply a results modification, using the Storage.
class MySQLArticleResultsModifier
{
public function __construct(MySQLArticleStorage $storage)
{
}
public function fetchAll()
{
// ...
}
}
In case of a pagination, how i can modify ArticleStorage fetchAll and apply my modified query ?
Is there a case where your model demands that a fetchall on top of another fetchall is possible; I don't think so, infact this is how you decide if you need a decorator or not, by answering this question to yourself
Is the decorator function you are thinking of making works like a decoration{like a real decoration where you can put stars on your christmas tree {decoration1}, and some toys on your tree {decoration2} at the same instance? Otherwise there is no point in making a decorator pattern, The nature of decorator is to decorate the concrete implementations from outside world, and change the output, without being affected by the other decoration being applied to a concrete instance.
Now as to the current implementation, I think #mrhobo is quite right, your fetch function might look like
public function fetch($limit, $order,$sort)
A very smart fetch could also expect the user to send a hashtable of key-value , of the columnname = value of column by using which you can make your own select query on the fly.
i need differents results from a model but i don't understand if it is correct make a single call and leave to model all the work or make more calls and collect the result to pass to the view when tables aren't joined or when i need fetch one row from a table and differents rows from others.
First example (more calls, collect and send to view):
CONTROLLER
// call functions of model
$modelName = new Application_Model_DbTable_ModelName();
$rs1 = $modelName->getTest($var);
$rs2 = $modelName->getTest2($var2);
// collect data
$pippo = $rs1->pippo;
if ($rs2->pluto == 'test') {
$pluto = 'ok';
} else {
$pluto = 'ko';
}
// send to view
$this->view->pippo = $pippo;
$this->view->pluto = $pluto;
MODEL
public function getTest($var) {
...
select from db...
return $result;
...
}
public function getTest2($var) {
...
select from db...
return $result;
...
}
Second example (one call, model collect all data, return to controller and send to view):
CONTROLLER
// call one function of model
$modelName = new Application_Model_DbTable_ModelName();
$rs = $modelName->getTest($var);
MODEL
public function getTest($var) {
...
select from db...
if ($result > 0) {
call other function
call other function
collect data
return $result;
...
}
Thanks
There's no one correct answer to this question, but in general, you should endeavor to keep your business logic in one place. Think of it as, "thin controller, thick model." I.e., keep the controllers as small and simple as possible and put all the business logic in the models.
There seems to be a few questions here:
But if i don't need to interact with db and i need only a simply
function is better put that function in model? For example:
CONTROLLER:
public function printAction() {
$data = $this->getRequest()->getPost();
$label = "blablabla";
$this->view->label = $label;
}
first, in the context of Zend Framework this particular example doesn't make much sense. The whole point of the controller is to populate the view template. However, I do get the idea. I would point you to Action Helpers and View helpers as a means to address your concerns. You can always add a utility class to your library for those pieces of code that don't seem to fit anywhere else.
Action Helpers typically are employed to encapsulate controller code that may be repetitive or reusable. They can be as simple or as complex as required, here is a simple example:
class Controller_Action_Helper_Login extends Zend_Controller_Action_Helper_Abstract
{
/**
* #return \Application_Form_Login
*/
public function direct()
{
$form = new Application_Form_Login();
$form->setAction('/index/login');
return $form;
}
}
//add the helper path to the stack in the application.ini
resources.frontController.actionhelperpaths.Controller_Action_Helper = APPLICATION_PATH "/../library/Controller/Action/Helper"
//the helper is called in the controller
$this->_helper->login();
a View helper does the same thing for the view templates:
class Zend_View_Helper_PadId extends Zend_View_Helper_Abstract
{
/**
* add leading zeros to value
* #param type $id
* #return string
*/
public function padId($id)
{
return str_pad($id, 5, 0, STR_PAD_LEFT);
}
}
//in this example the helper path is added to the stack from the boostrap.php
protected function _initView()
{
//Initialize view
$view = new Zend_View();
//add custom view helper path
$view->addHelperPath('/../library/View/Helper');
//truncated for brevity
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer');
$viewRenderer->setView($view);
//Return it, so that it can be stored by the bootstrap
return $view;
}
//and to use the helper in the view template
//any.phtml
<?php echo $this->padId($this->id) ?>
i need differents results from a model but i don't understand if it is
correct make a single call and leave to model all the work or make
more calls and collect the result to pass to the view when tables
aren't joined or when i need fetch one row from a table and differents
rows from others.
This question is more about structure then about correctness.
You can interact with your database table models in Action and View helpers for simple/repetitive queries if you need to, however most developers might frown on this approach as being difficult to maintain or just ugly.
Many people seem to favor Doctrine or Propel to help them manage their database needs.
At this point I like to roll my own and currently favor domain models and data mappers, not an end all be all pattern, but seems to be appropriate to your question.
This is not a simple suggestion to implement for the first time, however i found two articles helpful to get started:
http://phpmaster.com/building-a-domain-model/
http://phpmaster.com/integrating-the-data-mappers/
and if you really want to get into it try:
http://survivethedeepend.com/
I hope this answers at least a part of your questions.
So basically I'm making a leap from procedural coding to OOP.
I'm trying to implement the principles of OOP but I have a nagging feeling I'm actually just writing procedural style with Objects.
So say I have a list of pipes/chairs/printers/whatever, they are all all listed as products in my single table database. I need to build a webapp that displays the whole list and items depending on their type, emphasis is on 'correct' use of OOP and its paradigm.
Is there anything wrong about just doing it like:
CLass Show
{
public function showALL(){
$prep = "SELECT * FROM myProducts";
$q = $this->db-> prepare($prep);
$q->execute();
while ($row = $q->fetch())
{
echo "bla bla bla some arranged display".$row['something']
}
}
and then simply
$sth = new show();
$sth->showAll();
I would also implement more specific display methods like:
showSpecificProduct($id)->($id would be passed trough $_GET when user say clicks on one of the links and we would have seperate product.php file that would basically just contain
include('show.class.php');
$sth = new show();
$sth->showSpecificProduct($id);
showSpecificProduct() would be doing both select query and outputing html for display.
So to cut it short, am I going about it allright or I'm just doing procedural coding with classes and objects. Also any ideas/hints etc. on resolving it if I'm doing it wrong?
As well as the model practices described by #Phil and #Drew, I would urge you to separate your business, data and view layers.
I've included a very simple version which will need to be expanded upon in your implementation, but the idea is to keep your Db selects separate from your output and almost "joining" the two together in the controller.
class ProductController
{
public $view;
public function __construct() {
$this->view = new View;
}
public function indexAction() {
$model = new DbProductRepository;
$products = $model->fetchAll();
$this->view->products = $products;
$this->view->render('index', 'product');
}
}
class View
{
protected $_variables = array();
public function __get($name) {
return isset($this->_variables['get']) ? $this->_variables['get'] : null;
}
public function __set($name, $value) {
$this->_variables[$name] = $value;
}
public function render($action, $controller) {
require_once '/path/to/views/' . $controller . '/' . $action . '.php';
}
}
// in /path/to/views/product/index.php
foreach ($this->products as $product) {
echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}
A better fit would be to implement a repository pattern. An example interface might be
interface ProductRepository
{
public function find($id);
public function fetchAll();
}
You would then create a concrete implementation of this interface
class DbProductRepository implements ProductRepsoitory
{
private $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function find($id)
{
// prepare execute SQL statement
// Fetch result
// return result
}
public function fetchAll()
{
// etc
}
}
It's generally a bad idea to echo directly from a method or function. Have your methods return the appropriate objects / arrays / whatever and consume those results.
The scenario you are describing above seems like a good candidate for MVC.
In your case, I would create a class strictly for accessing the data (doing selects of product categories or specific products) and then have a different file (your view) take the output and display it.
It could look something like this:
class Product_Model {
public function find($prodId) { ... }
public function fetchAll($category = '') { ... }
public function search($string) { ... }
}
Then somewhere else you can do:
$products = new Product_Model();
$list = $products->fetchAll(37); // get all from category 37
// in true MVC, you would have a view that you would assign the list to
// $view->list = $list;
foreach($ilst as $product) {
echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}
The basic principle of MVC is that you have model classes that are simply objects representing data from some data source (e.g. database). You might have a mapper that maps data from the database to and from your data objects. The controller would then fetch the data from your model classes, and send the information to the view, where the actual presentation is handled. Having view logic (html/javascript) in controllers is not desirable, and interacting directly with your data from the controller is the same.
first, you will want to look into class autoloading. This way you do not have to include each class you use, you just use it and the autoloader will find the right file to include for you.
http://php.net/manual/en/language.oop5.autoload.php
each class should have a single responsibility. you wouldn't have a single class that connects to the database, and changes some user data. instead you would have a database class that you would pass into the user class, and the user class would use the database class to access the database. each function should also have a single responsibility. you should never have an urge to put an "and" in a function name.
You wouldn't want one object to be aware of the properties of another object. this would cause making changes in one class to force you to make changes in another and it eventually gets difficult to make changes. properties should be for internal use by the object.
before you start writing a class, you should first think about how you would want to be able to use it (see test driven development). How would you want the code to look while using it?
$user = new User($db_object);
$user->load($id);
$user->setName($new_name);
$user->save();
Now that you know how you want to be able to use it, it's much easier to code it the right way.
research agile principles when you get a chance.
One rule of thumb is that class names should usually be nouns, because OOP is about having software objects that correspond to real conceptual objects. Class member functions are usually the verbs, that is, the actions you can do with an object.
In your example, show is a strange class name. A more typical way to do it would be to have a class called something like ProductViewer with a member function called show() or list(). Also, you could use subclasses as a way to get specialized capabilities such as custom views for particular product types.