Merge remote-tracking branch 'origin/sql_hash_lastUpdate' into dev

This commit is contained in:
Alexandre Alapetite
2015-04-04 22:40:05 +02:00
8 changed files with 233 additions and 103 deletions

View File

@@ -145,7 +145,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Call the extension hook
$name = $feed->name();
$feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed);
if (is_null($feed)) {
if ($feed === null) {
Minz_Request::bad(_t('feed_not_added', $name), $url_redirect);
}
@@ -181,7 +181,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Use a shared statement and a transaction to improve a LOT the
// performances.
$prepared_statement = $entryDAO->addEntryPrepare();
$feedDAO->beginTransaction();
foreach ($entries as $entry) {
// Entries are added without any verification.
@@ -190,13 +189,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$entry->_isRead($is_read);
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
if (is_null($entry)) {
if ($entry === null) {
// An extension has returned a null value, there is nothing to insert.
continue;
}
$values = $entry->toArray();
$entryDAO->addEntry($values, $prepared_statement);
$entryDAO->addEntry($values);
}
$feedDAO->updateLastUpdate($feed->id());
$feedDAO->commit();
@@ -307,7 +306,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$feed->load(false);
} catch (FreshRSS_Feed_Exception $e) {
Minz_Log::notice($e->getMessage());
$feedDAO->updateLastUpdate($feed->id(), 1);
$feedDAO->updateLastUpdate($feed->id(), true);
$feed->unlock();
continue;
}
@@ -323,50 +322,69 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// We want chronological order and SimplePie uses reverse order.
$entries = array_reverse($feed->entries());
if (count($entries) > 0) {
// For this feed, check last n entry GUIDs already in database.
$existing_guids = array_fill_keys($entryDAO->listLastGuidsByFeed(
$feed->id(), count($entries) + 10
), 1);
$use_declared_date = empty($existing_guids);
$newGuids = array();
foreach ($entries as $entry) {
$newGuids[] = $entry->guid();
}
// For this feed, check existing GUIDs already in database.
$existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids);
unset($newGuids);
$use_declared_date = empty($existingHashForGuids);
$oldGuids = array();
// Add entries in database if possible.
$prepared_statement = $entryDAO->addEntryPrepare();
$feedDAO->beginTransaction();
foreach ($entries as $entry) {
$entry_date = $entry->date(true);
if (isset($existing_guids[$entry->guid()]) ||
($feed_history == 0 && $entry_date < $date_min)) {
// This entry already exists in DB or should not be added
// considering configuration and date.
continue;
if (isset($existingHashForGuids[$entry->guid()])) {
$existingHash = $existingHashForGuids[$entry->guid()];
if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') {
//This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3
$oldGuids[] = $entry->guid();
} else { //This entry already exists but has been updated
Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() .
', old hash ' . $existingHash . ', new hash ' . $entry->hash());
$entry->_isRead($is_read); //Reset is_read
if (!$entryDAO->hasTransaction()) {
$entryDAO->beginTransaction();
}
$entryDAO->updateEntry($entry->toArray());
}
} elseif ($feed_history == 0 && $entry_date < $date_min) {
// This entry should not be added considering configuration and date.
$oldGuids[] = $entry->guid();
} else {
$id = uTimeString();
if ($use_declared_date || $entry_date < $date_min) {
// Use declared date at first import.
$id = min(time(), $entry_date) . uSecString();
}
$entry->_id($id);
$entry->_isRead($is_read);
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
if ($entry === null) {
// An extension has returned a null value, there is nothing to insert.
continue;
}
if (!$entryDAO->hasTransaction()) {
$entryDAO->beginTransaction();
}
$entryDAO->addEntry($entry->toArray());
}
$id = uTimeString();
if ($use_declared_date || $entry_date < $date_min) {
// Use declared date at first import.
$id = min(time(), $entry_date) . uSecString();
}
$entry->_id($id);
$entry->_isRead($is_read);
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
if (is_null($entry)) {
// An extension has returned a null value, there is nothing to insert.
continue;
}
$values = $entry->toArray();
$entryDAO->addEntry($values, $prepared_statement);
}
$entryDAO->updateLastSeen($feed->id(), $oldGuids);
}
//TODO: updateLastSeen old GUIDS once in a while, in the case of caching (i.e. the whole feed content has not changed)
if ($feed_history >= 0 && rand(0, 30) === 1) {
// TODO: move this function in web cron when available (see entry::purge)
// Remove old entries once in 30.
if (!$feedDAO->hasTransaction()) {
$feedDAO->beginTransaction();
if (!$entryDAO->hasTransaction()) {
$entryDAO->beginTransaction();
}
//TODO: more robust system based on entry.lastSeen to avoid cleaning entries that are still published in the RSS feed.
$nb = $feedDAO->cleanOldEntries($feed->id(),
$date_min,
@@ -377,9 +395,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
}
}
$feedDAO->updateLastUpdate($feed->id(), 0, $feedDAO->hasTransaction());
if ($feedDAO->hasTransaction()) {
$feedDAO->commit();
$feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->hasTransaction());
if ($entryDAO->hasTransaction()) {
$entryDAO->commit();
}
if ($feed->url() !== $url) {

View File

@@ -361,7 +361,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
}
// Then, articles are imported.
$prepared_statement = $this->entryDAO->addEntryPrepare();
$this->entryDAO->beginTransaction();
foreach ($article_object['items'] as $item) {
if (!isset($article_to_feed[$item['id']])) {
@@ -396,7 +395,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
}
$values = $entry->toArray();
$id = $this->entryDAO->addEntry($values, $prepared_statement);
$id = $this->entryDAO->addEntry($values);
if (!$error && ($id === false)) {
$error = true;

View File

@@ -14,6 +14,7 @@ class FreshRSS_Entry extends Minz_Model {
private $content;
private $link;
private $date;
private $hash = null;
private $is_read;
private $is_favorite;
private $feed;
@@ -88,6 +89,14 @@ class FreshRSS_Entry extends Minz_Model {
}
}
public function hash() {
if ($this->hash === null) {
//Do not include $this->date because it may be automatically generated when lacking
$this->hash = md5($this->link . $this->title . $this->author . $this->content . $this->tags(true));
}
return $this->hash;
}
public function _id($value) {
$this->id = $value;
}
@@ -95,18 +104,23 @@ class FreshRSS_Entry extends Minz_Model {
$this->guid = $value;
}
public function _title($value) {
$this->hash = null;
$this->title = $value;
}
public function _author($value) {
$this->hash = null;
$this->author = $value;
}
public function _content($value) {
$this->hash = null;
$this->content = $value;
}
public function _link($value) {
$this->hash = null;
$this->link = $value;
}
public function _date($value) {
$this->hash = null;
$value = intval($value);
$this->date = $value > 1 ? $value : time();
}
@@ -120,6 +134,7 @@ class FreshRSS_Entry extends Minz_Model {
$this->feed = $value;
}
public function _tags($value) {
$this->hash = null;
if (!is_array($value)) {
$value = array($value);
}
@@ -182,6 +197,7 @@ class FreshRSS_Entry extends Minz_Model {
'content' => $this->content(),
'link' => $this->link(),
'date' => $this->date(true),
'hash' => $this->hash(),
'is_read' => $this->isRead(),
'is_favorite' => $this->isFavorite(),
'id_feed' => $this->feed(),

View File

@@ -6,20 +6,57 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return parent::$sharedDbType !== 'sqlite';
}
public function addEntryPrepare() {
$sql = 'INSERT INTO `' . $this->prefix . 'entry`(id, guid, title, author, '
. ($this->isCompressed() ? 'content_bin' : 'content')
. ', link, date, is_read, is_favorite, id_feed, tags) '
. 'VALUES(?, ?, ?, ?, '
. ($this->isCompressed() ? 'COMPRESS(?)' : '?')
. ', ?, ?, ?, ?, ?, ?)';
return $this->bd->prepare($sql);
protected function autoAddColumn($errorInfo) {
if (isset($errorInfo[0])) {
if ($errorInfo[0] == '42S22') { //ER_BAD_FIELD_ERROR
$hasTransaction = false;
try {
$stm = null;
if (stripos($errorInfo[2], 'lastSeen') !== false) { //v1.2
if (!$this->bd->inTransaction()) {
$this->bd->beginTransaction();
$hasTransaction = true;
}
$stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN lastSeen INT(11) NOT NULL');
if ($stm && $stm->execute()) {
$stm = $this->bd->prepare('CREATE INDEX entry_lastSeen_index ON `' . $this->prefix . 'entry`(`lastSeen`);'); //"IF NOT EXISTS" does not exist in MySQL 5.7
if ($stm && $stm->execute()) {
if ($hasTransaction) {
$this->bd->commit();
}
return true;
}
}
if ($hasTransaction) {
$this->bd->rollBack();
}
} elseif (stripos($errorInfo[2], 'hash') !== false) { //v1.2
$stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN hash BINARY(16) NOT NULL');
return $stm && $stm->execute();
}
} catch (Exception $e) {
Minz_Log::debug('FreshRSS_EntryDAO::autoAddColumn error: ' . $e->getMessage());
if ($hasTransaction) {
$this->bd->rollBack();
}
}
}
}
return false;
}
public function addEntry($valuesTmp, $preparedStatement = null) {
$stm = $preparedStatement === null ?
FreshRSS_EntryDAO::addEntryPrepare() :
$preparedStatement;
private $addEntryPrepared = null;
public function addEntry($valuesTmp) {
if ($this->addEntryPrepared === null) {
$sql = 'INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, '
. ($this->isCompressed() ? 'content_bin' : 'content')
. ', link, date, lastSeen, hash, is_read, is_favorite, id_feed, tags) '
. 'VALUES(?, ?, ?, ?, '
. ($this->isCompressed() ? 'COMPRESS(?)' : '?')
. ', ?, ?, ?, X?, ?, ?, ?, ?)';
$this->addEntryPrepared = $this->bd->prepare($sql);
}
$values = array(
$valuesTmp['id'],
@@ -29,55 +66,65 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$valuesTmp['content'],
substr($valuesTmp['link'], 0, 1023),
$valuesTmp['date'],
time(),
$valuesTmp['hash'],
$valuesTmp['is_read'] ? 1 : 0,
$valuesTmp['is_favorite'] ? 1 : 0,
$valuesTmp['id_feed'],
substr($valuesTmp['tags'], 0, 1023),
);
if ($stm && $stm->execute($values)) {
if ($this->addEntryPrepared && $this->addEntryPrepared->execute($values)) {
return $this->bd->lastInsertId();
} else {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries
$info = $this->addEntryPrepared == null ? array(2 => 'syntax error') : $this->addEntryPrepared->errorInfo();
if ($this->autoAddColumn($info)) {
return $this->addEntry($valuesTmp);
} elseif ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries
Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']);
} /*else {
Minz_Log::debug('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']);
}*/
}
return false;
}
}
public function addEntryObject($entry, $conf, $feedHistory) {
$existingGuids = array_fill_keys(
$this->listLastGuidsByFeed($entry->feed(), 20), 1
private $updateEntryPrepared = null;
public function updateEntry($valuesTmp) {
if ($this->updateEntryPrepared === null) {
$sql = 'UPDATE `' . $this->prefix . 'entry` '
. 'SET title=?, author=?, '
. ($this->isCompressed() ? 'content_bin=COMPRESS(?)' : 'content=?')
. ', link=?, date=?, lastSeen=?, hash=X?, is_read=?, tags=? '
. 'WHERE id_feed=? AND guid=?';
$this->updateEntryPrepared = $this->bd->prepare($sql);
}
$values = array(
substr($valuesTmp['title'], 0, 255),
substr($valuesTmp['author'], 0, 255),
$valuesTmp['content'],
substr($valuesTmp['link'], 0, 1023),
$valuesTmp['date'],
time(),
$valuesTmp['hash'],
$valuesTmp['is_read'] ? 1 : 0,
substr($valuesTmp['tags'], 0, 1023),
$valuesTmp['id_feed'],
substr($valuesTmp['guid'], 0, 760),
);
$nb_month_old = max($conf->old_entries, 1);
$date_min = time() - (3600 * 24 * 30 * $nb_month_old);
$eDate = $entry->date(true);
if ($feedHistory == -2) {
$feedHistory = $conf->keep_history_default;
if ($this->updateEntryPrepared && $this->updateEntryPrepared->execute($values)) {
return $this->bd->lastInsertId();
} else {
$info = $this->updateEntryPrepared == null ? array(2 => 'syntax error') : $this->updateEntryPrepared->errorInfo();
if ($this->autoAddColumn($info)) {
return $this->updateEntry($valuesTmp);
}
Minz_Log::error('SQL error updateEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while updating entry with GUID ' . $valuesTmp['guid'] . ' in feed ' . $valuesTmp['id_feed']);
return false;
}
if (!isset($existingGuids[$entry->guid()]) &&
($feedHistory != 0 || $eDate >= $date_min || $entry->isFavorite())) {
$values = $entry->toArray();
$useDeclaredDate = empty($existingGuids);
$values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
min(time(), $eDate) . uSecString() :
uTimeString();
return $this->addEntry($values);
}
// We don't return Entry object to avoid a research in DB
return -1;
}
/**
@@ -94,6 +141,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if (!is_array($ids)) {
$ids = array($ids);
}
if (count($ids) < 1) {
return 0;
}
$sql = 'UPDATE `' . $this->prefix . 'entry` '
. 'SET is_favorite=? '
. 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)';
@@ -296,11 +346,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
*
* If $idMax equals 0, a deprecated debug message is logged
*
* @param integer $id feed ID
* @param integer $id_feed feed ID
* @param integer $idMax fail safe article ID
* @return integer affected rows
*/
public function markReadFeed($id, $idMax = 0) {
public function markReadFeed($id_feed, $idMax = 0) {
if ($idMax == 0) {
$idMax = time() . '000000';
Minz_Log::debug('Calling markReadFeed(0) is deprecated!');
@@ -310,7 +360,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$sql = 'UPDATE `' . $this->prefix . 'entry` '
. 'SET is_read=1 '
. 'WHERE id_feed=? AND is_read=0 AND id <= ?';
$values = array($id, $idMax);
$values = array($id_feed, $idMax);
$stm = $this->bd->prepare($sql);
if (!($stm && $stm->execute($values))) {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
@@ -324,7 +374,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$sql = 'UPDATE `' . $this->prefix . 'feed` '
. 'SET cache_nbUnreads=cache_nbUnreads-' . $affected
. ' WHERE id=?';
$values = array($id);
$values = array($id_feed);
$stm = $this->bd->prepare($sql);
if (!($stm && $stm->execute($values))) {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
@@ -338,7 +388,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return $affected;
}
public function searchByGuid($feed_id, $id) {
public function searchByGuid($id_feed, $guid) {
// un guid est unique pour un flux donné
$sql = 'SELECT id, guid, title, author, '
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
@@ -347,8 +397,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$stm = $this->bd->prepare($sql);
$values = array(
$feed_id,
$id
$id_feed,
$guid,
);
$stm->execute($values);
@@ -519,12 +569,52 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
}
public function listLastGuidsByFeed($id, $n) {
$sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n);
public function listHashForFeedGuids($id_feed, $guids) {
if (count($guids) < 1) {
return array();
}
$sql = 'SELECT guid, hex(hash) AS hexHash FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
$stm = $this->bd->prepare($sql);
$values = array($id);
$stm->execute($values);
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
$values = array($id_feed);
$values = array_merge($values, $guids);
if ($stm && $stm->execute($values)) {
$result = array();
$rows = $stm->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$result[$row['guid']] = $row['hexHash'];
}
return $result;
} else {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
if ($this->autoAddColumn($info)) {
return $this->listHashForFeedGuids($id_feed, $guids);
}
Minz_Log::error('SQL error listHashForFeedGuids: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while querying feed ' . $id_feed);
return false;
}
}
public function updateLastSeen($id_feed, $guids) {
if (count($guids) < 1) {
return 0;
}
$sql = 'UPDATE `' . $this->prefix . 'entry` SET lastSeen=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
$stm = $this->bd->prepare($sql);
$values = array(time(), $id_feed);
$values = array_merge($values, $guids);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
if ($this->autoAddColumn($info)) {
return $this->updateLastSeen($id_feed, $guids);
}
Minz_Log::error('SQL error updateLastSeen: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while updating feed ' . $id_feed);
return false;
}
}
public function countUnreadRead() {

View File

@@ -255,6 +255,7 @@ class FreshRSS_Feed extends Minz_Model {
$feed->__destruct(); //http://simplepie.org/wiki/faq/i_m_getting_memory_leaks
unset($feed);
//TODO: Return a different information in case of cache/no-cache, and give access to the GUIDs in case of cache
}
}
}

View File

@@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` (
`name` varchar(255) NOT NULL,
`website` varchar(255) CHARACTER SET latin1,
`description` text,
`lastUpdate` int(11) DEFAULT 0,
`lastUpdate` int(11) DEFAULT 0, -- Until year 2038
`priority` tinyint(2) NOT NULL DEFAULT 10,
`pathEntries` varchar(511) DEFAULT NULL,
`httpAuth` varchar(511) DEFAULT NULL,
@@ -40,7 +40,9 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
`author` varchar(255),
`content_bin` blob, -- v0.7
`link` varchar(1023) CHARACTER SET latin1 NOT NULL,
`date` int(11),
`date` int(11), -- Until year 2038
`lastSeen` INT(11) NOT NULL, -- v1.2, Until year 2038
`hash` BINARY(16), -- v1.2
`is_read` boolean NOT NULL DEFAULT 0,
`is_favorite` boolean NOT NULL DEFAULT 0,
`id_feed` SMALLINT, -- v0.7
@@ -50,6 +52,7 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
UNIQUE KEY (`id_feed`,`guid`), -- v0.7
INDEX (`is_favorite`), -- v0.7
INDEX (`is_read`) -- v0.7
INDEX entry_lastSeen_index (`lastSeen`) -- v1.2
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci
ENGINE = INNODB;

View File

@@ -14,7 +14,7 @@ $SQL_CREATE_TABLES = array(
`name` varchar(255) NOT NULL,
`website` varchar(255),
`description` text,
`lastUpdate` int(11) DEFAULT 0,
`lastUpdate` int(11) DEFAULT 0, -- Until year 2038
`priority` tinyint(2) NOT NULL DEFAULT 10,
`pathEntries` varchar(511) DEFAULT NULL,
`httpAuth` varchar(511) DEFAULT NULL,
@@ -38,7 +38,9 @@ $SQL_CREATE_TABLES = array(
`author` varchar(255),
`content` text,
`link` varchar(1023) NOT NULL,
`date` int(11),
`date` int(11), -- Until year 2038
`lastSeen` INT(11) NOT NULL, -- v1.2, Until year 2038
`hash` BINARY(16), -- v1.2
`is_read` boolean NOT NULL DEFAULT 0,
`is_favorite` boolean NOT NULL DEFAULT 0,
`id_feed` SMALLINT,
@@ -50,6 +52,7 @@ $SQL_CREATE_TABLES = array(
'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `%1$sentry`(`is_favorite`);',
'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `%1$sentry`(`is_read`);',
'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `%1$sentry`(`lastSeen`);', //v1.2
'INSERT OR IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");',
);

View File

@@ -38,7 +38,7 @@ function classAutoloader($class) {
include(APP_PATH . '/Models/' . $components[1] . '.php');
return;
case 3: //Controllers, Exceptions
@include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php');
include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php');
return;
}
} elseif (strpos($class, 'Minz') === 0) {