Subversion-Projekte lars-tiefland.ci

Revision

Revision 2254 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | 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
 *
2257 lars 9
 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
68 lars 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/)
2257 lars 32
 * @copyright	Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
68 lars 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
 
2257 lars 342
		// _parse_attributes(), called by initialize(), needs to run at least once
343
		// in order to enable "rel" attributes, and this triggers it.
344
		isset($params['attributes']) OR $params['attributes'] = array();
345
 
68 lars 346
		$this->initialize($params);
347
		log_message('info', 'Pagination Class Initialized');
348
	}
349
 
350
	// --------------------------------------------------------------------
351
 
352
	/**
353
	 * Initialize Preferences
354
	 *
355
	 * @param	array	$params	Initialization parameters
356
	 * @return	CI_Pagination
357
	 */
358
	public function initialize(array $params = array())
359
	{
2257 lars 360
		if (isset($params['attributes']) && is_array($params['attributes']))
68 lars 361
		{
362
			$this->_parse_attributes($params['attributes']);
363
			unset($params['attributes']);
364
		}
365
 
366
		// Deprecated legacy support for the anchor_class option
367
		// Should be removed in CI 3.1+
368
		if (isset($params['anchor_class']))
369
		{
370
			empty($params['anchor_class']) OR $attributes['class'] = $params['anchor_class'];
371
			unset($params['anchor_class']);
372
		}
373
 
374
		foreach ($params as $key => $val)
375
		{
376
			if (property_exists($this, $key))
377
			{
378
				$this->$key = $val;
379
			}
380
		}
381
 
382
		if ($this->CI->config->item('enable_query_strings') === TRUE)
383
		{
384
			$this->page_query_string = TRUE;
385
		}
386
 
387
		if ($this->use_global_url_suffix === TRUE)
388
		{
389
			$this->suffix = $this->CI->config->item('url_suffix');
390
		}
391
 
392
		return $this;
393
	}
394
 
395
	// --------------------------------------------------------------------
396
 
397
	/**
398
	 * Generate the pagination links
399
	 *
400
	 * @return	string
401
	 */
402
	public function create_links()
403
	{
404
		// If our item count or per-page total is zero there is no need to continue.
405
		// Note: DO NOT change the operator to === here!
406
		if ($this->total_rows == 0 OR $this->per_page == 0)
407
		{
408
			return '';
409
		}
410
 
411
		// Calculate the total number of pages
412
		$num_pages = (int) ceil($this->total_rows / $this->per_page);
413
 
414
		// Is there only one page? Hm... nothing more to do here then.
415
		if ($num_pages === 1)
416
		{
417
			return '';
418
		}
419
 
420
		// Check the user defined number of links.
421
		$this->num_links = (int) $this->num_links;
422
 
423
		if ($this->num_links < 0)
424
		{
425
			show_error('Your number of links must be a non-negative number.');
426
		}
427
 
428
		// Keep any existing query string items.
429
		// Note: Has nothing to do with any other query string option.
430
		if ($this->reuse_query_string === TRUE)
431
		{
432
			$get = $this->CI->input->get();
433
 
2107 lars 434
			// Unset the control, method, old-school routing options
68 lars 435
			unset($get['c'], $get['m'], $get[$this->query_string_segment]);
436
		}
437
		else
438
		{
439
			$get = array();
440
		}
441
 
442
		// Put together our base and first URLs.
443
		// Note: DO NOT append to the properties as that would break successive calls
444
		$base_url = trim($this->base_url);
445
		$first_url = $this->first_url;
446
 
447
		$query_string = '';
448
		$query_string_sep = (strpos($base_url, '?') === FALSE) ? '?' : '&amp;';
449
 
450
		// Are we using query strings?
451
		if ($this->page_query_string === TRUE)
452
		{
453
			// If a custom first_url hasn't been specified, we'll create one from
454
			// the base_url, but without the page item.
455
			if ($first_url === '')
456
			{
457
				$first_url = $base_url;
458
 
459
				// If we saved any GET items earlier, make sure they're appended.
460
				if ( ! empty($get))
461
				{
462
					$first_url .= $query_string_sep.http_build_query($get);
463
				}
464
			}
465
 
466
			// Add the page segment to the end of the query string, where the
467
			// page number will be appended.
468
			$base_url .= $query_string_sep.http_build_query(array_merge($get, array($this->query_string_segment => '')));
469
		}
470
		else
471
		{
472
			// Standard segment mode.
473
			// Generate our saved query string to append later after the page number.
474
			if ( ! empty($get))
475
			{
476
				$query_string = $query_string_sep.http_build_query($get);
477
				$this->suffix .= $query_string;
478
			}
479
 
480
			// Does the base_url have the query string in it?
481
			// If we're supposed to save it, remove it so we can append it later.
482
			if ($this->reuse_query_string === TRUE && ($base_query_pos = strpos($base_url, '?')) !== FALSE)
483
			{
484
				$base_url = substr($base_url, 0, $base_query_pos);
485
			}
486
 
487
			if ($first_url === '')
488
			{
489
				$first_url = $base_url.$query_string;
490
			}
491
 
492
			$base_url = rtrim($base_url, '/').'/';
493
		}
494
 
495
		// Determine the current page number.
496
		$base_page = ($this->use_page_numbers) ? 1 : 0;
497
 
498
		// Are we using query strings?
499
		if ($this->page_query_string === TRUE)
500
		{
501
			$this->cur_page = $this->CI->input->get($this->query_string_segment);
502
		}
503
		elseif (empty($this->cur_page))
504
		{
505
			// Default to the last segment number if one hasn't been defined.
506
			if ($this->uri_segment === 0)
507
			{
508
				$this->uri_segment = count($this->CI->uri->segment_array());
509
			}
510
 
511
			$this->cur_page = $this->CI->uri->segment($this->uri_segment);
512
 
513
			// Remove any specified prefix/suffix from the segment.
514
			if ($this->prefix !== '' OR $this->suffix !== '')
515
			{
516
				$this->cur_page = str_replace(array($this->prefix, $this->suffix), '', $this->cur_page);
517
			}
518
		}
519
		else
520
		{
521
			$this->cur_page = (string) $this->cur_page;
522
		}
523
 
524
		// If something isn't quite right, back to the default base page.
525
		if ( ! ctype_digit($this->cur_page) OR ($this->use_page_numbers && (int) $this->cur_page === 0))
526
		{
527
			$this->cur_page = $base_page;
528
		}
529
		else
530
		{
531
			// Make sure we're using integers for comparisons later.
532
			$this->cur_page = (int) $this->cur_page;
533
		}
534
 
535
		// Is the page number beyond the result range?
536
		// If so, we show the last page.
537
		if ($this->use_page_numbers)
538
		{
539
			if ($this->cur_page > $num_pages)
540
			{
541
				$this->cur_page = $num_pages;
542
			}
543
		}
544
		elseif ($this->cur_page > $this->total_rows)
545
		{
546
			$this->cur_page = ($num_pages - 1) * $this->per_page;
547
		}
548
 
549
		$uri_page_number = $this->cur_page;
550
 
551
		// If we're using offset instead of page numbers, convert it
552
		// to a page number, so we can generate the surrounding number links.
553
		if ( ! $this->use_page_numbers)
554
		{
555
			$this->cur_page = (int) floor(($this->cur_page/$this->per_page) + 1);
556
		}
557
 
558
		// Calculate the start and end numbers. These determine
559
		// which number to start and end the digit links with.
560
		$start	= (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1;
561
		$end	= (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages;
562
 
563
		// And here we go...
564
		$output = '';
565
 
566
		// Render the "First" link.
567
		if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1 + ! $this->num_links))
568
		{
569
			// Take the general parameters, and squeeze this pagination-page attr in for JS frameworks.
570
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1);
571
 
572
			$output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
573
				.$this->first_link.'</a>'.$this->first_tag_close;
574
		}
575
 
576
		// Render the "Previous" link.
577
		if ($this->prev_link !== FALSE && $this->cur_page !== 1)
578
		{
579
			$i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page;
580
 
581
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, ($this->cur_page - 1));
582
 
583
			if ($i === $base_page)
584
			{
585
				// First page
586
				$output .= $this->prev_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('prev').'>'
587
					.$this->prev_link.'</a>'.$this->prev_tag_close;
588
			}
589
			else
590
			{
591
				$append = $this->prefix.$i.$this->suffix;
592
				$output .= $this->prev_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>'
593
					.$this->prev_link.'</a>'.$this->prev_tag_close;
594
			}
595
 
596
		}
597
 
598
		// Render the pages
599
		if ($this->display_pages !== FALSE)
600
		{
601
			// Write the digit links
602
			for ($loop = $start - 1; $loop <= $end; $loop++)
603
			{
604
				$i = ($this->use_page_numbers) ? $loop : ($loop * $this->per_page) - $this->per_page;
605
 
606
				$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $loop);
607
 
608
				if ($i >= $base_page)
609
				{
610
					if ($this->cur_page === $loop)
611
					{
612
						// Current page
613
						$output .= $this->cur_tag_open.$loop.$this->cur_tag_close;
614
					}
615
					elseif ($i === $base_page)
616
					{
617
						// First page
618
						$output .= $this->num_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
619
							.$loop.'</a>'.$this->num_tag_close;
620
					}
621
					else
622
					{
623
						$append = $this->prefix.$i.$this->suffix;
624
						$output .= $this->num_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.'>'
625
							.$loop.'</a>'.$this->num_tag_close;
626
					}
627
				}
628
			}
629
		}
630
 
631
		// Render the "next" link
632
		if ($this->next_link !== FALSE && $this->cur_page < $num_pages)
633
		{
634
			$i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page;
635
 
636
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $this->cur_page + 1);
637
 
638
			$output .= $this->next_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes
639
				.$this->_attr_rel('next').'>'.$this->next_link.'</a>'.$this->next_tag_close;
640
		}
641
 
642
		// Render the "Last" link
643
		if ($this->last_link !== FALSE && ($this->cur_page + $this->num_links + ! $this->num_links) < $num_pages)
644
		{
645
			$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
646
 
647
			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $num_pages);
648
 
649
			$output .= $this->last_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>'
650
				.$this->last_link.'</a>'.$this->last_tag_close;
651
		}
652
 
653
		// Kill double slashes. Note: Sometimes we can end up with a double slash
654
		// in the penultimate link so we'll kill all double slashes.
655
		$output = preg_replace('#([^:"])//+#', '\\1/', $output);
656
 
657
		// Add the wrapper HTML if exists
658
		return $this->full_tag_open.$output.$this->full_tag_close;
659
	}
660
 
661
	// --------------------------------------------------------------------
662
 
663
	/**
664
	 * Parse attributes
665
	 *
666
	 * @param	array	$attributes
667
	 * @return	void
668
	 */
669
	protected function _parse_attributes($attributes)
670
	{
671
		isset($attributes['rel']) OR $attributes['rel'] = TRUE;
672
		$this->_link_types = ($attributes['rel'])
673
			? array('start' => 'start', 'prev' => 'prev', 'next' => 'next')
674
			: array();
675
		unset($attributes['rel']);
676
 
677
		$this->_attributes = '';
678
		foreach ($attributes as $key => $value)
679
		{
680
			$this->_attributes .= ' '.$key.'="'.$value.'"';
681
		}
682
	}
683
 
684
	// --------------------------------------------------------------------
685
 
686
	/**
687
	 * Add "rel" attribute
688
	 *
689
	 * @link	http://www.w3.org/TR/html5/links.html#linkTypes
690
	 * @param	string	$type
691
	 * @return	string
692
	 */
693
	protected function _attr_rel($type)
694
	{
695
		if (isset($this->_link_types[$type]))
696
		{
697
			unset($this->_link_types[$type]);
698
			return ' rel="'.$type.'"';
699
		}
700
 
701
		return '';
702
	}
703
 
704
}