├── README.markdown ├── configuration-dist.php ├── sql └── assets.sql └── assetfix.php /README.markdown: -------------------------------------------------------------------------------- 1 | AssetFix 2 | ======== 3 | 4 | AssetFix is a CLI script that rewrite your #__assets table preventing errors and slow speed of load caused by bad migrations or 5 | end user manual manipulation of the tables. This scripts try to offer a way to solve that problem. 6 | 7 | Installation 8 | ------------ 9 | 10 | Get the source code from GIT: 11 | 12 | git clone git@github.com:fastslack/AssetFix.git 13 | 14 | Usage 15 | ------------ 16 | 17 | git clone git@github.com:fastslack/AssetFix.git 18 | git clone git@github.com:joomla/joomla-platform.git 19 | cd joomla-platform 20 | git checkout -b 11.4 tags/11.4 21 | cd ../AssetFix 22 | cp configuration-dist.php configuration.php 23 | vim configuration (edit the preferences with your database credentials) 24 | php assetfix.php 25 | 26 | -------------------------------------------------------------------------------- /configuration-dist.php: -------------------------------------------------------------------------------- 1 | JPATH_BASE.'/assetfix.log.php' 59 | ) 60 | ); 61 | 62 | // System configuration. 63 | $config = JFactory::getConfig(); 64 | 65 | // Note, this will throw an exception if there is an error 66 | // Creating the database connection. 67 | $this->dbo = JDatabase::getInstance( 68 | array( 69 | 'driver' => $config->get('dbtype'), 70 | 'host' => $config->get('host'), 71 | 'user' => $config->get('user'), 72 | 'password' => $config->get('password'), 73 | 'database' => $config->get('db'), 74 | 'prefix' => $config->get('dbprefix'), 75 | ) 76 | ); 77 | } 78 | 79 | protected function doExecute() 80 | { 81 | // Backup the tables to modify 82 | $tables = array('#__assets', '#__categories', '#__content'); 83 | $this->doBackup($tables); 84 | 85 | // Cleanup the asset table 86 | $this->populateDatabase('./sql/assets.sql'); 87 | 88 | // Fixing the extensions assets 89 | $this->fixExtensionsAssets(); 90 | 91 | // Fixing the categories assets 92 | $this->fixCategoryAssets(); 93 | 94 | // Fixing the content assets 95 | $this->fixContentAssets(); 96 | } 97 | 98 | /** 99 | * Backup tables 100 | * 101 | * @param array $tables Array with the tables to backup 102 | * @return boolean 103 | * @since 2.5.0 104 | * @throws Exception 105 | */ 106 | protected function doBackup($tables) { 107 | 108 | // Rename the tables 109 | $count = count($tables); 110 | 111 | for($i=0;$i<$count;$i++) { 112 | 113 | $table = $tables[$i]; 114 | $rename = $tables[$i]."_backup"; 115 | 116 | $exists = $this->_existsTable($rename); 117 | 118 | if ($exists == 0) { 119 | $this->_copyTable($table, $rename); 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * Copy table to old site to new site 126 | * 127 | * @return boolean 128 | * @since 1.1.0 129 | * @throws Exception 130 | */ 131 | protected function _copyTable($from, $to=null) { 132 | 133 | // System configuration. 134 | $config = JFactory::getConfig(); 135 | $database = $config->get('db'); 136 | 137 | if (!$to) $to = $from; 138 | $from = preg_replace ('/#__/', $this->dbo->getPrefix(), $from); 139 | $to = preg_replace ('/#__/', $this->dbo->getPrefix(), $to); 140 | 141 | $success = $this->_cloneTable($from, $to); 142 | if ($success) { 143 | $query = "INSERT INTO {$to} SELECT * FROM {$from}"; 144 | $this->dbo->setQuery($query); 145 | $this->dbo->query(); 146 | 147 | // Check for query error. 148 | $error = $this->dbo->getErrorMsg(); 149 | if ($error) { 150 | throw new Exception($error); 151 | } 152 | $success = true; 153 | } 154 | 155 | return $success; 156 | } 157 | 158 | /** 159 | * Clone table structure from old site to new site 160 | * 161 | * @return boolean 162 | * @since 1.1.0 163 | * @throws Exception 164 | */ 165 | protected function _cloneTable($from, $to=null, $drop=true) { 166 | // System configuration. 167 | $config = JFactory::getConfig(); 168 | $database = $config->get('db'); 169 | 170 | if (!$to) $to = $from; 171 | $from = preg_replace ('/#__/', $this->dbo->getPrefix(), $from); 172 | $to = preg_replace ('/#__/', $this->dbo->getPrefix(), $to); 173 | 174 | $exists = $this->_existsTable($from); 175 | 176 | if($exists == 0) { 177 | $success = false; 178 | } else { 179 | $query = "CREATE TABLE {$to} LIKE {$from}"; 180 | $this->dbo->setQuery($query); 181 | $this->dbo->query(); 182 | 183 | // Check for query error. 184 | $error = $this->dbo->getErrorMsg(); 185 | 186 | if ($error) { 187 | throw new Exception($error); 188 | } 189 | $success = true; 190 | } 191 | 192 | return $success; 193 | } 194 | 195 | /** 196 | * existsTable 197 | * 198 | * @return boolean 199 | * @since 1.1.0 200 | * @throws Exception 201 | */ 202 | function _existsTable($table) 203 | { 204 | // System configuration. 205 | $config = JFactory::getConfig(); 206 | $database = $config->get('db'); 207 | 208 | $table = preg_replace ('/#__/', $this->dbo->getPrefix(), $table); 209 | 210 | $this->dbo->setQuery("SELECT COUNT(*) AS count 211 | FROM information_schema.tables 212 | WHERE table_schema = '{$database}' 213 | AND table_name = '{$table}'"); 214 | 215 | return $this->dbo->loadResult(); 216 | } 217 | 218 | /** 219 | * populateDatabase 220 | * 221 | * @return boolean 222 | * @since 1.1.0 223 | * @throws Exception 224 | */ 225 | function populateDatabase($sqlfile) 226 | { 227 | if( !($buffer = file_get_contents($sqlfile)) ) 228 | { 229 | return -1; 230 | } 231 | 232 | $queries = $this->dbo->splitSql($buffer); 233 | 234 | foreach ($queries as $query) 235 | { 236 | $query = trim($query); 237 | if ($query != '' && $query {0} != '#') 238 | { 239 | $this->dbo->setQuery($query); 240 | $this->dbo->query(); 241 | 242 | // Check for query error. 243 | $error = $this->dbo->getErrorMsg(); 244 | 245 | if ($error) { 246 | throw new Exception($error); 247 | } 248 | 249 | } 250 | } 251 | 252 | return true; 253 | } 254 | 255 | 256 | protected function fixExtensionsAssets() 257 | { 258 | $this->dbo = JFactory::getDBO(); 259 | 260 | // Fixing categories assets 261 | $query = $this->dbo->getQuery(true); 262 | $query->select('name, element'); 263 | $query->from('#__extensions'); 264 | $query->where("type = 'component'"); 265 | $query->where("protected = 0"); 266 | $query->group('element'); 267 | $this->dbo->setQuery($query); 268 | $extensions = $this->dbo->loadObjectList(); 269 | 270 | // Getting the asset table 271 | $assetfix = JTable::getInstance('asset'); 272 | 273 | foreach($extensions as $extension) { 274 | $assetfix->id = 0; 275 | $assetfix->reset(); 276 | 277 | $assetfix->loadByName($extension->element); 278 | 279 | if ($assetfix->id == 0) { 280 | // Setting the name and title 281 | $assetfix->title = $extension->name; 282 | $assetfix->name = $extension->element; 283 | 284 | // Getting the original rules 285 | $query = $this->dbo->getQuery(true); 286 | $query->select('rules'); 287 | $query->from('#__assets_backup'); 288 | $query->where("name = '{$extension->element}'"); 289 | $this->dbo->setQuery($query); 290 | $rules = $this->dbo->loadResult(); 291 | $assetfix->rules = $rules !== null ? $rules : '{}'; 292 | 293 | // Setting the location of the new category 294 | $assetfix->setLocation(1, 'last-child'); 295 | $assetfix->store(); 296 | } 297 | } 298 | } // end method 299 | 300 | protected function fixCategoryAssets() 301 | { 302 | $this->dbo = JFactory::getDBO(); 303 | 304 | // Fixing categories assets 305 | $query = $this->dbo->getQuery(true); 306 | $query->select('*'); 307 | $query->from('#__categories'); 308 | $query->where('id != 1'); 309 | $query->order('parent_id'); 310 | $this->dbo->setQuery($query); 311 | $categories = $this->dbo->loadObjectList(); 312 | 313 | foreach($categories as $category) { 314 | 315 | // Fixing name of the extension 316 | $category->extension = $category->extension == 'com_contact_details' ? 'com_contact' : $category->extension; 317 | 318 | // Getting the asset table 319 | $assetfix = JTable::getInstance('asset'); 320 | 321 | $assetfix->title = $category->title; 322 | $assetfix->name = "{$category->extension}.category.{$category->id}"; 323 | 324 | // Getting the original rules 325 | $query = $this->dbo->getQuery(true); 326 | $query->select('rules'); 327 | $query->from('#__assets_backup'); 328 | $query->where("name = '{$assetfix->name}'"); 329 | $this->dbo->setQuery($query); 330 | $assetfix->rules = $this->dbo->loadResult(); 331 | 332 | // Setting the parent 333 | $parent = 0; 334 | if ($category->parent_id !== false) { 335 | if ($category->parent_id == 1) { 336 | $parentAsset = JTable::getInstance('asset'); 337 | $parentAsset->loadByName($category->extension); 338 | $parent = $parentAsset->id; 339 | } else if ($category->parent_id > 1) { 340 | // Getting the correct parent 341 | $query = $this->dbo->getQuery(true); 342 | $query->select('a.id'); 343 | $query->from('#__categories AS c'); 344 | $query->join('LEFT', '#__assets AS a ON a.title = c.title'); 345 | $query->where("c.id = {$category->parent_id}"); 346 | $this->dbo->setQuery($query); 347 | $parent = $this->dbo->loadResult(); 348 | } 349 | 350 | // Setting the location of the new category 351 | $assetfix->setLocation($parent, 'last-child'); 352 | } 353 | 354 | $assetfix->store(); 355 | 356 | // Fixing the category asset_id 357 | $query = $this->dbo->getQuery(true); 358 | $query->update($this->dbo->quoteName('#__categories')); 359 | $query->set($this->dbo->quoteName('asset_id') . ' = ' . (int)$assetfix->id); 360 | $query->where('id = ' . (int) $category->id); 361 | $this->dbo->setQuery($query); 362 | $this->dbo->query(); 363 | } 364 | } //end method 365 | 366 | protected function fixContentAssets() 367 | { 368 | $this->dbo = JFactory::getDBO(); 369 | 370 | // Fixing articles assets 371 | $query = $this->dbo->getQuery(true); 372 | $query->select('*'); 373 | $query->from('#__content'); 374 | $this->dbo->setQuery($query); 375 | $contents = $this->dbo->loadObjectList(); 376 | 377 | 378 | foreach($contents as $article) { 379 | 380 | // Getting the asset table 381 | $assetfix = JTable::getInstance('asset'); 382 | 383 | $assetfix->title = $article->title; 384 | $assetfix->name = "com_content.article.{$article->id}"; 385 | 386 | // Getting the original rules 387 | $query = $this->dbo->getQuery(true); 388 | $query->select('rules'); 389 | $query->from('#__assets_backup'); 390 | $query->where("name = '{$assetfix->name}'"); 391 | $this->dbo->setQuery($query); 392 | $assetfix->rules = $this->dbo->loadResult(); 393 | 394 | // Setting the parent 395 | $parent = 0; 396 | if ($article->catid !== false) { 397 | 398 | if ($article->catid == 1) { 399 | $parentAsset = JTable::getInstance('asset'); 400 | $parentAsset->loadByName('com_content'); 401 | $parent = $parentAsset->id; 402 | } else if ($article->catid > 1) { 403 | // Getting the correct parent 404 | $query = $this->dbo->getQuery(true); 405 | $query->select('a.id'); 406 | $query->from('#__categories AS c'); 407 | $query->join('LEFT', '#__assets AS a ON a.title = c.title'); 408 | $query->where("c.id = {$article->catid}"); 409 | $this->dbo->setQuery($query); 410 | $parent = $this->dbo->loadResult(); 411 | } 412 | 413 | // Setting the location of the new category 414 | $assetfix->setLocation($parent, 'last-child'); 415 | } 416 | 417 | $assetfix->store(); 418 | 419 | // Fixing the category asset_id 420 | $query = $this->dbo->getQuery(true); 421 | $query->update($this->dbo->quoteName('#__content')); 422 | $query->set($this->dbo->quoteName('asset_id') . ' = ' . (int)$assetfix->id); 423 | $query->where('id = ' . (int) $article->id); 424 | $this->dbo->setQuery($query); 425 | $this->dbo->query(); 426 | } 427 | 428 | } // end method 429 | 430 | } // end class 431 | 432 | JCli::getInstance('AssetFix')->execute(); 433 | --------------------------------------------------------------------------------