Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Setting tests (all). 19 * 20 * @package core_backup 21 * @category test 22 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace core_backup; 27 28 use activity_backup_setting; 29 use backup_setting; 30 use backup_setting_exception; 31 use base_setting; 32 use base_setting_exception; 33 use course_backup_setting; 34 use section_backup_setting; 35 use setting_dependency; 36 use setting_dependency_disabledif_empty; 37 38 defined('MOODLE_INTERNAL') || die(); 39 40 // Include all the needed stuff 41 global $CFG; 42 require_once($CFG->dirroot . '/backup/util/interfaces/checksumable.class.php'); 43 require_once($CFG->dirroot . '/backup/backup.class.php'); 44 require_once($CFG->dirroot . '/backup/util/settings/base_setting.class.php'); 45 require_once($CFG->dirroot . '/backup/util/settings/backup_setting.class.php'); 46 require_once($CFG->dirroot . '/backup/util/settings/setting_dependency.class.php'); 47 require_once($CFG->dirroot . '/backup/util/settings/root/root_backup_setting.class.php'); 48 require_once($CFG->dirroot . '/backup/util/settings/activity/activity_backup_setting.class.php'); 49 require_once($CFG->dirroot . '/backup/util/settings/section/section_backup_setting.class.php'); 50 require_once($CFG->dirroot . '/backup/util/settings/course/course_backup_setting.class.php'); 51 require_once($CFG->dirroot . '/backup/util/ui/backup_ui_setting.class.php'); 52 53 /** 54 * Setting tests (all). 55 * 56 * @package core_backup 57 * @category test 58 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} 59 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 60 */ 61 class settings_test extends \basic_testcase { 62 63 /** 64 * test base_setting class 65 */ 66 public function test_base_setting() { 67 // Instantiate base_setting and check everything 68 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN); 69 $this->assertTrue($bs instanceof base_setting); 70 $this->assertEquals($bs->get_name(), 'test'); 71 $this->assertEquals($bs->get_vtype(), base_setting::IS_BOOLEAN); 72 $this->assertTrue(is_null($bs->get_value())); 73 $this->assertEquals($bs->get_visibility(), base_setting::VISIBLE); 74 $this->assertEquals($bs->get_status(), base_setting::NOT_LOCKED); 75 76 // Instantiate base_setting with explicit nulls 77 $bs = new mock_base_setting('test', base_setting::IS_FILENAME, 'filename.txt', null, null); 78 $this->assertEquals($bs->get_value() , 'filename.txt'); 79 $this->assertEquals($bs->get_visibility(), base_setting::VISIBLE); 80 $this->assertEquals($bs->get_status(), base_setting::NOT_LOCKED); 81 82 // Instantiate base_setting and set value, visibility and status 83 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN); 84 $bs->set_value(true); 85 $this->assertNotEmpty($bs->get_value()); 86 $bs->set_visibility(base_setting::HIDDEN); 87 $this->assertEquals($bs->get_visibility(), base_setting::HIDDEN); 88 $bs->set_status(base_setting::LOCKED_BY_HIERARCHY); 89 $this->assertEquals($bs->get_status(), base_setting::LOCKED_BY_HIERARCHY); 90 91 // Instantiate with wrong vtype 92 try { 93 $bs = new mock_base_setting('test', 'one_wrong_type'); 94 $this->assertTrue(false, 'base_setting_exception expected'); 95 } catch (\Exception $e) { 96 $this->assertTrue($e instanceof base_setting_exception); 97 $this->assertEquals($e->errorcode, 'setting_invalid_type'); 98 } 99 100 // Instantiate with wrong integer value 101 try { 102 $bs = new mock_base_setting('test', base_setting::IS_INTEGER, 99.99); 103 $this->assertTrue(false, 'base_setting_exception expected'); 104 } catch (\Exception $e) { 105 $this->assertTrue($e instanceof base_setting_exception); 106 $this->assertEquals($e->errorcode, 'setting_invalid_integer'); 107 } 108 109 // Instantiate with wrong filename value 110 try { 111 $bs = new mock_base_setting('test', base_setting::IS_FILENAME, '../../filename.txt'); 112 $this->assertTrue(false, 'base_setting_exception expected'); 113 } catch (\Exception $e) { 114 $this->assertTrue($e instanceof base_setting_exception); 115 $this->assertEquals($e->errorcode, 'setting_invalid_filename'); 116 } 117 118 // Instantiate with wrong visibility 119 try { 120 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN, null, 'one_wrong_visibility'); 121 $this->assertTrue(false, 'base_setting_exception expected'); 122 } catch (\Exception $e) { 123 $this->assertTrue($e instanceof base_setting_exception); 124 $this->assertEquals($e->errorcode, 'setting_invalid_visibility'); 125 } 126 127 // Instantiate with wrong status 128 try { 129 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN, null, null, 'one_wrong_status'); 130 $this->assertTrue(false, 'base_setting_exception expected'); 131 } catch (\Exception $e) { 132 $this->assertTrue($e instanceof base_setting_exception); 133 $this->assertEquals($e->errorcode, 'setting_invalid_status'); 134 } 135 136 // Instantiate base_setting and try to set wrong ui_type 137 // We need a custom error handler to catch the type hinting error 138 // that should return incorrect_object_passed 139 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN); 140 set_error_handler('\core_backup\backup_setting_error_handler', E_RECOVERABLE_ERROR); 141 try { 142 $bs->set_ui('one_wrong_ui_type', 'label', array(), array()); 143 $this->assertTrue(false, 'base_setting_exception expected'); 144 } catch (\Exception $e) { 145 $this->assertTrue($e instanceof base_setting_exception); 146 $this->assertEquals($e->errorcode, 'incorrect_object_passed'); 147 } catch (\TypeError $e) { 148 // On PHP7+ we get a TypeError raised, lets check we've the right error. 149 $this->assertMatchesRegularExpression('/must be (of type|an instance of) backup_setting_ui/', $e->getMessage()); 150 } 151 restore_error_handler(); 152 153 // Instantiate base_setting and try to set wrong ui_label 154 // We need a custom error handler to catch the type hinting error 155 // that should return incorrect_object_passed 156 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN); 157 set_error_handler('\core_backup\backup_setting_error_handler', E_RECOVERABLE_ERROR); 158 try { 159 $bs->set_ui(base_setting::UI_HTML_CHECKBOX, 'one/wrong/label', array(), array()); 160 $this->assertTrue(false, 'base_setting_exception expected'); 161 } catch (\Exception $e) { 162 $this->assertTrue($e instanceof base_setting_exception); 163 $this->assertEquals($e->errorcode, 'incorrect_object_passed'); 164 } catch (\TypeError $e) { 165 // On PHP7+ we get a TypeError raised, lets check we've the right error. 166 $this->assertMatchesRegularExpression('/must be (of type|an instance of) backup_setting_ui/', $e->getMessage()); 167 } 168 restore_error_handler(); 169 170 // Try to change value of locked setting by permission 171 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN, null, null, base_setting::LOCKED_BY_PERMISSION); 172 try { 173 $bs->set_value(true); 174 $this->assertTrue(false, 'base_setting_exception expected'); 175 } catch (\Exception $e) { 176 $this->assertTrue($e instanceof base_setting_exception); 177 $this->assertEquals($e->errorcode, 'setting_locked_by_permission'); 178 } 179 180 // Try to change value of locked setting by config 181 $bs = new mock_base_setting('test', base_setting::IS_BOOLEAN, null, null, base_setting::LOCKED_BY_CONFIG); 182 try { 183 $bs->set_value(true); 184 $this->assertTrue(false, 'base_setting_exception expected'); 185 } catch (\Exception $e) { 186 $this->assertTrue($e instanceof base_setting_exception); 187 $this->assertEquals($e->errorcode, 'setting_locked_by_config'); 188 } 189 190 // Try to add same setting twice 191 $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null); 192 $bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null); 193 $bs1->add_dependency($bs2, null, array('value'=>0)); 194 try { 195 $bs1->add_dependency($bs2); 196 $this->assertTrue(false, 'base_setting_exception expected'); 197 } catch (\Exception $e) { 198 $this->assertTrue($e instanceof base_setting_exception); 199 $this->assertEquals($e->errorcode, 'setting_already_added'); 200 } 201 202 // Try to create one circular reference 203 $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null); 204 try { 205 $bs1->add_dependency($bs1); // self 206 $this->assertTrue(false, 'base_setting_exception expected'); 207 } catch (\Exception $e) { 208 $this->assertTrue($e instanceof base_setting_exception); 209 $this->assertEquals($e->errorcode, 'setting_circular_reference'); 210 $this->assertTrue($e->a instanceof \stdClass); 211 $this->assertEquals($e->a->main, 'test1'); 212 $this->assertEquals($e->a->alreadydependent, 'test1'); 213 } 214 215 $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null); 216 $bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null); 217 $bs3 = new mock_base_setting('test3', base_setting::IS_INTEGER, null); 218 $bs4 = new mock_base_setting('test4', base_setting::IS_INTEGER, null); 219 $bs1->add_dependency($bs2, null, array('value'=>0)); 220 $bs2->add_dependency($bs3, null, array('value'=>0)); 221 $bs3->add_dependency($bs4, null, array('value'=>0)); 222 try { 223 $bs4->add_dependency($bs1, null, array('value'=>0)); 224 $this->assertTrue(false, 'base_setting_exception expected'); 225 } catch (\Exception $e) { 226 $this->assertTrue($e instanceof base_setting_exception); 227 $this->assertEquals($e->errorcode, 'setting_circular_reference'); 228 $this->assertTrue($e->a instanceof \stdClass); 229 $this->assertEquals($e->a->main, 'test1'); 230 $this->assertEquals($e->a->alreadydependent, 'test4'); 231 } 232 233 $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null); 234 $bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null); 235 $bs1->register_dependency(new setting_dependency_disabledif_empty($bs1, $bs2)); 236 try { 237 // $bs1 is already dependent on $bs2 so this should fail. 238 $bs2->register_dependency(new setting_dependency_disabledif_empty($bs2, $bs1)); 239 $this->assertTrue(false, 'base_setting_exception expected'); 240 } catch (\Exception $e) { 241 $this->assertTrue($e instanceof base_setting_exception); 242 $this->assertEquals($e->errorcode, 'setting_circular_reference'); 243 $this->assertTrue($e->a instanceof \stdClass); 244 $this->assertEquals($e->a->main, 'test1'); 245 $this->assertEquals($e->a->alreadydependent, 'test2'); 246 } 247 248 // Create 3 settings and observe between them, last one must 249 // automatically inherit all the settings defined in the main one 250 $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null); 251 $bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null); 252 $bs3 = new mock_base_setting('test3', base_setting::IS_INTEGER, null); 253 $bs1->add_dependency($bs2, setting_dependency::DISABLED_NOT_EMPTY); 254 $bs2->add_dependency($bs3, setting_dependency::DISABLED_NOT_EMPTY); 255 // Check values are spreaded ok 256 $bs1->set_value(123); 257 $this->assertEquals($bs1->get_value(), 123); 258 $this->assertEquals($bs2->get_value(), $bs1->get_value()); 259 $this->assertEquals($bs3->get_value(), $bs1->get_value()); 260 261 // Add one more setting and set value again 262 $bs4 = new mock_base_setting('test4', base_setting::IS_INTEGER, null); 263 $bs2->add_dependency($bs4, setting_dependency::DISABLED_NOT_EMPTY); 264 $bs2->set_value(321); 265 // The above change should change 266 $this->assertEquals($bs1->get_value(), 123); 267 $this->assertEquals($bs2->get_value(), 321); 268 $this->assertEquals($bs3->get_value(), 321); 269 $this->assertEquals($bs4->get_value(), 321); 270 271 // Check visibility is spreaded ok 272 $bs1->set_visibility(base_setting::HIDDEN); 273 $this->assertEquals($bs2->get_visibility(), $bs1->get_visibility()); 274 $this->assertEquals($bs3->get_visibility(), $bs1->get_visibility()); 275 // Check status is spreaded ok 276 $bs1->set_status(base_setting::LOCKED_BY_HIERARCHY); 277 $this->assertEquals($bs2->get_status(), $bs1->get_status()); 278 $this->assertEquals($bs3->get_status(), $bs1->get_status()); 279 280 // Create 3 settings and observe between them, put them in one array, 281 // force serialize/deserialize to check the observable pattern continues 282 // working after that 283 $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null); 284 $bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null); 285 $bs3 = new mock_base_setting('test3', base_setting::IS_INTEGER, null); 286 $bs1->add_dependency($bs2, null, array('value'=>0)); 287 $bs2->add_dependency($bs3, null, array('value'=>0)); 288 // Serialize 289 $arr = array($bs1, $bs2, $bs3); 290 $ser = base64_encode(serialize($arr)); 291 // Unserialize and copy to new objects 292 $newarr = unserialize(base64_decode($ser)); 293 $ubs1 = $newarr[0]; 294 $ubs2 = $newarr[1]; 295 $ubs3 = $newarr[2]; 296 // Must continue being base settings 297 $this->assertTrue($ubs1 instanceof base_setting); 298 $this->assertTrue($ubs2 instanceof base_setting); 299 $this->assertTrue($ubs3 instanceof base_setting); 300 // Set parent setting 301 $ubs1->set_value(1234); 302 $ubs1->set_visibility(base_setting::HIDDEN); 303 $ubs1->set_status(base_setting::LOCKED_BY_HIERARCHY); 304 // Check changes have been spreaded 305 $this->assertEquals($ubs2->get_visibility(), $ubs1->get_visibility()); 306 $this->assertEquals($ubs3->get_visibility(), $ubs1->get_visibility()); 307 $this->assertEquals($ubs2->get_status(), $ubs1->get_status()); 308 $this->assertEquals($ubs3->get_status(), $ubs1->get_status()); 309 } 310 311 /** 312 * Test that locked and unlocked states on dependent backup settings at the same level 313 * correctly do not flow from the parent to the child setting when the setting is locked by permissions. 314 */ 315 public function test_dependency_empty_locked_by_permission_child_is_not_unlocked() { 316 // Check dependencies are working ok. 317 $bs1 = new mock_backup_setting('test1', base_setting::IS_INTEGER, 2); 318 $bs1->set_level(1); 319 $bs2 = new mock_backup_setting('test2', base_setting::IS_INTEGER, 2); 320 $bs2->set_level(1); // Same level *must* work. 321 $bs1->add_dependency($bs2, setting_dependency::DISABLED_EMPTY); 322 323 $bs1->set_status(base_setting::LOCKED_BY_PERMISSION); 324 $this->assertEquals(base_setting::LOCKED_BY_HIERARCHY, $bs2->get_status()); 325 $this->assertEquals(base_setting::LOCKED_BY_PERMISSION, $bs1->get_status()); 326 $bs2->set_status(base_setting::LOCKED_BY_PERMISSION); 327 $this->assertEquals(base_setting::LOCKED_BY_PERMISSION, $bs1->get_status()); 328 329 // Unlocking the parent should NOT unlock the child. 330 $bs1->set_status(base_setting::NOT_LOCKED); 331 332 $this->assertEquals(base_setting::LOCKED_BY_PERMISSION, $bs2->get_status()); 333 } 334 335 /** 336 * Test that locked and unlocked states on dependent backup settings at the same level 337 * correctly do flow from the parent to the child setting when the setting is locked by config. 338 */ 339 public function test_dependency_not_empty_locked_by_config_parent_is_unlocked() { 340 $bs1 = new mock_backup_setting('test1', base_setting::IS_INTEGER, 0); 341 $bs1->set_level(1); 342 $bs2 = new mock_backup_setting('test2', base_setting::IS_INTEGER, 0); 343 $bs2->set_level(1); // Same level *must* work. 344 $bs1->add_dependency($bs2, setting_dependency::DISABLED_NOT_EMPTY); 345 346 $bs1->set_status(base_setting::LOCKED_BY_CONFIG); 347 $this->assertEquals(base_setting::LOCKED_BY_HIERARCHY, $bs2->get_status()); 348 $this->assertEquals(base_setting::LOCKED_BY_CONFIG, $bs1->get_status()); 349 350 // Unlocking the parent should unlock the child. 351 $bs1->set_status(base_setting::NOT_LOCKED); 352 $this->assertEquals(base_setting::NOT_LOCKED, $bs2->get_status()); 353 } 354 355 /** 356 * test backup_setting class 357 */ 358 public function test_backup_setting() { 359 // Instantiate backup_setting class and set level 360 $bs = new mock_backup_setting('test', base_setting::IS_INTEGER, null); 361 $bs->set_level(1); 362 $this->assertEquals($bs->get_level(), 1); 363 364 // Instantiate backup setting class and try to add one non backup_setting dependency 365 set_error_handler('\core_backup\backup_setting_error_handler', E_RECOVERABLE_ERROR); 366 $bs = new mock_backup_setting('test', base_setting::IS_INTEGER, null); 367 try { 368 $bs->add_dependency(new \stdClass()); 369 $this->assertTrue(false, 'backup_setting_exception expected'); 370 } catch (\Exception $e) { 371 $this->assertTrue($e instanceof backup_setting_exception); 372 $this->assertEquals($e->errorcode, 'incorrect_object_passed'); 373 } catch (\TypeError $e) { 374 // On PHP7+ we get a TypeError raised, lets check we've the right error. 375 $this->assertMatchesRegularExpression('/must be (an instance of|of type) base_setting/', $e->getMessage()); 376 } 377 restore_error_handler(); 378 379 // Try to assing upper level dependency 380 $bs1 = new mock_backup_setting('test1', base_setting::IS_INTEGER, null); 381 $bs1->set_level(1); 382 $bs2 = new mock_backup_setting('test2', base_setting::IS_INTEGER, null); 383 $bs2->set_level(2); 384 try { 385 $bs2->add_dependency($bs1); 386 $this->assertTrue(false, 'backup_setting_exception expected'); 387 } catch (\Exception $e) { 388 $this->assertTrue($e instanceof backup_setting_exception); 389 $this->assertEquals($e->errorcode, 'cannot_add_upper_level_dependency'); 390 } 391 392 // Check dependencies are working ok 393 $bs1 = new mock_backup_setting('test1', base_setting::IS_INTEGER, null); 394 $bs1->set_level(1); 395 $bs2 = new mock_backup_setting('test2', base_setting::IS_INTEGER, null); 396 $bs2->set_level(1); // Same level *must* work 397 $bs1->add_dependency($bs2, setting_dependency::DISABLED_NOT_EMPTY); 398 $bs1->set_value(123456); 399 $this->assertEquals($bs2->get_value(), $bs1->get_value()); 400 } 401 402 /** 403 * test activity_backup_setting class 404 */ 405 public function test_activity_backup_setting() { 406 $bs = new mock_activity_backup_setting('test', base_setting::IS_INTEGER, null); 407 $this->assertEquals($bs->get_level(), backup_setting::ACTIVITY_LEVEL); 408 409 // Check checksum implementation is working 410 $bs1 = new mock_activity_backup_setting('test', base_setting::IS_INTEGER, null); 411 $bs1->set_value(123); 412 $checksum = $bs1->calculate_checksum(); 413 $this->assertNotEmpty($checksum); 414 $this->assertTrue($bs1->is_checksum_correct($checksum)); 415 } 416 417 /** 418 * test section_backup_setting class 419 */ 420 public function test_section_backup_setting() { 421 $bs = new mock_section_backup_setting('test', base_setting::IS_INTEGER, null); 422 $this->assertEquals($bs->get_level(), backup_setting::SECTION_LEVEL); 423 424 // Check checksum implementation is working 425 $bs1 = new mock_section_backup_setting('test', base_setting::IS_INTEGER, null); 426 $bs1->set_value(123); 427 $checksum = $bs1->calculate_checksum(); 428 $this->assertNotEmpty($checksum); 429 $this->assertTrue($bs1->is_checksum_correct($checksum)); 430 } 431 432 /** 433 * test course_backup_setting class 434 */ 435 public function test_course_backup_setting() { 436 $bs = new mock_course_backup_setting('test', base_setting::IS_INTEGER, null); 437 $this->assertEquals($bs->get_level(), backup_setting::COURSE_LEVEL); 438 439 // Check checksum implementation is working 440 $bs1 = new mock_course_backup_setting('test', base_setting::IS_INTEGER, null); 441 $bs1->set_value(123); 442 $checksum = $bs1->calculate_checksum(); 443 $this->assertNotEmpty($checksum); 444 $this->assertTrue($bs1->is_checksum_correct($checksum)); 445 } 446 } 447 448 /** 449 * helper extended base_setting class that makes some methods public for testing 450 */ 451 class mock_base_setting extends base_setting { 452 public function get_vtype() { 453 return $this->vtype; 454 } 455 456 public function process_change($setting, $ctype, $oldv) { 457 // Simply, inherit from the main object 458 $this->set_value($setting->get_value()); 459 $this->set_visibility($setting->get_visibility()); 460 $this->set_status($setting->get_status()); 461 } 462 } 463 464 /** 465 * helper extended backup_setting class that makes some methods public for testing 466 */ 467 class mock_backup_setting extends backup_setting { 468 public function set_level($level) { 469 $this->level = $level; 470 } 471 472 public function process_change($setting, $ctype, $oldv) { 473 // Simply, inherit from the main object 474 $this->set_value($setting->get_value()); 475 $this->set_visibility($setting->get_visibility()); 476 $this->set_status($setting->get_status()); 477 } 478 } 479 480 /** 481 * helper extended activity_backup_setting class that makes some methods public for testing 482 */ 483 class mock_activity_backup_setting extends activity_backup_setting { 484 public function process_change($setting, $ctype, $oldv) { 485 // Do nothing 486 } 487 } 488 489 /** 490 * helper extended section_backup_setting class that makes some methods public for testing 491 */ 492 class mock_section_backup_setting extends section_backup_setting { 493 public function process_change($setting, $ctype, $oldv) { 494 // Do nothing 495 } 496 } 497 498 /** 499 * helper extended course_backup_setting class that makes some methods public for testing 500 */ 501 class mock_course_backup_setting extends course_backup_setting { 502 public function process_change($setting, $ctype, $oldv) { 503 // Do nothing 504 } 505 } 506 507 /** 508 * This error handler is used to convert errors to excpetions so that simepltest can 509 * catch them. 510 * 511 * This is required in order to catch type hint mismatches that result in a error 512 * being thrown. It should only ever be used to catch E_RECOVERABLE_ERROR's. 513 * 514 * It throws a backup_setting_exception with 'incorrect_object_passed' 515 * 516 * @param int $errno E_RECOVERABLE_ERROR 517 * @param string $errstr 518 * @param string $errfile 519 * @param int $errline 520 * @return null 521 */ 522 function backup_setting_error_handler($errno, $errstr, $errfile, $errline) { 523 if ($errno !== E_RECOVERABLE_ERROR) { 524 // Currently we only want to deal with type hinting errors 525 return false; 526 } 527 throw new backup_setting_exception('incorrect_object_passed'); 528 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body