main
parent
14b5a48bed
commit
b1715e8f3e
@ -0,0 +1,105 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* @author Robert Strutts |
||||
* @copyright Copyright (c) 2022, Robert Strutts. |
||||
* @license MIT |
||||
*/ |
||||
|
||||
namespace IOcornerstone\Framework\Database; |
||||
|
||||
use IOcornerstone\Framework\{ |
||||
RandomEngine, |
||||
Common, |
||||
}; |
||||
|
||||
final class DummyData { |
||||
|
||||
private $pdo; |
||||
private $randomEngine; |
||||
|
||||
public function __construct(\PDO $pdo) { |
||||
$this->pdo = $pdo; |
||||
$this->randomEngine = new RandomEngine(); |
||||
} |
||||
|
||||
/* |
||||
* Helper for add_dummy_data and get_dummy_data. |
||||
* Purpose: To return ONE ROW of junk/dummy data from input data. |
||||
* @param array $data |
||||
* @retval array of random dummy data AKA one row worth of it. |
||||
*/ |
||||
|
||||
private function useDummyData(array $data): array { |
||||
$ret = []; |
||||
foreach ($data as $field => $array_values) { |
||||
$array_count = Common::getCount($array_values); |
||||
if ($array_count) { |
||||
$ret[$field] = $array_values[$this->randomEngine->getInt(0, $array_count - 1)]; |
||||
} |
||||
} |
||||
return $ret; |
||||
} |
||||
|
||||
/** |
||||
* Inserts Dummy Data to DB |
||||
* @param int $num_rows to add/make |
||||
* @param array $data sample data EX: array('fname'=>array('bob','kim','lisa', ect...), ...) |
||||
* @retval bool true |
||||
*/ |
||||
public function addDummyData(string $table, int $num_rows, array $data): bool { |
||||
for ($i = 0; $i < $num_rows; $i++) { |
||||
$bind_data = $this->useDummyData($data); |
||||
$fields = []; |
||||
foreach ($data as $field => $array_values) { |
||||
$fields[] = $field; |
||||
} |
||||
|
||||
$sql = "INSERT INTO `{$table}` " |
||||
. "(" . implode(", ", $fields) . ") " |
||||
. "VALUES (:" . implode(", :", $fields) . ");"; |
||||
|
||||
$bind = []; |
||||
foreach ($fields as $field) { |
||||
$bind[":$field"] = $bind_data[$field]; |
||||
} |
||||
unset($bind_data); |
||||
unset($fields); |
||||
|
||||
$pdo_stmt = $this->pdo->prepare($sql); |
||||
$exec = $pdo_stmt->execute($bind); |
||||
unset($bind); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Make an array of fields for a fake row of dummy data out of input data. |
||||
* @param int $num_rows to make |
||||
* @param array $data sample data |
||||
* @retval array of rows with dummy data in it. |
||||
*/ |
||||
public function getDummyData(int $num_rows, array $data): array { |
||||
if ($num_rows > 100) { |
||||
throw new \LengthException("Generating too much dummy data via \$num_rows!"); |
||||
} |
||||
$ret = []; |
||||
for ($i = 0; $i < $num_rows; $i++) { |
||||
$ret[] = $this->useDummyData($data); |
||||
} |
||||
return $ret; |
||||
} |
||||
|
||||
public function getDummyDataGenerator( |
||||
int $num_rows, |
||||
array $data |
||||
): \Generator { |
||||
for ($i = 0; $i < $num_rows; $i++) { |
||||
yield $this->useDummyData($data); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,347 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* @author Robert Strutts <Robert@TryingToScale.com> |
||||
* @copyright Copyright (c) 2022, Robert Strutts. |
||||
* @license MIT |
||||
*/ |
||||
|
||||
namespace IOcornerstone\Framework\Database; |
||||
|
||||
use IOcornerstone\Framework\{ |
||||
TimeZones, |
||||
Common, |
||||
}; |
||||
|
||||
class Model { |
||||
|
||||
use \IOCornerstone\Framework\Trait\Database\RunSql; |
||||
use \IOCornerstone\Framework\Trait\Database\Validation; |
||||
|
||||
const SUCCESSFUL_SAVE = 1; |
||||
const DUPLICATE_FOUND = 2; |
||||
const VALIDATION_ERROR = 3; |
||||
const PRE_SAVE_FAILED = 4; |
||||
const POST_SAVE_FAILED = 5; |
||||
|
||||
private $members = []; |
||||
private $validationMembers = []; |
||||
private $missing = []; |
||||
private $errorMessage; |
||||
private $primaryKey = 'id'; |
||||
private $dbSkiped = []; |
||||
|
||||
public function saved(bool $worked = true): array { |
||||
$time = TimeZones::convertTimeZone(array('format' => 'g:i a')); |
||||
return ['time' => $time, 'saved' => $worked]; |
||||
} |
||||
|
||||
/** |
||||
* JSON API inform AJAX that save failed |
||||
*/ |
||||
public function saveFailed($msg = 'Save Failed!'): array { |
||||
return ['saved' => false, 'msg' => $msg]; |
||||
} |
||||
|
||||
public function dumpTableFields(string $table) { |
||||
$fields = $this->get_fields($table); |
||||
$this->doDump($fields); |
||||
} |
||||
|
||||
public function dumpDiff(): bool { |
||||
$fields = $this->get_fields($this->table); |
||||
|
||||
$diff = array_diff($fields, array_keys($this->members)); |
||||
|
||||
if (($key = array_search('id', $diff)) !== false) { |
||||
unset($diff[$key]); // Who cares about IDs |
||||
} |
||||
|
||||
foreach($this->dbSkiped as $skip) { |
||||
unset($diff[$skip]); |
||||
} |
||||
|
||||
if (count($diff)) { |
||||
echo "Diff on fields:<br>" . PHP_EOL; |
||||
$this->doDump($diff); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private function doDump(array $data) { |
||||
echo "<pre style=\"border: 1px solid #000; overflow: auto; margin: 0.5em;\">"; |
||||
print_r($data); |
||||
echo '</pre>'; |
||||
} |
||||
|
||||
public function setPrimaryKeyName(string $key): void { |
||||
$this->primaryKey = $key; |
||||
} |
||||
|
||||
/** |
||||
* Do not use this one in production! AS anyone can override |
||||
* the DB security and Inject stuff into the DB via POST, etc... |
||||
*/ |
||||
public function autoSetMembers(array $globals = [], array $skip = ['route', 'm'], array $onlyThese = []): void { |
||||
if (isLive()) { |
||||
return; // Bail if LIVE |
||||
} |
||||
|
||||
foreach ($globals as $key => $data) { |
||||
if (count($skip) && in_array($key, $skip)) { |
||||
continue; |
||||
} |
||||
if (in_array($key, $onlyThese) || !count($onlyThese)) { |
||||
$this->members[$key] = (! empty($data)) ? $data : ""; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public function getMissing() { |
||||
return $this->missing; |
||||
} |
||||
|
||||
public function getMember(string $member) { |
||||
return $this->members[$member] ?? null; |
||||
} |
||||
|
||||
public function getMembers() { |
||||
return $this->members; |
||||
} |
||||
|
||||
public function setMember(string $member, string $data): void { |
||||
$this->members[$member] = $data; |
||||
} |
||||
|
||||
public function hasMember($member): bool { |
||||
return isset($this->members[$member]); |
||||
} |
||||
|
||||
public function getLastError(): string { |
||||
return $this->errorMessage; |
||||
} |
||||
|
||||
/** |
||||
* Set Member for Validation |
||||
* @param string $key |
||||
* @param array $a |
||||
*/ |
||||
public function setMemberForValidation(string $key, array $a): void { |
||||
$this->validationMembers[$key] = $a; |
||||
} |
||||
|
||||
/** |
||||
* Get Validation Member |
||||
* @param string $key |
||||
* @return array |
||||
*/ |
||||
public function getVaildationMember(string $key): array { |
||||
return $this->validationMembers[$key] ?? array(); |
||||
} |
||||
|
||||
/** |
||||
* Unset Validation Member |
||||
* @param string $key |
||||
*/ |
||||
public function clearValidationMember(string $key): void { |
||||
unset($this->validationMembers[$key]); |
||||
} |
||||
|
||||
private function cleanup($bind) { |
||||
if (!is_array($bind)) { |
||||
if (!empty($bind)) { |
||||
$bind = array($bind); |
||||
} else { |
||||
$bind = array(); |
||||
} |
||||
} |
||||
return $bind; |
||||
} |
||||
|
||||
public static function emptyGenerator(): \Generator { |
||||
yield from []; |
||||
} |
||||
|
||||
/** |
||||
* Please use this fetch_lazy instead of fetch_all!!! |
||||
* To AVOID running out of Memory!!!!!!!!!!!!!!!!!!!! |
||||
* @param \PDOStatement $stmt |
||||
* @return \Generator |
||||
*/ |
||||
public static function pdoFetchLazy(\PDOStatement $stmt): \Generator { |
||||
foreach($stmt as $record) { |
||||
yield $record; |
||||
} |
||||
} |
||||
|
||||
public static function isValid(array $data): bool { |
||||
$error_count = (isset($data['errors'])) ? count($data['errors']) : 0; |
||||
return ($error_count === 0); |
||||
} |
||||
|
||||
|
||||
public function load(int $id): bool{ |
||||
if (method_exists($this, 'pre_load')) { |
||||
$this->pre_load(); |
||||
} |
||||
|
||||
$sql = "SELECT * FROM {$this->table} WHERE {$this->primaryKey} = ? LIMIT 1"; |
||||
$query = $this->pdo->prepare($sql); |
||||
$query->execute(array($id)); |
||||
if ($query === false) { |
||||
return false; |
||||
} |
||||
$data = $query->fetch(\PDO::FETCH_ASSOC); |
||||
if ($data === false) { |
||||
return false; |
||||
} |
||||
$this->members = array_merge($this->members, $data); |
||||
|
||||
if (method_exists($this, 'post_load')) { |
||||
$this->post_load(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public function insert($table, $info) { |
||||
$fields = $this->filter($table, $info); |
||||
|
||||
if (strrpos($table, "`") === false) { |
||||
$table = "`{$table}`"; |
||||
} |
||||
|
||||
$sql = "INSERT INTO {$table} (" . implode(", ", $fields) . ") VALUES (:" . implode(", :", $fields) . ");"; |
||||
$bind = array(); |
||||
foreach ($fields as $field) { |
||||
$bind[":$field"] = $info[$field]; |
||||
} |
||||
return $this->run($sql, $bind); |
||||
} |
||||
|
||||
public function update($table, $info, $where, $bind = "") { |
||||
$bind = $this->cleanup($bind); |
||||
$fields = $this->filter($table, $info); |
||||
|
||||
if (strrpos($table, "`") === false) { |
||||
$table = "`{$table}`"; |
||||
} |
||||
|
||||
$sql = "UPDATE {$table} SET "; |
||||
$f = 0; |
||||
|
||||
foreach ($fields as $key => $value) { |
||||
if ($f > 0) { |
||||
$sql .= ", "; |
||||
} |
||||
$f++; |
||||
|
||||
$value = trim($value); |
||||
|
||||
if (strrpos($value, "`") === false) { |
||||
$cf = '`' . $value . '`'; |
||||
} else { |
||||
$cf = $value; |
||||
} |
||||
|
||||
$sql .= $cf . " = :update_" . $value; |
||||
$bind[":update_$value"] = $info[$value]; |
||||
} |
||||
|
||||
$sql .= " WHERE " . $where . ";"; |
||||
|
||||
return $this->run($sql, $bind); |
||||
} |
||||
|
||||
public static function makeDbTimeStamp(): string { |
||||
return TimeZones::convertTimeZone(['format' => 'database', 'timezone' => 'UTC']); |
||||
} |
||||
|
||||
/** |
||||
* Save |
||||
* |
||||
* @param object $lcoal_model Should be $this from the Model |
||||
* |
||||
* Insert if primary key not set |
||||
* Update if primary key set |
||||
*/ |
||||
public function save(bool $validate = true): int { |
||||
if (method_exists($this, 'preSave')) { |
||||
$preWasSuccessfull = $this->preSave(); |
||||
if (! $preWasSuccessfull) { |
||||
return self::PRE_SAVE_FAILED; |
||||
} |
||||
} |
||||
$name = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); // Get DB Driver |
||||
if ($name === 'mysql' && $validate) { |
||||
if (!$this->validateMysql()) { |
||||
return self::VALIDATION_ERROR; |
||||
} |
||||
} |
||||
|
||||
if ($this->hasMember('modified')) { |
||||
$this->setMember('modified', self::makeDbTimeStamp()); |
||||
} |
||||
|
||||
if (empty($this->members[$this->primaryKey])) { |
||||
if (method_exists($this, 'duplicateCheck')) { |
||||
$dup = $this->duplicateCheck(); |
||||
if ($dup) { |
||||
return self::DUPLICATE_FOUND; |
||||
} |
||||
} |
||||
|
||||
if ($this->hasMember('created')) { |
||||
$this->setMember('created', self::makeDbTimeStamp()); |
||||
} |
||||
|
||||
$this->members[$this->primaryKey] = $this->insert($this->table, $this->members); |
||||
} else { |
||||
$this->setMember("row_count", $this->update($this->table, $this->members, |
||||
"`{$this->primaryKey}` = :search_key", |
||||
array(':search_key' => $this->members[$this->primaryKey]) |
||||
)); |
||||
} |
||||
|
||||
if (method_exists($this, 'postSave')) { |
||||
$postSaveSuccessfull = $this->postSave(); |
||||
if (! $postSaveSuccessfull) { |
||||
return self::POST_SAVE_FAILED; |
||||
} |
||||
} |
||||
|
||||
return self::SUCCESSFUL_SAVE; |
||||
} |
||||
|
||||
/** |
||||
* This FN requires SSL connection to the database. |
||||
* So, the KEY does not get exposed!!!! |
||||
*/ |
||||
public function encodeMySQLusingAES(#[\SensitiveParameter] string $data, #[\SensitiveParameter] string $key, bool $bind = true) { |
||||
$safe_text = addslashes($data); |
||||
$safe_key = addslashes($key); |
||||
$parm = ($bind) ? ":{$safe_text}" : "'{$safe_text}'"; |
||||
$ret = "HEX(AES_ENCRYPT($parm},'{$safe_key}'))"; |
||||
Common::wipe($key); |
||||
Common::wipe($safe_key); |
||||
Common::wipe($data); |
||||
Common::wipe($safe_text); |
||||
Common::wipe($parm); |
||||
return $ret; |
||||
} |
||||
|
||||
/** |
||||
* This FN requires SSL connection to the database. |
||||
* So, the KEY does not get exposed!!!! |
||||
*/ |
||||
public function decodeMySQLusingAES(string $field_name, #[\SensitiveParameter] string $key, bool $add_as = false) { |
||||
$safe_field = addslashes($field_name); |
||||
$safe_key = addslashes($key); |
||||
$as = ($add_as === true) ? " AS `{$safe_field}`" : ""; |
||||
return "CAST(AES_DECRYPT(UNHEX(`{$safe_field}`),'{$safe_key}') AS char){$as}"; |
||||
} |
||||
|
||||
/* End Model */ |
||||
} |
||||
@ -0,0 +1,283 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* Modified from: |
||||
* @link https://code.tutsplus.com/tutorials/how-to-paginate-data-with-php--net-2928 |
||||
*/ |
||||
|
||||
namespace IOcornerstone\Framework\Database; |
||||
|
||||
class Paginate |
||||
{ |
||||
|
||||
private $_conn; |
||||
private int $_limit; |
||||
private int $_page; |
||||
private $_query; |
||||
private $_total; |
||||
private $_url; |
||||
private $_url_limit; |
||||
private $_url_page; |
||||
public $maxLimit = 500; |
||||
|
||||
/* |
||||
* Query needs to be string for MySQL and array for MonogDB |
||||
*/ |
||||
|
||||
public function __construct($conn, string|array $query, string $dbType = "mysql") |
||||
{ |
||||
$this->_conn = $conn; |
||||
$this->_query = $query; |
||||
|
||||
if ($dbType === "mysql") { |
||||
$rs = $this->_conn->query($this->_query); |
||||
$this->_total = $rs->rowCount(); |
||||
} |
||||
} |
||||
|
||||
private function setLimit(int $limit = 10): int |
||||
{ |
||||
if ($limit < 1) { |
||||
return 10; |
||||
} |
||||
return ($limit > $this->maxLimit) ? $this->maxLimit : $limit; |
||||
} |
||||
|
||||
private function setPage(int $page = 1): int |
||||
{ |
||||
return ($page < 1) ? 1 : $page; |
||||
} |
||||
|
||||
public function mongoGetData(int $limit = 10, int $page = 1, array $options = []) |
||||
{ |
||||
$this->_limit = $this->setLimit($limit); // Number of items per page |
||||
$this->_page = $this->setPage($page); // The current page number |
||||
|
||||
$skip = (($this->_page - 1) * $this->_limit); |
||||
|
||||
if ($this->_limit === 0) { |
||||
$db_options = $options; |
||||
} else { |
||||
$limits = ['limit' => $this->_limit, 'skip' => $skip]; |
||||
$db_options = array_merge($limits, $options); |
||||
} |
||||
|
||||
// NOTE _query is the WHERE condition as an array |
||||
$collection = $this->_conn; |
||||
$documents = $collection->find($this->_query, $db_options); |
||||
|
||||
// Calculate the total number of documents in the collection |
||||
$this->_total = $collection->countDocuments($this->_query); |
||||
|
||||
$result = new \stdClass(); |
||||
$result->page = $this->_page; |
||||
$result->limit = $this->_limit; |
||||
$result->total = $this->_total; |
||||
$result->data = $documents; |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
public function getData(int $limit = 10, int $page = 1) |
||||
{ |
||||
$this->_limit = $this->setLimit($limit); |
||||
$this->_page = $this->setPage($page); |
||||
|
||||
if ($this->_limit === 0) { |
||||
$query = $this->_query; |
||||
} else { |
||||
$query = $this->_query . " LIMIT " . (($this->_page - 1) * $this->_limit) . ", $this->_limit"; |
||||
} |
||||
$rs = $this->_conn->query($query); |
||||
|
||||
$result = new \stdClass(); |
||||
$result->page = $this->_page; |
||||
$result->limit = $this->_limit; |
||||
$result->total = $this->_total; |
||||
$result->rs = $rs; |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
public function useHashRoutes(string $url): void |
||||
{ |
||||
$this->_url = $url; |
||||
$this->_url_limit = "/"; |
||||
$this->_url_page = "/"; |
||||
} |
||||
|
||||
public function useGetRoutes(string $url = ""): void |
||||
{ |
||||
$this->_url = $url; |
||||
$this->_url_limit = "?limit="; |
||||
$this->_url_page = "&page="; |
||||
} |
||||
|
||||
private function do_href(int $limit, int $page): string |
||||
{ |
||||
return 'href="' . $this->_url . $this->_url_limit . $limit . $this->_url_page . $page . '"'; |
||||
} |
||||
|
||||
public function createLinks(int $links = 7, string $list_class = "ui pagination menu", string $item = "item"): string |
||||
{ |
||||
$last = ceil($this->_total / $this->_limit); |
||||
|
||||
if ($this->_limit === 0 || $last < 2) { |
||||
return ''; |
||||
} |
||||
|
||||
$start = (($this->_page - $links) > 0) ? $this->_page - $links : 1; |
||||
$end = (($this->_page + $links) < $last) ? $this->_page + $links : $last; |
||||
|
||||
$html = '<div class="' . $list_class . '">'; |
||||
|
||||
$class = ($this->_page == 1) ? "disabled" : ""; |
||||
$item = " " . $item; |
||||
|
||||
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $this->_page - 1) . '>«</a>'; |
||||
|
||||
if ($start > 1) { |
||||
$html .= '<a class="' . $item . '" ' . $this->do_href($this->_limit, 1) . '>1</a>'; |
||||
$html .= '<div class="disabled' . $item . '"><span>...</span></div>'; |
||||
} |
||||
|
||||
for ($i = $start; $i <= $end; $i++) { |
||||
$class = ($this->_page == $i) ? "active" : ""; |
||||
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $i) . '>' . $i . '</a>'; |
||||
} |
||||
|
||||
if ($end < $last) { |
||||
$html .= '<div class="disabled' . $item . '"><span>...</span></div>'; |
||||
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $last) . '>' . $last . '</a>'; |
||||
} |
||||
|
||||
$class = ($this->_page == $last) ? "disabled" : ""; |
||||
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $this->_page + 1) . '>»</a>'; |
||||
|
||||
$html .= '</div>'; |
||||
|
||||
return $html; |
||||
} |
||||
|
||||
public function createJumpMenuWithLinks(int $links = 7, string $label = "Jump to ", string $end_label = " page.", string $item = "item"): string |
||||
{ |
||||
if ($this->_limit === 0) { |
||||
return ''; |
||||
} |
||||
|
||||
$last = ceil($this->_total / $this->_limit); |
||||
|
||||
$start = (($this->_page - $links) > 0) ? $this->_page - $links : 1; |
||||
$end = (($this->_page + $links) < $last) ? $this->_page + $links : $last; |
||||
|
||||
// Prev. Page |
||||
$class = ($this->_page == 1) ? "disabled " : ""; |
||||
$item = " " . $item; |
||||
$href = ($this->_page == 1) ? "" : $this->do_href($this->_limit, $this->_page - 1); |
||||
$html .= '<a class="' . $class . $item . '" ' . $href . '>«</a>'; |
||||
|
||||
$html .= $this->createJumpMenu(); |
||||
|
||||
// Next Page |
||||
$class = ($this->_page == $last) ? "disabled " : ""; |
||||
$href = ($this->_page == $last) ? "" : $this->do_href($this->_limit, $this->_page + 1); |
||||
$html .= '<a class="' . $class . $item . '" ' . $href . '>»</a>'; |
||||
|
||||
return $html; |
||||
} |
||||
|
||||
public function createJumpMenu(string $label = "Jump to ", string $end_label = " page.", string $item = "item"): string |
||||
{ |
||||
$last = ceil($this->_total / $this->_limit); |
||||
$option = ''; |
||||
for ($i = 1; $i <= $last; $i++) { |
||||
$option .= ($i == $this->_page) ? "<option value=\"{$i}\" selected>Page {$i}</option>\n" : "<option value=\"{$i}\">Page {$i}</option>\n"; |
||||
} |
||||
return "<label>{$label}<select class=\"{$item}\" onchange=\"window.location='" . $this->_url . $this->_url_limit . $this->_limit . $this->_url_page . "'+this[this.selectedIndex].value;return false;\">" |
||||
. "{$option}</select>" |
||||
. "{$end_label}</label>\n"; |
||||
} |
||||
|
||||
public function createItemsPerPage(string $label = "Items ", string $end_label = " per page.", string $item = "item"): string |
||||
{ |
||||
$items = ''; |
||||
$ipp_array = array(3, 6, 12, 24, 50, 100); |
||||
$found = false; |
||||
foreach ($ipp_array as $ipp_opt) { |
||||
if ($ipp_opt == $this->_limit) { |
||||
$found = true; |
||||
} |
||||
$items .= ($ipp_opt == $this->_limit) ? "<option selected value=\"{$ipp_opt}\">{$ipp_opt}</option>\n" : "<option value=\"{$ipp_opt}\">{$ipp_opt}</option>\n"; |
||||
} |
||||
|
||||
if ($found === false) { |
||||
$items = "<option selected value=\"{$this->_limit}\">{$this->_limit}</option>\n" . $items; |
||||
} |
||||
|
||||
$my_page = str_replace("&", "?", $this->_url_page); |
||||
$my_limit = str_replace("?", "&", $this->_url_limit); |
||||
|
||||
return "<label>{$label}<select class=\"{$item}\" onchange=\"window.location='" . $my_page . "1" . $my_limit . "'+this[this.selectedIndex].value;return false;\">{$items}</select>" |
||||
. "{$end_label}</label>\n"; |
||||
} |
||||
|
||||
public function getCSS(): string |
||||
{ |
||||
return ".pagination a { |
||||
color: #333; |
||||
padding: 2px 20px; |
||||
line-height: 1; |
||||
font-size: 14px; |
||||
text-decoration: none; |
||||
border-radius: 6px; |
||||
border: 1px solid #ddd; |
||||
background: #fff; |
||||
box-shadow: 0 1px 3px rgba(0,0,0,.1); |
||||
transition: all .2s ease; |
||||
} |
||||
.pagination a:hover:not(.active) { |
||||
transform: translateY(-1px); |
||||
box-shadow: 0 2px 6px rgba(0,0,0,.15); |
||||
} |
||||
.pagination a.active { |
||||
background: #4CAF50; |
||||
color: white; |
||||
border-color: #4CAF50; |
||||
} |
||||
.pagination .disabled { |
||||
display: inline-block; |
||||
padding: 4px 12px; |
||||
color: #999; |
||||
border: 1px solid #ddd; |
||||
border-radius: 4px; |
||||
background: #f8f8f8; |
||||
cursor: not-allowed; |
||||
pointer-events: none; |
||||
opacity: 0.6; |
||||
} |
||||
div.pagination.menu { |
||||
padding-top: 10px; |
||||
}"; |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* mongo db |
||||
$limit = $_GET['limit'] ?? 18; |
||||
$page = $_GET['page'] ?? 1; |
||||
$url = "#pages/bill"; |
||||
$query = [ 'user_id' => (string) $user_id ]; |
||||
$mongo_options = [ 'projection' => [ 'billing' => 1 ]]; |
||||
|
||||
$pag = new Paginate($collection, $query, "mongodb"); |
||||
$r = $pag->mongoGetData($limit, $page, $mongo_options); |
||||
$pag->useHashRoutes($url); |
||||
|
||||
foreach ($r->data as $bill) { |
||||
echo $bill; |
||||
} |
||||
|
||||
echo $pag->createLinks(); |
||||
*/ |
||||
Loading…
Reference in new issue