/**
  * Save assets by section
  * @param string $section
  * @param array $assets
  * @return Status
  */
 public function saveAssetsBySection($section, $assets)
 {
     wfProfileIn(__METHOD__);
     if (empty($this->language) || empty($this->publishDate)) {
         wfProfileOut(__METHOD__);
         return Status::newFatal(wfMessage('videopagetool-error-missing-parameter')->plain());
     }
     $db = $this->getMasterDB();
     $db->begin();
     $status = Status::newGood();
     // save program
     $this->save();
     if (!$status->isGood()) {
         $db->rollback();
         wfProfileOut(__METHOD__);
         return $status;
     }
     // save assets
     $time = time();
     $userId = $this->wg->User->getId();
     $assetList = array();
     foreach ($assets as $order => $asset) {
         $assetObj = VideoPageToolAsset::newAsset($this->programId, $section, $order);
         if (empty($asset)) {
             $status = $assetObj->delete();
         } else {
             $assetObj->setData($asset);
             $assetObj->setUpdatedAt($time);
             $assetObj->setUpdatedBy($userId);
             $status = $assetObj->save();
         }
         if (!$status->isGood()) {
             $db->rollback();
             wfProfileOut(__METHOD__);
             return $status;
         }
         if (!empty($asset)) {
             $assetList[$order] = $assetObj;
         }
     }
     $db->commit();
     // save cache
     $this->invalidateCache();
     $this->saveToCache();
     foreach ($assetList as $assetObj) {
         /** @var VideoPageToolAsset $assetObj */
         $assetObj->saveToCache();
     }
     wfProfileOut(__METHOD__);
     return $status;
 }
 /**
  * @dataProvider CRUDAssetData
  */
 public function testCRUDAsset($type, $order, $data)
 {
     $section = $type::SECTION;
     /**
      * Create and save the object
      */
     // Check creation
     $asset = VideoPageToolAsset::newAsset($this->programID, $section, $order);
     $this->assertInstanceOf($type, $asset, "Failed to create new {$type} object");
     $asset->setData($data);
     global $wgUser;
     $asset->setUpdatedBy($wgUser->getId());
     $status = $asset->save();
     $this->assertTrue($status->isGood(), 'Failed to save new $type object');
     $this->assertInternalType('integer', $asset->getAssetId(), 'Result of getAssetId is not an integer');
     $this->assertGreaterThan(0, $asset->getAssetId(), 'Asset ID is not greater than zero');
     // Make sure we can get the program
     $program = $asset->getProgram();
     $this->assertTrue($program instanceof VideoPageToolProgram, 'Did not get a program object back from getProgram');
     /**
      * Check loading the object from cache
      */
     $memcLoadedAsset = VideoPageToolAsset::newAsset($this->programID, $section, $order);
     $this->assertEquals($asset->getAssetId(), $memcLoadedAsset->getAssetId(), "Not able to load saved asset");
     // Check getters
     $this->assertEquals($this->programID, $memcLoadedAsset->getProgramId(), 'Got wrong program ID');
     $this->assertEquals($section, $memcLoadedAsset->getSection(), 'Got wrong section name');
     $this->assertEquals($order, $memcLoadedAsset->getOrder(), 'Got wrong order number');
     // Check for default data
     $defaultAssetData = $memcLoadedAsset->getDefaultAssetData();
     $this->assertNotNull($defaultAssetData, 'No default data present');
     // Get the data
     $assetData = $memcLoadedAsset->getAssetData();
     // Note that $assetData will always be the classes default data since the test data
     // we're sending in does not name a valid video title
     $this->assertNotNull($assetData, 'No asset data present');
     // Check the asset data against what we saved
     foreach ($data as $prop => $value) {
         $this->assertObjectHasAttribute($prop, $memcLoadedAsset);
         $this->assertAttributeEquals($value, $prop, $memcLoadedAsset, "Attribute {$prop} has incorrect value");
     }
     // Let slave catch up
     sleep(1);
     /**
      * Check loading the object from database
      */
     // Make sure memcache doesn't fulfill our request
     $this->disableMemcached();
     $dbLoadedAsset = VideoPageToolAsset::newAsset($this->programID, $section, $order);
     $this->assertEquals($asset->getAssetId(), $dbLoadedAsset->getAssetId(), "Not able to load saved asset");
     // Check getters
     $this->assertEquals($this->programID, $dbLoadedAsset->getProgramId(), 'Got wrong program ID');
     $this->assertEquals($section, $dbLoadedAsset->getSection(), 'Got wrong section name');
     $this->assertEquals($order, $dbLoadedAsset->getOrder(), 'Got wrong order number');
     // Check for default data
     $defaultAssetData = $dbLoadedAsset->getDefaultAssetData();
     $this->assertNotNull($defaultAssetData, 'No default data present');
     // Get the data
     $assetData = $dbLoadedAsset->getAssetData();
     // Note that $assetData will always be the classes default data since the test data
     // we're sending in does not name a valid video title
     $this->assertNotNull($assetData, 'No asset data present');
     // Check the asset data against what we saved
     foreach ($data as $prop => $value) {
         $this->assertObjectHasAttribute($prop, $dbLoadedAsset);
         $this->assertAttributeEquals($value, $prop, $dbLoadedAsset, "Attribute {$prop} has incorrect value");
     }
     // Check delete
     $this->enableMemcached();
     $status = $asset->delete();
     $this->assertTrue($status->isGood(), 'Failed to delete new $type object');
     $deletedAsset = VideoPageToolAsset::newAsset($this->programID, $section, $order);
     $this->assertNull($deletedAsset->getAssetId(), 'Unsuccessful delete');
 }