What is a minimal, complete example of pagination in Kohana 3.2? - php

I found much information about pagination in Kohana 3.2 but most of it is scattered across forum comments and blog posts with no single complete source to refer to.
(note: I intended to self answer this question)

This is what worked for me:
Download the pagination module from https://github.com/kloopko/kohana-pagination (pagination was removed from Kohana 3.2, so this is an adapted module).
Install the module in modules/pagination.
Add the module in bootstrap.php:
Kohana::modules(array(
// ... other modules ...
'pagination' => MODPATH.'pagination'
));
Copy the configuration file from modules/pagination/config/pagination.php to application/config/pagination.php.
Add the following actions to your controller:
public function action_index() {
// Go to first page by default
$this->request->redirect('yourcontroller/page/?page=1');
}
public function action_page() {
$orm = orm::factory('your_orm');
$pagination = Pagination::factory(array(
'total_items' => $orm->count_all(),
'items_per_page' => 20,
)
);
// Pass controller and action names explicitly to $pagination object
$pagination->route_params(array('controller' => $this->request->controller(), 'action' => $this->request->action()));
// Get data
$data = $orm->offset($pagination->offset)->limit($pagination->items_per_page)->find_all()->as_array();
// Pass data and validation object to view
echo View::factory('yourview/page', array('data' => $data, 'pagination' => $pagination));
}
Create yourview/page as follows:
<?php
foreach($data as $item) {
// ...put code to list items here
}
// Show links
echo $pagination;
Modify application/config/pagination.php according to your needs. I had to change the 'view' parameter to 'pagination/floating' which displays ellipses (...) when the list of pages is too large, unlike the default 'pagination/basic' which lists all pages regardless of length.

Pagination wasn't originally working/supported in Kohana 3.2. Luckily, somebody has updated the module and you can get the code at https://github.com/kloopko/kohana-pagination

Related

How to call Custom Module in Drupal

I am new to Drupal, I have made a custom module using PHP, which shows List of Student's with Information, and want to call it, on click of Submenu item, named, student Info. Please guide me by step wise step procedure.
The starting place to look for generating a "page callback" (essentially making a url active in drupal) would be hook_menu. As suggested take a look at the documentation but a starting point to actually make your callback work would be this in a my_module.module file:
/**
* Implements hook_menu().
*/
function my_module__menu() {
$items = array();
$items['student-info'] = array(
'title' => 'Student Info', // This becomes the page title
'description' => 'Information about students.', // this is the link description
'page callback' => 'function_name_that_outputs_content', // this is the page callback function that will fire
'type' => MENU_CALLBACK, // this is the type of menu callback, there are several that you can use depending on what your needs are.
);
return $items; // make sure you actually return the items.
}
/**
* Output the page contents when someone visits http://example.com/student-info.
*/
function function_name_that_outputs_content() {
$output = 'My page content'
return $output;
}

Access Paginator object in controller

I am using cakePHP 2.5 and I want to access $this->Paginator->hasNext() in controller, but it through exception.
$type = array('featured', 'newest', 'trending');
foreach($type as $each)
{
$conditions = array('Product.status'=>'1', "is_$each" => '1');
$this->Product->recursive = 1;
//retrieve and set final result set
$this->paginate = array(
'fields' => array('Product.*'),
'conditions' => $conditions,
'limit' => $page_limit,
'page' => $page,
'order' => "$order_by $order_by_sort",
);
$products[$each] = $this->paginate('Product');
}
On my page, I want to display 3 type of product featured/trending/newest. Initially I load first page by default, then when user scroll down then I will call ajax and append next page like wise. But if last page is reached then I want to stop ajax call (because unknown page through 404 not found error).
To overcome that, I prevent AJAX call for unknown pages. And also make sure that first page isn't last!!
Hope my details make sense!
I could not find any answer on any forum/document. Please guide me or point me if it's duplicate of any.
You don't need to (and cannot*) access a helper in the controller.
Take a look at the source code for hasNext which is just calling the helper function _hasPage, which is simply checking the parameters array.
The paginator parameters are all available in the controller:
$paging = array(
'page' => $page,
'current' => count($results),
'count' => $count,
'prevPage' => ($page > 1),
'nextPage' => ($count > ($page * $limit)),
'pageCount' => $pageCount,
'order' => $order,
'limit' => $limit,
'options' => Hash::diff($options, $defaults),
'paramType' => $options['paramType']
);
So from the code in the question:
$this->request['paging']['Product']['nextPage']
Is the information you're looking for (it will be overwritten each time you call paginate.
Consider your application design.
Unless you have exactly the same number of featured, newest and trending records - it'd be better to have one ajax request for each type. Also see this related question, for more information on implementing infinite-scroll type pages.
* Almost anything is possible, you certainly should not need to use a helper in a controller though.
MVC Violation
$this->Paginator->hasNext()
That's a method of the helper. Helpers are not thought to be used in controllers because this is a violation of the MVC pattern and bad practice. If you think you have to you're wrong: Fix your architecture, it's broken by design.
Proper solution
Return the status of the pagination along with the data in the AJAX response:
$this->set('pagination', $this->request->paging['Product']);
$this->set('products', $result);
$this->set('_serialize', ['products', 'pagination']);
You can change the state of your view depending on the data then:
if (pagination.Product.nextPage == true) { /*... */ }

how to run yii widget when button clicked

I have this widget:
<?php
class Search extends CWidget
{
public $dataProvider = null;
public function init()
{
$criteria = new CDbCriteria();
if ( isset($_GET['file']) ) {
$criteria->compare('fileName', $_GET['file'], true, 'OR');
$criteria->compare('tags', $_GET['file'], true, 'OR');
}
$this->dataProvider = new CActiveDataProvider("Files", array(
'criteria' => $criteria,
//'countCriteria' => $criteria,
'pagination'=>array(
// results per page
'pageSize'=>1,
),
));
}
public function run(){
$this->render('site/result', array(
'dataProvider' => $this->dataProvider,
'pages' => $this->dataProvider->pagination,
));
}
}
?>
how I can run this widget only when the search button is clicked, and how to view its result in the view reuslt that is located in the folder site
Maybe I misunderstood you, but I think you have a little confusion about widget. Avoid making a
lengthy answer, I made a model in below
Question 1: How I can run this widget only when the search button is clicked?
The idea is that you put the widget content into hidden div, and then add a jQuery script to show it after the search button is clicked
<div id='search-result' style="display:none"><?php $this->widget(...) ?></div>
<script>
$('#search-button-id').click({
// do something
$('#search-result').show();
})</script>
Question 2: how to view its result in the view reuslt that is located in the folder site?
Imao, I recommend you don't do this. The widget is independant part, you can use it for many specific purposes & many locations of your project, so just put a simple view for widget to render in its own, instead of trying to render a view outside widget's scope. It should look like below
/your-app/protected/extensions/widgets/search/Search.php
/your-app/protected/extensions/widgets/search/views/result.php // view for rendering

Difference in rendering when visiting node/1 and programmatically loading it

A node loads a profile of a user (external database + views). All of this works when I visit: node/123/profile/id/3. Now I have implemented hook_menu() in order to load any profile page and have nicer URLs.
When I load it myself for some reason $left in page.tpl.php is suddenly empty and many more variables seem not to be loading. I have tried many different functions to render and create the correct $output but realized that node_show() seems to be the function of choice.
Testing has shown now that for some reason hook_nodeapi() calls are ignored.
My code:
/**
* Implementation of hook_menu
*/
function modulename_menu() {
$items = array();
$items['my/nice/url/profile'] = array(
'description' => 'This page holds a view that shows profiles based on the %',
'page callback' => 'website_profile_load',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Menu path wildcard callback
*/
function website_profile_load() {
$output = node_show(node_load(1221), false, true);
return $output;
}
So what is the correct way to do this and get Panels (see comment below) to load correctly?
UPDATE:
I am using table wizard and Views 2 to connect to another database with information about people that aren't users of the system. This is an alumni page, the page is administered externally and showed internally (nothing I can do about, have to make this work :)
Just discovered that Panels aren't loaded at all. So even if the node I am trying to load is uses panels for some reason none of that is loaded.
/**
* Menu path wildcard callback
*/
function website_profile_load($uid = null) {
if (!$uid) {
global $user; // if no user passed in argument, show current user profile
$uid = $user->uid;
}
$output = drupal_render(content_profile_show_profiles($uid));
}
There are many reasons why rendering the result of a node_load is different from going to the stock Drupal path /node. It is way too much to go over here honestly but the short answer is that you have to define a template/theme and blocks etc for each page you create. Just because you make a new path and do a node_load in the callback for that path doesn't mean Drupal can automagically know how you want to display that content. It simply loads data from the node and it is available to do whatever you please with it after that. This is why you get a blankish looking page instead of what you'd expect from going through /node.
However I will offer this simple solution since it sounds like you want the exact same page you'd get when you go to 'node/123/profile/id/3' but accessible through a link you define yourself. You just need to setup a redirect in your hook_menu like so:
$items['my/nice/url/profile'] = array(
'description' => 'This page holds a view that shows profiles based on the %',
'page callback' => 'drupal_goto',
'page arguments' => 'node/123/profile/id/3',
'access callback' => TRUE,
'type' => MENU_CALLBACK);
This is essentially saying that when you navigate to 'my/nicer/url/profile' it runs: drupal_goto('node/123/profile/id/3');
I found the answer to be that apparently somewhere in the pipeline of creating a node Drupal uses $path (that is originally set by $_GET['q']) and sometimes also $_GET['q'] to determine how to render the page. NOTE that I am using Panels and Ctools Page Manager modules in order to get my things working correctly.
It turns out Panels, if you search the code, looks at $_GET['q'] for quite an amount of things.
Here is what I ended up with:
/**
* Implementation of hook_menu
*/
function modulename_menu() {
$items = array();
// For department and having nice URL's for their profile pages.
$items['my/nice/url/profile/%'] = array(
'description' => 'This page holds a view that shows profiles based on the %',
'page callback' => 'website_profile_load',
'page arguments' => arg(4),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Menu path callback
*/
function website_profile_load($id = NULL) {
// Rename the query internally since other functions base the design
// on the way the query is structured and not simply by the node which
// is currently loading.
if(!empty($id)) {
$path = $_GET['q'] = 'node/1221/profile/id/' . $id;
}
// Use ctools function to correctly display node view since
// this site heavily uses ctools rendering for panels and
// web parts / web pages.
drupal_load('module', 'page_manager');
ctools_include('node_view', 'page_manager', 'plugins/tasks');
if(function_exists('page_manager_node_view')) {
$output = page_manager_node_view(node_load(1221));
} else {
// Will display incorrectly but still load the UI
$output = node_page_view(node_load(1221));
}
return $output;
}
And it works :)

Passing url parameters to Zend_Navigation using an XML-file

I am using Zend Framework 1.10.8.
I want to create a breadcrumb section in my layout.phtml. There are some links in my menu that have dynamic url parameters like http://mydomain.com/editor/edit/id/42
I try to figure out how to pass id=XXX to Zend_Navigation, while XXX comes from the database and is different in every request.
One solution I found so far is adding a property e.g. params_id to my xml declaration:
in configs/navigation.xml
<pages>
<editor>
<label>Editor</label>
<controller>editor</controller>
<action>edit</action>
<params_id>id</params_id>
<route>default</route>
</editor>
</pages>
and in the controller looping through the pages and dynamically adding my parameter id = 42 (while 42 would be retrieved from the request object in the final version)
$pages = $this->view->navigation()->getContainer()->findAllBy('params_id','id');
foreach ($pages as &$page) {
$page->setParams(array(
'id' => 42,
'something_else' => 667
));
}
As adding dynamic url parameters seems such a basic requirement for Zend_Navigation I am quite sure that my solution is too complicate, too expensive and there must be a much simplier solution "out of the box".
It is very simple. Just write in your XML
<pages>
<editor>
<label>Editor</label>
<controller>editor</controller>
<action>edit</action>
<params>
<id>42</id>
<someting_else>667</something_else>
</params>
<route>default</route>
</editor>
</pages>
Here is example to do it dynamically based on database data
First define Navigation loading plugin. Name the file Navigation.php and place it in application/plugins/ directory. Here's an example of such plugin:
class Plugin_Navigation extends Zend_Controller_Plugin_Abstract
{
function preDispatch(Zend_Controller_Request_Abstract $request)
{
$view = Zend_Controller_Action_HelperBroker::getExistingHelper('ViewRenderer')->view;
//load initial navigation from XML
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml','nav');
$container = new Zend_Navigation($config);
//get root page
$rootPage = $container->findOneBy('sth', 'value');
//get database data
$data = Model_Sth::getData();
foreach ($data as $row) {
$rootPage->addPage(new Zend_Navigation_Page_Mvc(array(
'module' => 'default',
'controller' => 'examplecontroller',
'action' => 'exampleaction',
'route' => 'exampleroute',
'label' => $row['some_field'],
'params' => array(
'param1' => $row['param1'],
'param2' => $row['param1']
)
)));
}
//pass container to view
$view->navigation($container);
}
}
Then in you Bootstrap init this plugin
protected function _initNavigation() {
Zend_Controller_Front::getInstance()->registerPlugin(new Plugin_Navigation());
}
An update: I finally ended up throwing away the xml file. What I do now:
I wrote a plugin (see Daimon's approach)
in this plugin I configure my navigation structure as an array, the
dynamic parameters are retrieved from Zend_Request
then I init the navigation using this array

Categories