[英]CakePHP 2.2.4: Pagination Links
我的网站上有很多“页面”。 页面是针对不同主题创建的,并由用户主持(例如,加勒比海盗页面或贾斯汀·比伯页面)。 该页面属于一个类别,例如,电影或音乐。 页面的默认URL是http://www.example.com/category-directory/page-id 。 (可选)如果主持人希望为页面建立自己的链接以作为更轻松的导航方式,则可以通过在“ Page.link”列中赋值来实现(例如: http : //www.example.com/ potc为电影加勒比海盗 )。
我已经设置了所有路线,这本身花费了一些时间。 路由检查以查看URL的“ .com”后面的第一个参数是否与任何页面的“ link”列匹配(如果匹配),路由到该页面及其下的控制器/动作。 如果没有,请照常进行路由。
当用户浏览http://www.example.com/potc/articles/99或http://www.example.com/movies/106/articles/99时 (假设“加勒比海盗”的 ID为= 106),然后将用户定向到商品控制器,查看操作,id =99。106作为$ page_id传递到控制器的操作,并在AppController中进行设置。
我在控制器中提供的URL数组可以很好地工作,例如,如果id不存在,我将重定向到'controller' => 'articles', 'action' => 'index', 'page_id' = $page_id
。 我被重定向回http://www.example.com/potc/articles 。 实际上,我不必定义控制器,因为默认情况下它使用当前控制器。
但是,我对分页链接有疑问。 举例来说,我在文章索引页面上,有100篇文章,但是我只查看前20篇文章。我希望将URL输出为http://www.example.com/potc/articles/page :2 。
相反,如果我将URL数组设置为'controller' => 'articles', 'action' => 'index', 'page_id' => $page_id
类似于在控制器中所做的操作, 'controller' => 'articles', 'action' => 'index', 'page_id' => $page_id
获得链接http:// www.example.com/articles/page_id:106/page:2我可以理解为什么此路由不起作用,因为如果存在值Page.link,则可能必须传递它,如果不存在Category.directory和Page,则必须传递它。 ID。 我尝试使用URL数组'controller' => 'articles', 'action' => 'index', 'category' => $page['Category']['directory'], 'page_id' => $page_id
。 我有一条与此匹配的路线,但分页链接仍然生成为http://www.example.com/articles/category:movies/page_id:106/page:2
这是我的routes.php中的一些片段: https ://gist.github.com/9ba0a54a7f4d68803d14
我的问题是:“ 我可以使用确切的当前URL用于分页链接(减去对我当前页面的引用)吗? ”例如,如果我正在查看http://www.example.com/dynamic-route/controller / id / page:2 ,分页链接将自动转到http://www.example.com/dynamic-route/controller/id/page:3
我将所有的分页代码都放在一个元素中,并且无论何时需要分页,我都希望将该元素包括在我的视图文件中。
现在,如果我正在查看articles控制器的index操作,则分页链接的默认URL为http://www.example.com/articles/page:2 ,但我需要将其设置为http:// www .example.com / dynamic-route / articles / page:2
我尝试使用
$this->Paginator->options = array(
'url' => 'http://www.example.com/dynamic-route/articles'
);
但是链接的输出类似于http://www.example.com/articles/http://www.example.com/dynamic-route/articles/page:2
编辑:犹太人,你提到把
'customlink'=>'[a-z0-9] {1}([a-z0-9-] {2,} [a-z0-9] {1})?
在我的路线上。 好吧,我不能简单地这样做,因为路由会执行查询以检查customlink是否在数据库中,如果是,则会进行相应的路由。
我的路由器文件的一个示例是:
在获得网址的第一个参数http://www.domain.com/ CUSTOM-LINK之后 ,请执行以下操作:
if($param1 != "users" && $param1){
$pagelink = str_replace('-', ' ', $param1);
$pagesModel = ClassRegistry::init('Page');
$matchedpage = $pagesModel->find('first', array(
'conditions' => array('Page.link LIKE' => "$pagelink"), 'recursive' => '-1'
));
if($matchedpage['Page']['id']){
Router::connect('/' . $param1 . '/:controller', array('action' => 'index', 'page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id'),
'page_id' => '[0-9]+',
'persist' => array('page_id'),
));
Router::connect('/' . $param1 . '/:controller/:action/:id', array('page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id', 'id'),
'page_id' => '[0-9]+',
'persist' => array('page_id'),
));
Router::connect('/' . $param1 . '/:controller/:id', array('action' => 'view', 'page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id', 'id'),
'page_id' => '[0-9]+',
'id' => '[0-9]+',
'persist' => array('page_id'),
));
Router::connect('/' . $param1 . '/:controller/:action', array('page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id'),
'page_id' => '[0-9]+',
'persist' => array('page_id'),
));
} // end if page matches
} // end if param1 is not users
如果我去http://www.domain.com/custom-link/articles , http://www.domain.com/custom-link/articles/1 , http://www.domain.com/custom- link / articles / edit / 1等,将显示正确的页面。 如果我尝试导航到不存在自定义链接的页面,请继续浏览我的路由器文件,如果没有其他路由匹配,则抛出错误消息。 那里一切都很好。
在我的ArticlesController.php中,重定向方法按预期工作。 举例来说,我尝试访问http://www.domain.com/custom-link/articles/99,但id 99不存在,我已正确重定向回http://www.domain.com/custom -链接/文章使用
$ this-> redirect(array('action'=>'index','page_id'=> $ page_id),null,true);
但是,在分页时,我将url选项设置为
array('controller'=>'articles','action'=>'index','page_id'=> $ page_id);
其中$ page_id是在AppController中设置为由路由器传递的。 虽然我不需要设置控制器和动作,因为将使用当前的动作。 同样,我的分页链接显示为http://www.domain.com/articles/page_id:3/page:2,而不是我想要的http://www.domain.com/custom-link/articles/page :2
编辑:耶斯达
我只是将整个路由文件更改为具有自定义链接参数(我重命名为“链接”)后所拥有的文件,然后创建了一个组件,供应用控制器使用,以从链接获取页面ID。
路线示例
Router::connect('/:link/:controller/:action/:id', array(), array(
'pass' => array('link', 'id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
));
Router::connect('/:link/:controller/:id', array('action' => 'view'), array(
'pass' => array('link', 'id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'id' => '[0-9]+',
'persist' => array('link'),
));
但是,使用url数组作为array('link' => 'test-example')
进行分页时,URL输出为http://www.domain.com/articles/link:test-example/page:2
。 我的代码与您的代码完全相同,减去了将“ custom-link”重命名为“ link”。 另外,现在我的路线无法区分我是否要访问http://www.domain.com/custom-link ,这将是“ controller” =>“ pages”,“ action” =>“ view” (他的页面基本上将使用“新闻”模型,并显示该页面的最新新闻),如果我尝试访问http://www.domain.com/articles ,则该页面将为“ controller” =>“ articles”,“操作” =>“索引”,它将显示所有页面的最新文章。 注意,文章和新闻是单独的模型。
Router::connect('/:link', array('controller' => 'pages', 'action' => 'view'), array(
'pass' => array('link'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
));
是相同的
Router::connect('/:controller', array('action' => 'index'));
因为在路由中不再检查“链接”是否属于特定页面。
编辑:好的,我正在进步。 我发现下一个和上一个分页链接不能很好地使用分页器->选项。 我删除了paginator-> options并将下一个按钮的url数组留空。 链接输出为http://www.domain.com/articles/custom-link/articles/page:2 。 进步! 但是,有什么办法可以利用第一个“文章/”?
我的路线是
Router::connect('/:link/:controller/*', array(), array(
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
));
最好为此使用相对路径:
$this->Paginator->options = array(
'url' => '/dynamic-route'
);
Or:
$this->Paginator->options = array(
'url' => '/dynamic-route/articles'
);
Or:
$this->Paginator->options = array(
'url' => array('controller'=>'dynamic-route')
);
或开始在路由器文件http://api.cakephp.org/class/router#method-Routerurl中构建自定义路由
如果您正确构建了路线,则所有路线都将自动运行:
在你的routes.php中
/**
* Movies view/details page
*/
Router::connect(
'/:link',
array(
'controller' => 'movies',
'action' => 'view',
),
array(
/**
* Custom Link:
* lowercase alphanumeric and dashes, but NO leading/trailing dash
* should be at least 4 characters long
*
* IMPORTANT:
* custom links should *NOT* overlap with actual controller
* names, like 'movies, articles' etc!
*/
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
// Define what should be passed to the 'view' action as arguments
'pass' => array('link'),
/**
* Define what parameters should be automatically preserved
* when creating URLs/links
*/
'persist' => array('link'),
)
);
/**
* Article view/details page
*/
Router::connect(
'/:link/:controller/:page_id',
array(
'controller' => 'articles',
'action' => 'view',
),
array(
/**
* Specify the 'controllers' that are allowed to be put
* after link. You can add more, for example
* 'reviews' to show reviews for a movie. this
* will result in Reviews::view([page_id]) to be shown
*/
'controller' => 'articles',
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'page_id' => '[1-9]{1}[0-9]{0,}',
// Define what should be passed to the 'view' action as arguments
'pass' => array('page_id', 'link'),
/**
* Define what parameters should be automatically preserved
* when creating URLs/links
*/
'persist' => array('page_id', 'link'),
)
);
/**
* Article overview/index page
*/
Router::connect(
'/:link/:controller/*',
array(
'controller' => 'articles',
'action' => 'index',
),
array(
'controller' => 'articles',
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
// Define what should be passed to the 'index' action as arguments
'pass' => array('link'),
/**
* Define what parameters should be automatically maintained
* when creating URLs/links
*/
'persist' => array('page_id', 'link'),
)
);
打开http://example.com/potc时,您将被带到Movies :: view('potc')
打开http://example.com/potc/articles时,您将被带到Articles :: index('potc')
当打开http://example.com/potc/articles/page:2时,您还将被带到Articles :: index('potc')。 “页面”将作为命名参数传递
打开http://example.com/potc/articles/99时,您将进入Articles :: view(99,'potc')
在您的Articles / index.ctp视图中:
debug($this->Html->link('current page', array()));
// outputs:
// <a href="/potc/articles/">current page</a>
debug($this->Html->link('next page', array('page' => 2)));
// outputs:
// <a href="/potc/articles/page:2">next page</a>
debug($this->Html->link('view article', array('action' => 'view', 'page_id' => 99)));
// outputs:
// <a href="/potc/articles/99">view article</a>
访问分页链接( http://example.com/potc/articles/page:2/sort:title/dir:desc )
debug($this->request);
输出:
object(CakeRequest) {
params => array(
'plugin' => null,
'controller' => 'articles',
'action' => 'index',
'named' => array(
'page' => '2',
'sort' => 'title',
'dir' => 'desc'
),
'pass' => array(
(int) 0 => 'potc'
),
'link' => 'potc',
(int) 0 => 'page:2/sort:title/dir:desc',
'paging' => array(
'Article' => array(
'page' => (int) 1,
'current' => (int) 0,
'count' => (int) 3,
'prevPage' => false,
'nextPage' => false,
'pageCount' => (int) 1,
'order' => array(),
'limit' => (int) 10,
'options' => array(
'page' => (int) 2,
'sort' => 'title',
'order' => array(),
'conditions' => array()
),
'paramType' => 'named'
)
),
'models' => array(
'Article' => array(
'plugin' => null,
'className' => 'Article'
)
)
)
data => array()
query => array()
url => 'potc/articles/page:2/sort:title/dir:desc'
base => ''
webroot => '/'
here => '/potc/articles/page:2/sort:title/dir:desc'
}
如您所见,所有需要的信息都在请求对象中
我看到您在此路由中使用':id':
/:link/:controller/:action/:id
但是您没有为此包含正则表达式。 另外,我不希望使用此路由,因为要匹配此路由,您必须在URL中包含操作。 例如:
/test-example/articles/view/1
对于这条路线,更好的选择是来自我原始示例的该路线:
/:link/:controller/:page_id
这将路由到:
Controller::view('page_id', 'link')
如前所述,添加路由的“顺序”确定首先匹配的内容,因此,如果在添加CakePHP默认路由之前添加了路由,则将优先选择路由。
在这种情况下; / test-example / / pages /
总是与'/:link'匹配,因此/ pages / view / test-example 也会匹配,如果您传递了有效的controllername(!),为防止这种情况,您应该在包含CakePHP默认路由之后添加路由。
如果添加路由/:link /:controller /
然后这个网址:/ test-example / something
仅当“某物”是已知控制器时才匹配
/:link/:controller/:action/:id
如果“控制器”是已知的控制器,则将匹配,任何动作将被“接受”,但是如果您尝试访问它,则会导致“未找到异常”。 同样(如上所述),您应该为'id'添加正则表达式
您添加的最后一条路线:
Router::connect('/:link/:controller/*', array(), array(
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
));
缺少默认的“操作”参数,因此CakePHP可能不会将其匹配,这可能是:
Router::connect('/:link/:controller/*',
array(
'action' => 'index',
), array(
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
));
这样,它将匹配:
/any-link/controllername/pass1
/any-link/controllername/pass1/pass2
etc.
如果将“ pass1,pass2”作为操作的参数发送到控制器,例如:
/test-example/articles/some/thing/else
将被路由到:
ArticlesController::index('some', 'thing', 'else');
我认为您路线的最佳顺序是:
注意最后两条路线的顺序; 仅当'id'是一个数字值时,路由3才会匹配,从而导致路由'view'操作。路由4将在控制器之后与'anything'匹配,并显示控制器的'index'操作
编辑:这是一个修改过的答案,当我意识到我对ArticlesConntroller :: redirect的最后一个答案有缺陷之后
对于已经设法阅读了整个问题/评论并希望知道答案的任何人。 我想出了一个解决方案,这要归功于Jeztah的帮助。 让我很难过的问题之一是,一个页面可能有2个URL。 例如: http : //www.domain.com/potc或http://www.domain.com/movies/106 。 基本上,我结合了我的思想和耶斯达的思想。
首先,我必须在route.php中执行检查,以查看.com之后的第一个参数是否与页面的快捷方式“链接”相匹配(例如: http : //www.domain.com/potc = potc)。
// get params of URL
$requestURI = explode('/', $_SERVER['REQUEST_URI']);
$scriptName = explode('/',$_SERVER['SCRIPT_NAME']);
for($i= 0;$i < sizeof($scriptName);$i++) {
if ($requestURI[$i] == $scriptName[$i]) {
unset($requestURI[$i]);
}
}
$param = array_values($requestURI);
// only concerned about first param
$param1 = $param[0];
// do the following routes if url != http://www.domain.com/users/* or http://www.domain.com
if($param1 != "users" && $param1){
// convert http://www.domain.com/assassins-creed to "assassins creed"
$pagelink = str_replace('-', ' ', $param1);
$pagesModel = ClassRegistry::init('Page');
// check if there is a page whose "link" matches converted link, if so, get the field "id"
$matched_page_id = $pagesModel->field('id', array('Page.link LIKE' => "$pagelink"));
// if there is a match, route as follows
if($matched_page_id){
// Jeztah's way with some modifications
// domain.com/potc/articles/edit/1
Router::connect(
'/:link/:controller/:action/:id',
array('page_id' => $matched_page_id, 'category' => 0),
array(
'pass' => array('id', 'link', 'category', 'page_id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
'id' => '[0-9]+'
)
);
// domain.com/potc/articles/1
Router::connect(
'/:link/:controller/:id',
array('action' => 'view', 'page_id' => $matched_page_id, 'category' => 0),
array(
'pass' => array('id', 'link', 'category', 'page_id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
'id' => '[0-9]+'
)
);
// domain.com/potc/articles/add
Router::connect(
'/:link/:controller/:action',
array('page_id' => $matched_page_id, 'category' => 0),
array(
'pass' => array('link', 'category', 'page_id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
'action' => 'add|uncategorized',
)
);
// domain.com/potc/articles OR domain.com/articles/page:2
Router::connect(
'/:link/:controller/*',
array('action' => 'index', 'page_id' => $matched_page_id, 'category' => 0),
array(
'pass' => array('link', 'category', 'page_id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
)
);
} // end if first param matches a page's "link" shortcut
} // end if first param is not users and is not empty
// do some general site routing
// do some general site routing
// now route for page's that do not have a link shortcut (example: http://www.domain.com/movies/106)
// domain.com/movies/106/articles/edit/1
Router::connect(
'/:category/:page_id/:controller/:action/:id',
array('link' => '0'),
array(
'pass' => array('id', 'link', 'category', 'page_id'),
'page_id' => '[0-9]+',
'id' => '[0-9]+'
)
);
// domain.com/movies/106/articles/1
Router::connect(
'/:category/:page_id/:controller/:id',
array('action' => 'view', 'link' => '0'),
array(
'pass' => array('id', 'link', 'category', 'page_id'),
'page_id' => '[0-9]+',
'id' => '[0-9]+'
)
);
// domain.com/movies/106/articles/add
Router::connect(
'/:category/:page_id/:controller/:action',
array('link' => '0'),
array(
'pass' => array('link', 'category', 'page_id'),
'page_id' => '[0-9]+',
'action' => 'add|uncategorized'
)
);
// domain.com/movies/106/articles OR domain.com/movies/106/articles/page:2
Router::connect(
'/:category/:page_id/:controller/*',
array('action' => 'index', 'link' => '0'),
array(
'pass' => array('link', 'category', 'page_id', 'controller'),
'page_id' => '[0-9]+'
)
);
因为page_id在:link路由和:category路由中都被传递,所以我不必具有建议使用的获取页面ID的组件。
现在在我的ArticlesController中
public function index($link = null, $category = null, $page_id = null, $controller = null) {
if($page_id){
// display all articles for a particular page if on
// http://www.domain.com/potc/articles or http://www.domain.com/movies/106/articles
$this->set('articles', $this->paginate('Article', array('Article.page_id' => $page_id, 'Article.status <= 5')));
}
else{
// display all articles if on http://www.domain.com/articles
$this->set('articles', $this->paginate('Article', array('Article.status <= 5')));
}
} // end index function
public function view($id = null, $link = null, $category = null, $page_id = null) {
$this->Article->id = $id;
$article_page = $this->Article->field('page_id', array('id =' => $id));
if (!$this->Article->exists()) {
$this->Session->setFlash('This article does not exist');
// using PageLinkRedirect function of my custom component,
// determine where to redirect. Either to "potc/articles" or
// "movies/106/articles";
$this->redirect('../'.$this->CustomPage->PageLinkRedirect($link, $category, $page_id).'/articles', null, true);
}
elseif($article_page != $page_id) {
$this->Session->setFlash('Invalid article for this page');
// using PageLinkRedirect function of my custom component,
// determine where to redirect. Either to "potc/articles" or
// "movies/106/articles";
$this->redirect('../'.$this->CustomPage->PageLinkRedirect($link, $category, $page_id).'/articles', null, true);
}
else{
$this->set('title_for_layout', $this->Article->field('title', array('id =' => $id)));
$this->set('article', $this->Article->read(null, $id));
$this->set('comments', $this->paginate($this->Article->Comment, array('Comment.module_id' => $this->viewVars['module_id'], 'Comment.post_id' => $id)));
} // end else
} // end view function
我的分页存储在一个元素中,但是我将该元素加载到Articles index.ctp视图的底部
<?php echo $this->element('all/pagination', array('pagination_url' => 'articles')); ?>
我将为每个不同的控制器放置相同的代码,但更改单词“ articles”(例如:“评论”,“新闻/主题”等)
我的pagination.ctp元素看起来像这样
<?php
if($this->params['paging'][key($this->params['paging'])]['pageCount'] > 1){
$pagination_class = "pagination_enabled";
}
else{
$pagination_class = "pagination_disabled";
}
?>
<div class="<?php echo $pagination_class; ?>">
<?php echo $this->Paginator->counter(array(
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
));
?>
<ul>
<?php
// $link is set in AppController from the link param, same with category and page_id
if($link){
$this->Paginator->options = array('url' => array('controller' => null, $link, $pagination_url));
// This outputs http://www.domain.com/potc/articles where articles
// is from the passed $pagination_url when I loaded the element
// in my Articles index.ctp view. I have to set controller = null
// or else the link will output as http://www.domain.com/articles/potc/articles
}
else{
$this->Paginator->options = array('url' => array('controller' => null, 'link' => null, $category, $page_id, $pagination_url));
// This outputs http://www.domain.com/movies/106/articles where articles
// is from the passed $pagination_url when I loaded the element
// in my Articles index.ctp view. I have to set controller = null AND
// link = null or else the link will output as
// http://www.domain.com/articles/0/movies/9/articles
}
echo $this->Paginator->prev('< ' . __('previous'), array('tag' => 'li'), null, array('class' => 'prev disabled'));
if($this->Paginator->numbers){echo $this->Paginator->numbers(array('tag' => 'li', 'separator' => ''));}
echo $this->Paginator->next(__('next') . ' >', array('tag' => 'li'), null, array('class' => 'next disabled'));
?>
</ul></div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.