File Manager

Current Directory: /home/astoriaah/www/old15/administrator/components/com_sh404sef/models
Viewing File: /home/astoriaah/www/old15/administrator/components/com_sh404sef/models/editurl.php
<?php /** * sh404SEF - SEO extension for Joomla! * * @author Yannick Gaultier * @copyright (c) Yannick Gaultier 2014 * @package sh404SEF * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @version 4.4.4.1791 * @date 2014-07-01 */ // Security check to ensure this file is being included by a parent file. if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.'); class Sh404sefModelEditurl extends Sh404sefClassBaseeditmodel { protected $_context = 'sh404sef.editurl'; protected $_defaultTable = 'urls'; protected $_url = null; /** * Create or update a record to * DB from POST data * * Overriden from base model * to also save metas and aliases * * @param array $dataArray an array holding data to save. If empty, $_POST is used * @return integer id of created or updated record */ public function save( $dataArray = null, $type = sh404SEF_URLTYPE_CUSTOM) { // use parent save method to save the url itself, from default values $this->_data = is_null( $dataArray) ? JRequest::get('post') : $dataArray; // save the non-sef/sef pair data $savedId = $this->_saveUrl( $type); //now save metas if( !empty($savedId)) { $savedId = $this->_saveMetas() ? $savedId : 0; } // now save aliases if( !empty($savedId)) { $savedId = $this->_saveAliases() ? $savedId : 0; } // return savedId of the url, will have // been set to 0 if something wrong happened // while saving either url, meta data or aliase return $savedId; } /** * Get a list of urls from their ids, * passed as params * * @param array of integer $ids the list of url id to fetch * @return array of objects as read from db */ public function getByIds( $ids = array()) { $urls = array(); if (empty($ids)) { return $urls; } try { $whereIds = ShlDbHelper::arrayToIntValList( $ids); $urls = ShlDbHelper::selectObjectList( $this->_getTableName(), '*', $this->_db->quoteName( 'id') . ' in (' . $whereIds . ')'); } catch (Exception $e) { ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage()); } // return result return $urls; } /** * Save an url (not aliases or metas) passed as param * * @param $url array holding the various fields of an url */ public function saveUrl( $url) { // use parent save method to save the url itself, from default values $this->_data = $url; $savedId = $this->_saveUrl(); // return savedId of the url, will have // been set to 0 if something wrong happened // while saving url return $savedId; } /** * Delete a list of urls from their ids, * passed as params * * @param array of integer $ids the list of url id to delete * @return boolean true if success */ public function deleteByIds( $ids = array()) { if (empty($ids)) { return false; } $status = true; // build a list of ids to read $whereIds = ShlDbHelper::arrayToIntValList( $ids); // Need to delete urls from db, from cache // and also make sure the ranking is correct for duplicates // so we must find the first duplicate (if any) for all // urls to delete, and set its rank to zero. // First find about duplicates $query = 'select r2.*' . ' from `#__sh404sef_urls` as r1' . ' join `#__sh404sef_urls` as r2' . ' on r1.`oldurl` = r2.`oldurl`' . ' where r1.' . $this->_db->quoteName( 'id') . ' in (' . $whereIds . ')'; $query .= ' and r2.' . $this->_db->quoteName( 'rank') . ' > 0'; $query .= ' order by `rank`'; // perform query try { $this->_db->setQuery( $query); $duplicates = $this->_db->loadObjectList(); // now delete urls from db and cache $rows = $this->_getNonSefUrls( $ids); if (!empty( $rows)) { Sh404sefHelperCache::removeURLFromCache($rows); } // finally, we can simply delete from db by ids ShlDbHelper::deleteIn( '#__sh404sef_urls', 'id', $ids); } catch (Exception $e) { ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage()); $this->setError( 'Internal database error ' . $e->getMessage()); $status = false; } // if successfull, set the new rank 0 duplicate if( $status && !empty($duplicates)) { // array to hold ids of urls that should be set to rank=0 $newMainUrls = array(); // temporary arrays, holding duplicates grouped by nonsef url $groupedDuplicates = array(); // group them by old url foreach($duplicates as $url) { $groupedDuplicates[md5($url->oldurl)][] = $url; } // now collect the first url of each group, it // will have the lowest rank of the bunch as the initial // db query was ordered by rank asc foreach( $groupedDuplicates as $urlGroup) { $newMainUrls[] = $urlGroup[0]->id; } // now we just set the rank column to 0 for the // selected urls, so as to make them the new main urls // build a list of ids to read try { ShlDbHelper::updateIn( '#__sh404sef_urls', array( 'rank' => 0), 'id', $newMainUrls, ShlDbHelper::INTEGER); } catch (Exception $e) { ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage()); $this->setError( 'Internal database error ' . $e->getMessage()); $status = false; } } return $status; } /** * Delete a list of urls from their ids, * passed as params * Also delete all duplicates * * @param array of integer $ids the list of url id to delete * @return boolean true if success */ public function deleteByIdsWithDuplicates( $ids = array()) { if (empty($ids)) { return true; } // build a list of ids to read $whereIds = ShlDbHelper::arrayToIntValList( $ids); // read urls and their duplicates $query = 'select r2.id' . ' from `#__sh404sef_urls` as r1' . ' join `#__sh404sef_urls` as r2' . ' on r1.`oldurl` = r2.`oldurl`' . ' where r1.' . $this->_db->quoteName( 'id') . ' in (' . $whereIds . ')'; try { // perform query $this->_db->setQuery( $query); $urlsIds = $this->_db->loadColumn(); // now delete urls from db and cache $rows = $this->_getNonSefUrls( $urlsIds); if (!empty( $rows)) { Sh404sefHelperCache::removeURLFromCache($rows); } // finally, we can simply delete from db by ids ShlDbHelper::deleteIn( '#__sh404sef_urls', 'id', $urlsIds); } catch (Exception $e) { ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage()); $this->setError( 'Internal database error # ' . $e->getMessage()); } return true; } /** * Save an url to the database, updating various elements * at the same time like ranking of duplicates * * @param integer $type force url type, used when saving a custom url */ private function _saveUrl( $type = sh404SEF_URLTYPE_AUTO) { // check for homepage handling if (!empty( $this->_data['newurl']) && ($this->_data['newurl'] == '/' || $this->_data['newurl'] == sh404SEF_HOMEPAGE_CODE)) { $this->_saveHomeUrl(); return sh404SEF_HOMEPAGE_CODE; } // check for importing urls : if importing, rank will already be set in // incoming data. If saving a url from the UI, rank is never set // as it is caculated upon saving the url $importing = isset( $this->_data['rank']); // get required tools jimport( 'joomla.database.table'); $row = JTable::getInstance( $this->_defaultTable, 'Sh404sefTable'); try { // now bind incoming data to table row if (!$row->bind( $this->_data)) { $this->setError( $row->getError()); return 0; } // pre-save checks if (!$row->check()) { $this->setError( $row->getError()); return 0; } // find if we are adding a custom or automatic url $urlType = $row->dateadd == '0000-00-00' ? sh404SEF_URLTYPE_AUTO : sh404SEF_URLTYPE_CUSTOM; // override with user supplied if (!empty( $type)) { $urlType = $type; } // adjust date added field if needed $dateString = date("Y-m-d"); if ($urlType == sh404SEF_URLTYPE_CUSTOM) { $row->dateadd = $dateString; } // if custom url, and no language string, let's add default one if ( ($urlType == sh404SEF_URLTYPE_CUSTOM) && !preg_match( '/(&|\?)lang=[a-zA-Z]{2,3}/iUu', $row->newurl)) { $shTemp = explode( '-', Sh404sefHelperLanguage::getDefaultLanguageTag()); $shLangTemp = $shTemp[0] ? $shTemp[0] : 'en'; $row->newurl .= '&lang='.$shLangTemp; } // normalize the non-sef url representation, sorting query parts alphabetically $row->newurl = Sh404sefHelperUrl::sortUrl($row->newurl); // retrieve previous values of sef and non sef urls $previousSefUrl = JRequest::getVar( 'previousSefUrl', null, 'POST'); $previousNonSefUrl = JRequest::getVar( 'previousNonSefUrl', null, 'POST'); // if both were set, and nothing has changed, then nothing to do if (!empty($previousSefUrl) && !empty( $previousNonSefUrl) && $previousNonSefUrl == $row->newurl && $previousSefUrl == $row->oldurl) { // nothing changed ! must be changing meta or aliases $this->_url = $row; return $row->id; } // search DB for urls pairs with same SEF url $query = 'SELECT * FROM #__sh404sef_urls WHERE binary oldurl = ' . $this->_db->Quote( $row->oldurl) . ' ORDER BY rank ASC'; $this->_db->setQuery($query); $dbUrlList = $this->_db->loadObjectList(); // do we have urls in the db with same SEF ? if (count($dbUrlList) > 0) { // yes we do // get config object $sefConfig = Sh404sefFactory::getConfig(); if (!$sefConfig->shRecordDuplicates) { // we don't allow duplicates : reject this URL $this->setError( JText::_('COM_SH404SEF_DUPLICATE_NOT_ALLOWED')); } else { // same SEF, but we allow duplicates $existingRecord = null; // importing meta data for instance foreach ($dbUrlList as $urlInDB) { // same SEF, but is the incoming non-sef in this list of URl with same SEF ? if ($urlInDB->newurl == $row->newurl) { $existingRecord = $urlInDB; $this->setError( JText::_('COM_SH404SEF_URLEXIST')); } } if (empty( $existingRecord)) { // this new non-sef does not already exists $shTemp = array('nonSefURL' => $row->newurl); // which means we must update the record for the old non-sef url Sh404sefHelperCache::removeURLFromCache( $shTemp); // remove the old url from cache // then find new rank (as we are adding a duplicate, we add it at the end of the duplicate list) // but only if not importing. When importing, rank is already set if (!$importing) { $row->rank = $dbUrlList[count($dbUrlList)-1]->rank+1; } // store will create a new record if id=0, or update existing if id non 0 $row->store(); // put custom URL in DB and cache Sh404sefHelperCache::addSefUrlToCache( $row->newurl, $row->oldurl, $urlType); // we must add the previous SEF url to the alias list, only if // - not already there // - this sef url does not already exists in the DB; which will happen if the url // being saved was customized and also had duplicates // TODO this code is duplicated just a few line below, need refactoring if (!empty($previousSefUrl) && strpos($this->_data['shAliasList'], $previousSefUrl) === false) { // check if not already a valid SEF url in the DB $query = 'SELECT count(id) FROM #__sh404sef_urls WHERE binary oldurl = ' . $this->_db->Quote( $previousSefUrl); $this->_db->setQuery($query); $isThere = $this->_db->loadResult(); if (empty( $isThere)) { $this->_data['shAliasList'] .= $previousSefUrl. "\n"; } } } else { // there is already a record with both this sef and non sef. // just do nothing but return success (ie: record id). // Later, controller may store new aliases or metas // This should never happen when saving regular data as we added // a check for this case earlier // May happen when importing though $this->_url = $row; return $row->id; } // additional step : if we are here, it may be because we have modified // an existing url, and specifically changed it sef value to something else // Now it may be that this record was the one with rank = 0 in a series // of duplicate urls. If so, the urls which was ranked above must now become // the main url, having rank = 0 // note : when importing, we don't enter this test as previousSefUrl is empty // TODO this code is duplicated just a few line below, need refactoring if (!empty( $previousSefUrl) && $previousSefUrl != $row->newurl) { // search for the old #2 record in duplicate list $query = 'SELECT id FROM #__sh404sef_urls WHERE binary oldurl = ' . $this->_db->Quote( $previousSefUrl) . ' ORDER BY rank ASC'; $this->_db->setQuery($query); $previousRanked2 = $this->_db->loadObject(); // there was more than one duplicate in the same series, promote #2 to top spot if (!empty($previousRanked2)) { $query = 'UPDATE #__sh404sef_urls SET rank="0" WHERE id = '. $this->_db->Quote( $previousRanked2->id); $this->_db->setQuery($query); $this->_db->execute(); } } } } else { // there is no URL with same SEF URL, we are customizing an existing SEF url $shTemp = array('nonSefURL' => $row->newurl); Sh404sefHelperCache::removeURLFromCache( $shTemp); // remove it from cache // simply store URL. If there is already one with same non-sef, this will raise an error in store() // as we don't allow creating a custom url for an already existing non-sef. User should // directly edit the existing non-sef/sef pair if (!$row->check()) { $this->setError( $row->getError()); return 0; } if (!$row->store()) { $this->setError( $row->getError()); return 0; } // add also to cache if saved to db Sh404sefHelperCache::addSefUrlToCache( $row->newurl, $row->oldurl, $urlType); // we must add the previous SEF url to the alias list, only if // - not already there // - this sef url does not already exists in the DB; which will happen if the url // begin saved was customized and also had duplicates // note : when importing, we don't enter this test as previousSefUrl is empty if (!empty($previousSefUrl) && strpos($this->_data['shAliasList'], $previousSefUrl) === false) { // check if not already a valid SEF url in the DB $query = 'SELECT count(id) FROM #__sh404sef_urls WHERE binary oldurl = ' . $this->_db->Quote( $previousSefUrl); $this->_db->setQuery($query); $isThere = $this->_db->loadResult(); if (empty( $isThere)) { $this->_data['shAliasList'] .= $previousSefUrl. "\n"; } } // finally, also check db for urls with same sef as previous SEF if any. We need // to search for the first duplicate of this old sef, and set it to be // the new main url // note : when importing, we don't enter this test as previousSefUrl is empty if (!empty( $previousSefUrl) && $previousSefUrl != $row->newurl) { // search for the old #2 record in duplicate list $query = 'SELECT id FROM #__sh404sef_urls WHERE binary oldurl = ' . $this->_db->Quote( $previousSefUrl) . ' ORDER BY rank ASC'; $this->_db->setQuery($query); $previousRanked2 = $this->_db->loadObject(); // there was more than one duplicate in the same series, promote #2 to top spot if (!empty($previousRanked2)) { ShlDbHelper::update( '#__sh404sef_urls', array( 'rank' => 0), array( 'id' => $previousRanked2->id)); } } } // store saved url object $this->_url = $row; // return what should be a non-zero id return $this->_url->id; } catch (Exception $e) { ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage()); $this->setError( $e->getMessage()); return 0; } } private function _saveHomeUrl() { // get required tools jimport( 'joomla.database.table'); $url = JTable::getInstance( $this->_defaultTable, 'Sh404sefTable'); // build a fake url record $url->newurl = sh404SEF_HOMEPAGE_CODE; // store it for future usage when saving meta and aliases $this->_url = $url; } private function _saveMetas() { // get a meta model object $model = ShlMvcModel_Base::getInstance( 'metas', 'Sh404sefModel'); // buil an array with metas input $this->_data['newurl'] = is_object( $this->_url) ? $this->_url->newurl : $this->_data['newurl']; $this->_data['id'] = $this->_data['meta_id']; // ask model to save the data $status = $model->save( $this->_data); if (!$status) { $this->setError( $model->getError()); } return $status; } /** * Save aliases entered by user to the db * overwriting existing ones * */ private function _saveAliases() { if(!isset($this->_data['shAliasList'])) { return true; } // get an aliases model object $model = ShlMvcModel_Base::getInstance( 'aliases', 'Sh404sefModel'); // ask it to save the data $newUrl = is_object( $this->_url) ? $this->_url->newurl : ''; $status = $model->saveFromInput( $this->_data['shAliasList'], $newUrl); if (!$status) { $this->setError( $model->getError()); } return $status; } /** * Read urls from db and returns an array * of non-sef urls, as needed currently * by the cache class for deletion operation * * @param array of integer $ids */ private function _getNonSefUrls( $ids) { $nonSefUrls = array(); $rawUrls = $this->getByIds( $ids); if (!empty( $rawUrls)) { foreach( $rawUrls as $url) { $nonSefUrls[] = $url->newurl; } } return $nonSefUrls; } /** * Returns the default full table name on * which this model operates */ protected function _getTableName() { return '#__sh404sef_urls'; } }