Subversion-Projekte lars-tiefland.ci

Revision

Revision 2049 | Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
68 lars 1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
 
40
/**
41
 * Pagination Class
42
 *
43
 * @package		CodeIgniter
44
 * @subpackage	Libraries
45
 * @category	Pagination
46
 * @author		EllisLab Dev Team
47
 * @link		https://codeigniter.com/user_guide/libraries/pagination.html
48
 */
49
class CI_Pagination {
50
 
51
	/**
52
	 * Base URL
53
	 *
54
	 * The page that we're linking to
55
	 *
56
	 * @var	string
57
	 */
58
	protected $base_url		= '';
59
 
60
	/**
61
	 * Prefix
62
	 *
63
	 * @var	string
64
	 */
65
	protected $prefix = '';
66
 
67
	/**
68
	 * Suffix
69
	 *
70
	 * @var	string
71
	 */
72
	protected $suffix = '';
73
 
74
	/**
75
	 * Total number of items
76
	 *
77
	 * @var	int
78
	 */
79
	protected $total_rows = 0;
80
 
81
	/**
82
	 * Number of links to show
83
	 *
84
	 * Relates to "digit" type links shown before/after
85
	 * the currently viewed page.
86
	 *
87
	 * @var	int
88
	 */
89
	protected $num_links = 2;
90
 
91
	/**
92
	 * Items per page
93
	 *
94
	 * @var	int
95
	 */
96
	public $per_page = 10;
97
 
98
	/**
99
	 * Current page
100
	 *
101
	 * @var	int
102
	 */
103
	public $cur_page = 0;
104
 
105
	/**
106
	 * Use page numbers flag
107
	 *
108
	 * Whether to use actual page numbers instead of an offset
109
	 *
110
	 * @var	bool
111
	 */
112
	protected $use_page_numbers = FALSE;
113
 
114
	/**
115
	 * First link
116
	 *
117
	 * @var	string
118
	 */
119
	protected $first_link = '&lsaquo; First';
120
 
121
	/**
122
	 * Next link
123
	 *
124
	 * @var	string
125
	 */
126
	protected $next_link = '&gt;';
127
 
128
	/**
129
	 * Previous link
130
	 *
131
	 * @var	string
132
	 */
133
	protected $prev_link = '&lt;';
134
 
135
	/**
136
	 * Last link
137
	 *
138
	 * @var	string
139
	 */
140
	protected $last_link = 'Last &rsaquo;';
141
 
142
	/**
143
	 * URI Segment
144
	 *
145
	 * @var	int
146
	 */
147
	protected $uri_segment = 0;
148
 
149
	/**
150
	 * Full tag open
151
	 *
152
	 * @var	string
153
	 */
154
	protected $full_tag_open = '';
155
 
156
	/**
157
	 * Full tag close
158
	 *
159
	 * @var	string
160
	 */
161
	protected $full_tag_close = '';
162
 
163
	/**
164
	 * First tag open
165
	 *
166
	 * @var	string
167
	 */
168
	protected $first_tag_open = '';
169
 
170
	/**
171
	 * First tag close
172
	 *
173
	 * @var	string
174
	 */
175
	protected $first_tag_close = '';
176
 
177
	/**
178
	 * Last tag open
179
	 *
180
	 * @var	string
181
	 */
182
	protected $last_tag_open = '';
183
 
184
	/**
185
	 * Last tag close
186
	 *
187
	 * @var	string
188
	 */
189
	protected $last_tag_close = '';
190
 
191
	/**
192
	 * First URL
193
	 *
194
	 * An alternative URL for the first page
195
	 *
196
	 * @var	string
197
	 */
198
	protected $first_url = '';
199
 
200
	/**
201
	 * Current tag open
202
	 *
203
	 * @var	string
204
	 */
205
	protected $cur_tag_open = '<strong>';
206
 
207
	/**
208
	 * Current tag close
209
	 *
210
	 * @var	string
211
	 */
212
	protected $cur_tag_close = '</strong>';
213
 
214
	/**
215
	 * Next tag open
216
	 *
217
	 * @var	string
218
	 */
219
	protected $next_tag_open = '';
220
 
221
	/**
222
	 * Next tag close
223
	 *
224
	 * @var	string
225
	 */
226
	protected $next_tag_close = '';
227
 
228
	/**
229
	 * Previous tag open
230
	 *
231
	 * @var	string
232
	 */
233
	protected $prev_tag_open = '';
234
 
235
	/**
236
	 * Previous tag close
237
	 *
238
	 * @var	string
239
	 */
240
	protected $prev_tag_close = '';
241
 
242
	/**
243
	 * Number tag open
244
	 *
245
	 * @var	string
246
	 */
247
	protected $num_tag_open = '';
248
 
249
	/**
250
	 * Number tag close
251
	 *
252
	 * @var	string
253
	 */
254
	protected $num_tag_close = '';
255
 
256
	/**
257
	 * Page query string flag
258
	 *
259
	 * @var	bool
260
	 */
261
	protected $page_query_string = FALSE;
262
 
263
	/**
264
	 * Query string segment
265
	 *
266
	 * @var	string
267
	 */
268
	protected $query_string_segment = 'per_page';
269
 
270
	/**
271
	 * Display pages flag
272
	 *
273
	 * @var	bool
274
	 */
275
	protected $display_pages = TRUE;
276
 
277
	/**
278
	 * Attributes
279
	 *
280
	 * @var	string
281
	 */
282
	protected $_attributes = '';
283
 
284
	/**
285
	 * Link types
286
	 *
287
	 * "rel" attribute
288
	 *
289
	 * @see	CI_Pagination::_attr_rel()
290
	 * @var	array
291
	 */
292
	protected $_link_types = array();
293
 
294
	/**
295
	 * Reuse query string flag
296
	 *
297
	 * @var	bool
298
	 */
299
	protected $reuse_query_string = FALSE;
300
 
301
	/**
302
	 * Use global URL suffix flag
303
	 *
304
	 * @var	bool
305
	 */
306
	protected $use_global_url_suffix = FALSE;
307
 
308
	/**
309
	 * Data page attribute
310
	 *
311
	 * @var	string
312
	 */
313
	protected $data_page_attr = 'data-ci-pagination-page';
314
 
315
	/**
316
	 * CI Singleton
317
	 *
318
	 * @var	object
319
	 */
320
	protected $CI;
321
 
322
	// --------------------------------------------------------------------
323
 
324
	/**
325
	 * Constructor
326
	 *
327
	 * @param	array	$params	Initialization parameters
328
	 * @return	void
329
	 */
330
	public function __construct($params = array())
331
	{
332
		$this->CI =& get_instance();
333
		$this->CI->load->language('pagination');
334
		foreach (array('first_link', 'next_link', 'prev_link', 'last_link') as $key)
335
		{
336
			if (($val = $this->CI->lang->line('pagination_'.$key)) !== FALSE)
337
			{
338
				$this->$key = $val;
339
			}
340
		}
341
 
342
		$this->initialize($params);
343
		log_message('info', 'Pagination Class Initialized');
344
	}
345
 
346
	// --------------------------------------------------------------------
347
 
348
	/**
349
	 * Initialize Preferences
350
	 *
351
	 * @param	array	$params	Initialization parameters
352
	 * @return	CI_Pagination
353
	 */
354
	public function initialize(array $params = array())
355
	{
356
		isset($params['attributes']) OR $params['attributes'] = array();
357
		if (is_array($params['attributes']))
358
		{
359
			$this->_parse_attributes($params['attributes']);
360
			unset($params['attributes']);
361
		}
362
 
363
		// Deprecated legacy support for the anchor_class option
364
		// Should be removed in CI 3.1+
365
		if (isset($params['anchor_class']))
366
		{
367
			empty($params['anchor_class']) OR $attributes['class'] = $params['anchor_class'];
368
			unset($params['anchor_class']);
369
		}
370
 
371
		foreach ($params as $key => $val)
372
		{
373
			if (property_exists($this, $key))
374
			{
375
				$this->$key = $val;
376
			}
377
		}
378
 
379
		if ($this->CI->config->item('enable_query_strings') === TRUE)
380
		{
381
			$this->page_query_string = TRUE;
382
		}
383
 
384
		if ($this->use_global_url_suffix === TRUE)
385
		{
386
			$this->suffix = $this->CI->config->item('url_suffix');
387
		}
388
 
389
		return $this;
390
	}
391
 
392
	// --------------------------------------------------------------------
393
 
394
	/**
395
	 * Generate the pagination links
396
	 *
397
	 * @return	string
398
	 */
399
	public function create_links()
400
	{
401
		// If our item count or per-page total is zero there is no need to continue.
402
		// Note: DO NOT change the operator to === here!
403
		if ($this->total_rows == 0 OR $this->per_page == 0)
404
		{
405
			return '';
406
		}
407
 
408
		// Calculate the total number of pages
409
		$num_pages = (int) ceil($this->total_rows / $this->per_page);
410
 
411
		// Is there only one page? Hm... nothing more to do here then.
412
		if ($num_pages === 1)
413
		{
414
			return '';
415
		}
416
 
417
		// Check the user defined number of links.
418
		$this->num_links = (int) $this->num_links;
419
 
420
		if ($this->num_links < 0)
421
		{
422
			show_error('Your number of links must be a non-negative number.');
423
		}
424
 
425
		// Keep any existing query string items.
426
		// Note: Has nothing to do with any other query string option.
427
		if ($this->reuse_query_string === TRUE)
428
		{
429
			$get = $this->CI->input->get();
430
 
431
			// Unset the controll, method, old-school routing options
432
			unset($get['c'], $get['m'], $get[$this->query_string_segment]);
433
		}
434
		else
435
		{
436
			$get = array();
437
		}
438
 
439
		// Put together our base and first URLs.
440
		// Note: DO NOT append to the properties as that would break successive calls
441
		$base_url = trim($this->base_url);
442
		$first_url = $this->first_url;
443
 
444
		$query_string = '';
445
		$query_string_sep = (strpos($base_url, '?') === FALSE) ? '?' : '&amp;';
446
 
447
		// Are we using query strings?
448
		if ($this->page_query_string === TRUE)
449
		{
450
			// If a custom first_url hasn't been specified, we'll create one from
451
			// the base_url, but without the page item.
452
			if ($first_url === '')
453
			{
454
				$first_url = $base_url;
455
 
456
				// If we saved any GET items earlier, make sure they're appended.
457
				if ( ! empty($get))
458
				{
459
					$first_url .= $query_string_sep.http_build_query($get);
460
				}
461
			}
462
 
463
			// Add the page segment to the end of the query string, where the
464
			// page number will be appended.
465
			$base_url .= $query_string_sep.http_build_query(array_merge($get, array($this->query_string_segment => '')));
466
		}
467
		else
468
		{
469
			// Standard segment mode.
470
			// Generate our saved query string to append later after the page number.
471
			if ( ! empty($get))
472
			{
473
				$query_string = $query_string_sep.http_build_query($get);
474
				$this->suffix .= $query_string;
475
			}
476
 
477
			// Does the base_url have the query string in it?
478
			// If we're supposed to save it, remove it so we can append it later.
479
			if ($this->reuse_query_string === TRUE && ($base_query_pos = strpos($base_url, '?')) !== FALSE)
480
			{
481
				$base_url = substr($base_url, 0, $base_query_pos);
482
			}
483
 
484
			if ($first_url === '')
485
			{
486
				$first_url = $base_url.$query_string;
487
			}
488
 
489
			$base_url = rtrim($base_url, '/').'/';
490
		}
491
 
492
		// Determine the current page number.
493
		$base_page = ($this->use_page_numbers) ? 1 : 0;
494
 
495
		// Are we using query strings?
496
		if ($this->page_query_string === TRUE)
497
		{
498
			$this->cur_page = $this->CI->input->get($this->query_string_segment);
499
		}
500
		elseif (empty($this->cur_page))
501
		{
502
			// Default to the last segment number if one hasn't been defined.
503
			if ($this->uri_segment === 0)
504
			{
505
				$this->uri_segment = count($this->CI->uri->segment_array());
506
			}
507
 
508
			$this->cur_page = $this->CI->uri->segment($this->uri_segment);
509
 
510
			// Remove any specified prefix/suffix from the segment.
511
			if ($this->prefix !== '' OR $this->suffix !== '')
512
			{
513
				$this->cur_page = str_replace(array($this->prefix, $this->suffix), '', $this->cur_page);
514
			}
515
		}
516
		else
517
		{
518
			$this->cur_page = (string) $this->cur_page;
519
		}
520
 
521
		// If something isn't quite right, back to the default base page.
522
		if ( ! ctype_digit($this->cur_page) OR ($this->use_page_numbers && (int) $this->cur_page === 0))
523
		{
524
			$this->cur_page = $base_page;
525
		}
526
		else
527
		{
528
			// Make sure we're using integers for comparisons later.
529
			$this->cur_page = (int) $this->cur_page;
530
		}
531
 
532
		// Is the page number beyond the result range?
533
		// If so, we show the last page.
534
		if ($this->use_page_numbers)
535
		{
536
			if ($this->cur_page > $num_pages)
537
			{
538
				$this->cur_page = $num_pages;
539
			}
540
		}
541
		elseif ($this->cur_page > $this->total_rows)
542
		{
543
			$this->cur_page = ($num_pages - 1) * $this->per_page;
544
		}
545
 
546
		$uri_page_number = $this->cur_page;
547
 
548
		// If we're using offset instead of page numbers, convert it
549
		// to a page number, so we can generate the surrounding number links.
550
		if ( ! $this->use_page_numbers)
551
		{
552
			$this->cur_page = (int) floor(($this->cur_page/$this->per_page) + 1);
553
		}
554
 
555
		// Calculate the start and end numbers. These determine
556
		// which number to start and end the digit links with.
557
		$start	= (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1;
558
		$end	= (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages;
559
 
560
		// And here we go...
561
		$output = '';
562
 
563
		// Render the "First" link.
564
		if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1 + ! $this->num_links))
565
		{
566
			// Take the general parameters, and squeeze this pagination-page attr in for JS frameworks.
567
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1);
568
 
569
			$output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
570
				.$this->first_link.'</a>'.$this->first_tag_close;
571
		}
572
 
573
		// Render the "Previous" link.
574
		if ($this->prev_link !== FALSE && $this->cur_page !== 1)
575
		{
576
			$i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page;
577
 
578
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, ($this->cur_page - 1));
579
 
580
			if ($i === $base_page)
581
			{
582
				// First page
583
				$output .= $this->prev_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('prev').'>'
584
					.$this->prev_link.'</a>'.$this->prev_tag_close;
585
			}
586
			else
587
			{
588
				$append = $this->prefix.$i.$this->suffix;
589
				$output .= $this->prev_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>'
590
					.$this->prev_link.'</a>'.$this->prev_tag_close;
591
			}
592
 
593
		}
594
 
595
		// Render the pages
596
		if ($this->display_pages !== FALSE)
597
		{
598
			// Write the digit links
599
			for ($loop = $start - 1; $loop <= $end; $loop++)
600
			{
601
				$i = ($this->use_page_numbers) ? $loop : ($loop * $this->per_page) - $this->per_page;
602
 
603
				$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $loop);
604
 
605
				if ($i >= $base_page)
606
				{
607
					if ($this->cur_page === $loop)
608
					{
609
						// Current page
610
						$output .= $this->cur_tag_open.$loop.$this->cur_tag_close;
611
					}
612
					elseif ($i === $base_page)
613
					{
614
						// First page
615
						$output .= $this->num_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
616
							.$loop.'</a>'.$this->num_tag_close;
617
					}
618
					else
619
					{
620
						$append = $this->prefix.$i.$this->suffix;
621
						$output .= $this->num_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.'>'
622
							.$loop.'</a>'.$this->num_tag_close;
623
					}
624
				}
625
			}
626
		}
627
 
628
		// Render the "next" link
629
		if ($this->next_link !== FALSE && $this->cur_page < $num_pages)
630
		{
631
			$i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page;
632
 
633
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $this->cur_page + 1);
634
 
635
			$output .= $this->next_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes
636
				.$this->_attr_rel('next').'>'.$this->next_link.'</a>'.$this->next_tag_close;
637
		}
638
 
639
		// Render the "Last" link
640
		if ($this->last_link !== FALSE && ($this->cur_page + $this->num_links + ! $this->num_links) < $num_pages)
641
		{
642
			$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
643
 
644
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $num_pages);
645
 
646
			$output .= $this->last_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>'
647
				.$this->last_link.'</a>'.$this->last_tag_close;
648
		}
649
 
650
		// Kill double slashes. Note: Sometimes we can end up with a double slash
651
		// in the penultimate link so we'll kill all double slashes.
652
		$output = preg_replace('#([^:"])//+#', '\\1/', $output);
653
 
654
		// Add the wrapper HTML if exists
655
		return $this->full_tag_open.$output.$this->full_tag_close;
656
	}
657
 
658
	// --------------------------------------------------------------------
659
 
660
	/**
661
	 * Parse attributes
662
	 *
663
	 * @param	array	$attributes
664
	 * @return	void
665
	 */
666
	protected function _parse_attributes($attributes)
667
	{
668
		isset($attributes['rel']) OR $attributes['rel'] = TRUE;
669
		$this->_link_types = ($attributes['rel'])
670
			? array('start' => 'start', 'prev' => 'prev', 'next' => 'next')
671
			: array();
672
		unset($attributes['rel']);
673
 
674
		$this->_attributes = '';
675
		foreach ($attributes as $key => $value)
676
		{
677
			$this->_attributes .= ' '.$key.'="'.$value.'"';
678
		}
679
	}
680
 
681
	// --------------------------------------------------------------------
682
 
683
	/**
684
	 * Add "rel" attribute
685
	 *
686
	 * @link	http://www.w3.org/TR/html5/links.html#linkTypes
687
	 * @param	string	$type
688
	 * @return	string
689
	 */
690
	protected function _attr_rel($type)
691
	{
692
		if (isset($this->_link_types[$type]))
693
		{
694
			unset($this->_link_types[$type]);
695
			return ' rel="'.$type.'"';
696
		}
697
 
698
		return '';
699
	}
700
 
701
}