I'm new to OOP. I created this class called Site that is extended but many other classes with common queries and excutions.
This particular class "Pagination" , I need its methods to be accessed from other instances and access to data sent to it "internally". It's probably bad written but I'd like some help.
<?php
class Site {
public $lang;
public $user_agent;
public $user_lang;
public $url;
public $bots;
public $total_items;
public $itemsPerPage;
public $page;
class Products extends Site {
function getProducts($last = false, $id = false, $cat = false, $active_only = false, $lang_pref = false, $itemsPerPage = false, $page =false){
//code
//prepare paging
if(!empty($itemsPerPage)){
//count total product
$count = mysql_query(
"SELECT COUNT(*)
FROM products_list
".#$cat_to_choose."
".#$lang."
")
or die(mysql_error());
$count = mysql_fetch_row($count);
$total_items = $count[0];
// set vars for Pagination class
$this->total_items = $total_items;
$this->itemsPerPage = $itemsPerPage;
$this->page = mysql_real_escape_string($page);
//send data to class Pagination
$pagination = new Pagination();
$start = $pagination->createPagination();
$limit = "LIMIT ".$start.", ".$itemsPerPage;
}
//code
}
//other classes
class Pagination extends Site {
function createPagination(){
// get total pages by dividing
$this->total_pages = $this->total_items/$this->itemsPerPage;
//round to highest integer
$this->total_pages= ceil($this->total_pages);
switch($this->page){
case "0":
case null:
case "1":
$start = 0;
break;
default :
$start = ($this->page-1)*($this->itemsPerPage);
break;
}
return $start;
}
public function htmlPagination(){
if($this->page == 0){
$this->page = 1;
}
$pagination = array(
"total_pages" => $this->total_pages,
"current_page" => $this->page,
"total_items" => $this->total_items
);
return $pagination;
}
}
}
PHP CODE
$products_object= new Products();
$products = $products_object->getProducts(false,false,$cat, true, $site->lang, $itemsperpage, #$_GET["pag"]);
Once I did this, how do I access htmlPagination with the data processed in the Products instance?
You could set the pagination as a field of the products object and retrieve it with a get method or by defining it as public and reading it directly.
In products:
class Products
{
...
private $pagination;
public function getProducts(...)
{
...
$this->pagination = new Pagination();
...
}
public function getPagination()
{
return $this->pagination;
}
}
Then later:
$product->getPagination()->htmlPagination();
to retrieve the html pagination.
Related
I want to set a PHP variable within my SQL SELECT statement that can then be used on another page. Here is my code:
<?php
class Page extends DbConnect
{
public function getPage()
{
$sql = "SELECT * FROM pages WHERE page_name = 'Contact'";
$result = $this->connect()->query($sql);
while($row = $result->fetch())
{
echo $row['page_name'];
}
}
}
?>
You can pass a variable on a class's construct and assign it to a private or public variable
<?php
class Page extends DbConnect
{
private $page;
public function __construct($toView){
$this->page = $toView;
}
public function getPage()
{
$pageToView = $this->page;
$sql = "SELECT * FROM pages WHERE page_name = '$pageToView'";
...
}
}
<?php
// on contact page
$page = new Page('contact');
$page->getPage();
<?php
// on about page
$page = new Page('about');
$page->getPage();
You can also pass a parameter directly on a class's function
<?php
class Page extends DbConnect
{
public function getPage($pageToView)
{
$sql = "SELECT * FROM pages WHERE page_name = '$pageToView'";
...
}
}
<?php
// on contact page
$page = new Page();
$page->getPage('contact');
<?php
// on about page
$page = new Page();
$page->getPage('about');
I am trying to figure out how how to create my own simple cursor based pagination system in PHP and am having difficulty trying to understand how star starting_after and starting_before works as mentioned in this medium.com post for how the company stripe deals with cursor pagination. In my case I am using the id column that is in ascending order to hopefully make this work. The issue that I am having is getting an id for the first "page". Currently my first page would direct to the second page since starting_after leads to the next page and not the currently page. Any advice for how to build this out would be awesome. I already created page based pagination, but think that cursor pagination would be more useful for most of my cases.
I have attached the two files that I have created thus far to try to get this to work.
Pagination class
<?php
require_once "DB.php";
class New_Pagination {
private $table = "";
private $limit;
private $starting_after = "";
private $starting_before = "";
private $db;
public function __construct() {
$this->db = DB::getInstance();
}
public function getLimit(): int {
return $this->limit;
}
public function setLimit(int $limit): void {
$this->limit = $limit;
}
public function getStartingAfter(): string {
return $this->starting_after;
}
public function setStartingAfter(string $starting_after): void {
$this->starting_after = $starting_after;
}
public function getStartingBefore(): string {
return $this->starting_before;
}
public function setStartingBefore(string $starting_before): void {
$this->starting_before = $starting_before;
}
public function getTable(): string {
return $this->table;
}
public function setTable(string $table): void {
$this->table = $table;
}
public function idExists($id) {
$result = $this->db->find(self::getTable(), [
"select" => "id",
"conditions" => "id = $id",
"fetchType" => "single"
]);
if (empty($result)) {
return FALSE;
} else {
return $result->id;
}
}
public function getData($starting_after, $starting_before) {
self::setStartingAfter($starting_after);
self::setStartingBefore($starting_before);
$starting_after = self::getStartingAfter();
$starting_before = self::getStartingBefore();
$data = [];
$order = !empty($starting_after) ? "ASC" : "DESC";
if (empty($starting_after) && empty($starting_before)) {
$data["data"] = $this->db->find(self::getTable(), [
"select" => "*",
"order" => "id ASC",
"limit" => self::getLimit(),
"fetchType" => "all"
]);
} else {
$data["data"] = $this->db->find("carousel_image", [
"select" => "*",
"conditions" => "id >= '$starting_after' OR id <= '$starting_before'",
"order" => "id $order",
"limit" => self::getLimit(),
"fetchType" => "all"
]);
}
$next = self::idExists($data["data"][count($data["data"]) - 1]->id + 1);
$previous = self::idExists($data["data"][0]->id - 1);
$data["cursor"] = [
"next" => $next,
"previous" => $previous
];
return $data;
}
public function generateLink() {
$test = self::getData("", "");
$test2 = [];
$test2[0] = $test;
$i = 0;
do {
$test2[$i] = $test;
$test = self::getData($test["cursor"]["next"], "");
$i++;
$test2[$i] = $test;
} while ($test["cursor"]["next"] !== FALSE);
$test2[$i] = $test;
echo "<ul>";
$j = 1;
foreach ($test2 as $key => $val) {
if ($val["cursor"]["next"] !== FALSE) {
$url = "/process.php?starting_after=" . $val["cursor"]["next"];
echo "<li>";
echo "<a href='$url'>$j</a>";
echo "</li>";
$j++;
}
}
echo "<ul>";
}
}
Test file
$pagination = new New_Pagination();
$pagination->setLimit(2);
$pagination->setTable("carousel_image");
echo "<pre>";
$pagination->generateLink();
echo "</pre>";
The cursors are useful to prevent scan big tables and allow to move in very big sources (files, external resources, etc., etc.). In the majority of the cases, cursors are provided by binary libraries and supported by the core of the related system (mysql, files). If you try to emulate this behavior in not natural way you must take care because you could add overhead and get unexpected results.
In the other hand, is very useful to have a pagination class, but be aware, this class have some problems.
getData is very expensive because it performs 3 queries to get a batch of results
the class is too verbose, the getters and setters add too much noise
the results are sorted using very rare criteria. Remember, if you are in search results you need the same order moving to the next page and moving to the previous page
My suggestions...
Create interfaces
<?php
interface CursorAble {
public function fetchNext ($startingAfter);
public function fetchPrev ($startingBefore);
public function getPreviousLink ();
public function getNextLink ();
}
interface Pageable {
public function getCollectionSize ();
public function getPageSize ();
public function getPagesCount ();
public function getPageLinks ();
}
When you create interfaces you ensures that the classes expose the desired behavior and furthermore delegate the specialized details to the concrete implementations. The concrete implementations can define it dependencies in the constructor, something very good when you relies on dependency injection.
CursorAble implementation example
<?php
class PdoCursorAbleTable implements CursorAble {
private $pdo;
private $table;
private $results;
private $pageSize;
public function __construct (PDO $pdo, $table, $pageSize = 100) {
$this->pdo = $pdo;
$this->table = $table;
$this->pageSize = (int)$pageSize ?: 100;
}
public function fetchNext ($startingAfter) {
$s = $this->pdo->prepare("select * from {$this->table} where id > :starting_after limit {$this->pageSize}");
$s->bindValue(':starting_after', $startingAfter, PDO::PARAM_INT);
$s->execute();
$this->results = $s->fetchAll() ?: [];
return $this->results;
}
public function fetchPrev ($startingBefore) {
$s = $this->pdo->prepare("select * from {$this->table} where id < :starting_before limit {$this->pageSize}");
$s->bindValue(':starting_before', $startingBefore, PDO::PARAM_INT);
$s->execute();
$this->results = $s->fetchAll() ?: [];
return $this->results;
}
public function getPreviousLink () {
return !$this->results ? '' : '?starting_before=' . $this->results[0]->id;
}
public function getNextLink () {
if (!$this->results || count($this->results) < $this->pageSize) return '';
return '?starting_after=' . $this->results[count($this->results)]->id;
}
}
And the Pageable example
<?php
class PdoPageableTable implements Pageable {
private $pdo;
private $table;
private $pageSize;
private $collectionSize;
public function __construct (PDO $pdo, $table, $pageSize = 100) {
$this->pdo = $pdo;
$this->table = $table;
$this->pageSize = $pageSize;
}
public function getCollectionSize () {
if ($this->collectionSize === null) {
$s = $this->pdo->prepare("select count(id) from {$this->table}");
$s->execute();
$this->collectionSize = $s->fetchColumn('0');
}
return $this->collectionSize;
}
public function getPageSize () {
return $this->pageSize;
}
public function getPagesCount () {
return ceil($this->collectionSize / $this->getPageSize());
}
public function getPageLinks () {
$pages = [];
foreach (range(1, $this->getPagesCount()) as $page) {
$pages[] = '?page=' . $page;
}
return $pages;
}
}
The test file
<?php
$pagination = new PdoCursorAbleTable($pdo, 'carousel_image', 2);
echo "<pre>";
$startingAfter = 0;
$results = $pagination->fetchNext($startingAfter);
foreach ($results as $result) {
// do something
}
echo $pagination->getNextLink();
echo "</pre>";
I am sending a ajax request in function and calling model function but model function not calling and i also try a local controller function but not call any local function
controller
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.controller');
class IgalleryController extends JControllerLegacy
{
function __construct($config = array())
{
$config['base_path'] = JPATH_SITE.'/components/com_igallery';
parent::__construct($config);
}
function ajaxrequest()
{
//JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_igallery/models', 'category');
//echo $db = JFactory::getDBO();
$model = $this->getModel('category');
$this->params = JComponentHelper::getParams('com_igallery');
$this->source = JRequest::getCmd('igsource', 'component');
//
$igid = JFactory::getApplication()->input->get('igid');
$Itemid = JFactory::getApplication()->input->get('Itemid');
$this->catid = JRequest::getInt('igid', 0);
$this->category = $model->getCategory($this->catid);
$profileId = JRequest::getInt('igpid', 0);
$profileId = $profileId == 0 ? $this->category->profile : $profileId;
$user = JFactory::getUser();
//print_r($user); die;
$this->profile = $model->getProfile($profileId);
$searchChildren = JRequest::getInt('igchild', 0);
$tags = JRequest::getVar('igtags', '');
//
$limit = JRequest::getInt('iglimit', 0);
$limit = $limit == 0 ? 1000 : $limit;
$foo = $this->foo();
print_r($foo);
$this->photoList = $model->getCategoryImagesList($this->profile, $this->catid, $tags, $searchChildren, $limit);
//
print_r($this->photoList);
}
function $this->foo()
{
return true;
}
...
in above code also print $foo variable but not get true or 1 value;
You must override function getModel() in your controller
parent model has construct:
public function getModel($name = '', $prefix = '', $config = array('ignore_request' => true))
You lacked $prefix and you also add include path of the model file if necessary
Regarding issue return value true of false, you must echo 1 for true of 0 for false and stop the process by die function. The return method will show so much html of joomla page.
function $this->foo()
{
echo 1;
die;
}
I don't know if the title is really correct for what I'm asking, but here it goes. I'm trying to build a very basic pagination class, just for retrieving a range of items.
This is my class so far
<?php
Class Pagination {
private $_dbh;
private $_currentPage;
private $_totalPages;
private $_startLimit;
private $_totalItems;
private $_table = 'products';
private $_perPage = 8;
private $_allowedTables = ['products', 'cart', 'orders'];
public $_results = [];
public function __construct($dbh = null) {
$this->_dbh = ($dbh !== null) ? $dbh : null;
}
public function getResults() {
$this->_results = $this->_dbh->query(" SELECT * FROM $this->_table ORDER BY id DESC LIMIT $this->_startLimit, $this->_perPage ")->fetchAll();
}
public function setCurrentPage($currentPage = null) {
$this->_currentPage = ($currentPage !== null && is_int($currentPage)) ? $currentPage : 1;
}
public function setPerPage($perPage = null) {
$this->_perPage = ($perPage !== null && is_int($perPage)) ? $perPage : $this->_perPage;
}
public function setTable($table = null) {
$this->_table = ($table !== null && in_array($table, $this->_allowedTables)) ? $table : $this->_table;
}
private function totalItems() {
$this->_totalItems = $this->_dbh->query(" SELECT COUNT(id) AS total FROM $this->_table")->fetch()->total;
}
private function totalPages() {
$this->_totalPages = ceil($this->_totalItems / $this->_perPage);
}
private function startLimit() {
$this->_startLimit = ( $this->_currentPage - 1 ) * $this->_perPage;
}
public function getInfo() {
return array(
'table' => $this->_table,
'perPage' => $this->_perPage,
'currentPage' => $this->_currentPage,
'totalItems' => $this->_totalItems,
'totalPages' => $this->_totalPages,
'startLimit' => $this->_startLimit,
'query' => " SELECT * FROM $this->_table ORDER BY id DESC LIMIT $this->_startLimit, $this->_perPage "
);
}
}
?>
It is incomplete, but this is how I would like to call it
$pagination = new Pagination($dbh); // $dbh = PDO connection
$pagination->setCurrentPage(2);
$pagination->setTable('products'); // optional
$pagination->setPerPage(12); // optional
$products = $pagination->_results();
The problem is that all the variables that I define at the top of my class ( $_currentPage, $_totalPages, $_startLimit and $_totalItems ) are empty.
Even when I set them, they are still empty(as I expect) so I cannot calculate the $_totalPages, $_startLimit, $_totalItems or call the method getResults() which will query the DB for the items.
The first approach was to do everything in the __construct method and it worked, but I feel like it's not good to perform too many actions inside one method.
So my question is how can I modify my class so I can use it as I showed even without calling the setter methods ?
Plus, all the methods that calculate the number of pages, total items, etc.., would have to be called automatically from inside the class so they actually set the variables values, the way it is now they are only available but aren't run anywhere.
Thank you.
I want to write a php simple pagination class. Here is my code:
<?php
class Pagination {
public $rowsPerPage;
public $currentPage;
public $totalPages;
public $totalRows;
public $firstElement;
public $lastElement;
public function paginate()
{
if(isset($_GET['page'])){
$this->currentPage = $_GET['page'];
}
$this->totalPages = $this->totalRows/$this->rowsPerPage ;
return $this->totalPages;
$this->firstElement = $this->currentPage-1)*$this->rowsPerPage+1;
return $this->firstElement;
}
}
$totalRecords = 55;
$paginator = new Pagination();
$paginator->totalRows = $totalRecords;
$paginator->rowsPerPage = 5;
$paginator->paginate();
echo $paginator->totalPages;
echo $paginator->firstElement;
?>
I can echo $paginator->totalPages; but not $paginator->firstElement.
What I do wrong ?
Thanks
Your paginate function has two return statements.
When the code hits the return $this->totalPages;, it will stop running the function. Therefore, the $this->firstElement = ... line is never ran.