VbzCart/archive/code/admin.cache

from HTYP, the free directory anyone can edit if they can prove to me that they're not a spambot
< VbzCart‎ | archive‎ | code
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Code

<?php
/*
  LIBRARY: admin.cache.php - administration of cache management tables using MW UI
  HISTORY:
    2010-11-08 extracting from SpecialVbzAdmin
    2010-11-09 renaming "data" to "cache"
	Also renamed everything "Proc" to "Query", but then later decided this was not
	  as great an idea as I originally thought because procs are really the way to do this.
    2010-11-11 renaming "query" back to "proc"
*/
 
class clsAdminCacheMgr extends clsCacheMgr {
// STATIC methods -- these should later be methods of descendent classes of the component tables
    
    /*----
      INPUT:
	iName: what to display for a page (or interwiki) link
	iPfx: full name of page (or interwiki) link, but without the name (iPfx+iName = full page name)
    */
    static public function PageLink($iName,$iPfx) {
	global $vgOut;

	return $vgOut->InternalLink($iPfx.$iName,$iName);
    }
    static public function TableLinkDoc($iName) {
	return self::PageLink($iName,kwp_DocTblPfx);
    }
    static public function ProcLinkDoc($iName) {
	return self::PageLink($iName,kwp_DocPrcPfx);
    }
// OVERRIDE methods
    protected function NewTblTables($iName) {
	return new clsAdminCacheTables($this, $iName);
    }
    protected function NewTblProcs($iName) {
	return new clsAdminCacheProcs($this,$iName);
    }
    protected function NewTblFlows($iName) {
	return new clsAdminCacheFlows($this,$iName);
    }
    protected function NewTblEvents($iName) {
	return new clsAdminCacheEvents($this,$iName);
    }
// DYNAMIC methods
    public function MenuDispatch($iAction,$iID=NULL) {
	switch ($iAction) {
	  case 'cache':
	    $this->AdminPage();
	    break;
	  case 'cache.tbl':
	    $obj = $this->Tables->GetItem($iID);
	    $obj->AdminPage();
	    break;
	  case 'cache.proc':
	    $obj = $this->Procs->GetItem($iID);
	    $obj->AdminPage();
	    break;
	}
    }
    public function AdminPage() {
	global $wgRequest, $wgOut;
	global $vgPage, $vgOut;
	$vgPage->UseWiki();

	$out = '==Cache Management=='."\n";
	$wgOut->addWikiText($out,TRUE);	$out = '';

	$dbVBZ = $this->Engine();

// check for action requests
	$strDo = $vgPage->Arg('do');
	//$strTbls = $vgPage->Arg('id.table');
	if ($strDo != '') {
	    $idTbl = $vgPage->Arg('id');
	    if (is_numeric($idTbl)) {
		$objTbl = $this->Tables->GetItem($idTbl);
	    }
	    switch ($strDo) {
	      case 'update':
		$out .= $objTbl->UpdateData_Verbose();
		$out .= '<br>Update of '.$objTbl->AdminLink_Name().' complete.';
		break;
	      case 'stamp':
		$arRes = $objTbl->UpdateTime(__METHOD__);
		$out .= 'Stamped '.$objTbl->AdminLink_Name();
		$out .= "\n* '''Was''': ".$arRes['was'];
		$out .= "\n* '''SQL''': ".$arRes['sql'];
		break;
	      case 'clear':
		$arRes = $objTbl->ClearTime(__METHOD__);
		$out .= 'Cleared '.$objTbl->AdminLink_Name();
		$out .= "\n* '''Was''': ".$arRes['was'];
		$out .= "\n* '''SQL''': ".$arRes['sql'];
		break;
/*	      case 'table-info':
		$out = $this->AdminTable($idTbl);
		break;
	      case 'table-update':
		$out = $this->UpdateTable($idTbl,'Special:VbzAdmin');
		break;
	      case 'table-stamp';
		$out = $dbVBZ->StampTable($idTbl);
		break;
*/
	    }
	    $wgOut->addWikiText($out,TRUE);	$out = '';
	} else {
// display the current status
	    $out = '===Cache Tables==='."\n";
	    $wgOut->addWikiText($out,TRUE);	$out = '';
	    //$out = $this->ShowTables($strTbls);
	    $out = $this->ShowTables();
	    $wgOut->addWikiText($out,TRUE);	$out = '';
	    $out = '===Cache Procedures==='."\n";
	    $wgOut->addWikiText($out,TRUE);	$out = '';
	    $this->ShowProcs();
	}
	$dbVBZ->Shut();
    }

    public function ShowProcs() {
	global $vgPage,$vgOut;

	$vgPage->UseHTML();

	$tblProcs = $this->Procs;

	$objRows = $tblProcs->DataSet();	// get all rows

	if ($objRows->hasRows()) {
	    $out = $vgOut->TableOpen('class=sortable');
	    $out .= $vgOut->TblRowOpen(NULL,TRUE);
	      $out .= $vgOut->TblCell('procedure name');
	      $out .= $vgOut->TblCell('A?');
	      $out .= $vgOut->TblCell('Clr?');
	      $out .= $vgOut->TblCell('notes');
	    $out .= $vgOut->TblRowShut();
	    while ($objRows->NextRow()) {
		$out .= $vgOut->TblRowOpen();
		  //$ftName = $this->ProcLinkDoc($objRows->Name);
		  $ftName = $objRows->AdminLink_Name();
		  $isActive = $objRows->Value('isActive');
		  if (!$isActive) {
		      $ftName = '<s>'.$ftName.'</s>';
		  }
		  $out .= $vgOut->TblCell($ftName);
		  $out .= $vgOut->TblCell($isActive?'&radic;':'-');
		  $out .= $vgOut->TblCell(($objRows->Value('doesClear'))?'&radic;':'-');
		  $out .= $vgOut->TblCell($objRows->Value('Notes'));
		$out .= $vgOut->TblRowShut();
	    }
	    $out .= $vgOut->TableShut();
	} else {
	    $out .= 'No procedures found!';
	}
	$vgOut->AddText($out);
    }
    /*----
      FUTURE:
	Rename ShowTables() -> AdminTables()
	Move most of the code into clsAdminTables
    */
    public function ShowTables() {
	global $vgPage,$vgOut;

	$objPage = $vgPage;
	$vgPage->UseWiki();

	//$objTbls = $this->objDB->DataSet('SELECT * FROM '.$this->Tables->Name().' WHERE Name != "" ORDER BY Name');
	$objTbls = $this->Tables->GetData('Name != ""',NULL,'Name');

	if ($objTbls->hasRows()) {
	    $out = "{| class=sortable \n|-\n! table name || last update || sources || targets || notes";
	    while ($objTbls->NextRow()) {
		if ($objTbls->Value('isActive')) {
		    //$strTbl = $objTbls->Name;
		    $idTbl =  $objTbls->KeyValue();

		    $objSrces = $this->Sources($idTbl);
		    $objTargs = $this->Targets($idTbl);
		    $cntSrces = $objSrces->RowCount();
		    $cntTargs = $objTargs->RowCount();

// table info open/shut calculations
//		    $doInfo = isset($lstTbls[$idTbl]);

		    $htTblName = $objTbls->AdminLink_Name();

		    // common elements in action links
		    $arLink = $vgPage->Args(array('page'));
		    $arLink['id'] = $idTbl;

// source table list:
		    if ($cntSrces) {
/*
			$arLink = array(
			  'id'	=> $idTbl,
			  'do'	=> 'table-update'
			  );
			$txtSrces .= $objPage->SelfLink($arLink,'update').' ('.$cntSrces.')';
*/
			$arLink['do'] = 'update';
			$ftLink = $vgOut->SelfLink($arLink,'update','update this table from its sources');
			$txtSrces = $cntSrces.'&rarr;'.$ftLink;
		    } else { $txtSrces = ''; }
// target table list:

		    if ($cntTargs) {
			$arLink['do'] = 'clear';
			$ftLink1 = $vgOut->SelfLink($arLink,'un','clear the time-updated stamp for this table');

			$arLink['do'] = 'stamp';
			$ftLink2 = $vgOut->SelfLink($arLink,'stamp','update the time-updated stamp for this table');

			$txtTargs = '('.$ftLink1.')'.$ftLink2.'&rarr;'.$cntTargs;
		    } else { $txtTargs = ''; }
		    
		    $out .= "\n|-\n| ".$htTblName. ' || ' . $objTbls->Value('WhenUpdated') . 
		      ' || '.$txtSrces.
		      ' || '.$txtTargs.
		      ' || '.$objTbls->Value('Notes');

		    // if table is selected to show info, add a row for that:
/*
		    if ($doInfo) {
			$out .= "\n|-\n| colspan=5 |";
			if ($objSrces->hasRows()) {
			    $out .= "\n* '''Sources''':";
			    while ($objSrces->NextRow()) {
				$objSrce = 	$objDataMgr->Tables->GetItem($objSrces->ID_Srce);
				if ($objSrce->isActive) {
				    $strName = $objSrce->Name;
				    $out .= ' [['.kwp_DocTblPfx.$strName.'|'.$strName.']]';
				} else {
				    $out .= " ''N/A id=".$objSrces->ID_Srce."''";
				}
			    }
			}
			if ($objTargs->hasRows()) {
			    $out .= "\n* '''Targets''':";
			    while ($objTargs->NextRow()) {
				$objTarg = 	$objDataMgr->Tables->GetItem($objTargs->ID_Dest);
				if ($objTarg->isActive) {
				    $strName = $objTarg->Name;
				    $out .= ' [['.kwp_DocTblPfx.$strName.'|'.$strName.']]';
				} else {
				    $out .= " ''N/A id=".$objTargs->ID_Dest."''";
				}
			    }
			}
		    }
*/
		}
	    }
	    $out .= "\n|}";
	} else {
	    $out .= 'ERROR: Mysterious lack of data';
	}
	return $out;
    }
}
class clsAdminCacheTables extends clsCacheTables {
    protected $arMap,$arCkd;

    public function __construct(clsCacheMgr $iMgr,$iName) {
	parent::__construct($iMgr,$iName);
	  $this->ClassSng('clsAdminCacheTable');
	  $this->ActionKey('cache.tbl');
    }

// INFORMATION methods

    /*----
      RETURNS: recordset of targets with more recently-updated sources
      HISTORY:
	2011-12-21 created for update-cat maintenance script
    */
    public function UpdatedTargets() {
	// map out the cache and find out what needs to be run initially
	Write('Mapping the cache...');
	$rcFlows = $this->Mgr()->Flow->GetData();	// get table of all flows
	$this->arMap = $rcFlows->FullMap();
	$this->arCkd = array();

	WriteLn(' ok');
	$arRun = $this->arMap['run'];
	$cntRun = count($arRun);
	if ($cntRun > 0) {
	    WriteLn('Starting with '.$cntRun.' update'.Pluralize($cntRun).':');
	    $this->RunUpdates($arRun);
	}
    }
    /*----
      INPUT:
	$arRun: array of procs that need to be run
      NOTE: This does not take a rigorous approach to preventing loops.
	It just cuts off execution after the same Proc has been executed
	more than a preset number of times. There's probably a very tidy
	algorithmic way to figure out what order everything should be executed
	in while rigorously preventing recursion, but I don't have time
	to figure it out right now.
      HISTORY:
	2011-12-22 created for command line utility
	2011-12-24 allowing limited number of duplicate Procs
    */
    public function RunUpdates(array $arRun) {
	$tblT = $this->Mgr()->Tables;
	$rcT = $tblT->SpawnItem();
	$arDone = array();
	do {
	    $isMore = FALSE;
	    $arRunNext = array();

	    // display run list
	    WriteLn("----------\nTO RUN:");
	    foreach ($arRun as $idP => $objP) {
		$txt = ' '.$objP->NameFull();
		$msg = NULL;
		if (array_key_exists($idP,$arDone)) {
		    $cnt = $arDone[$idP];
		    if ($cnt > 2) {
			$msg = ' - LOOP DETECTED; quitting.';
			die($txt.$msg."\n");
		    }
		    $msg = ' - repeat #'.$cnt;
		    $arDone[$idP]++;
		} else {
		    $arDone[$idP] = 1;
		}
		WriteLn($txt.$msg);
	    }

	    foreach ($arRun as $idP => $objP) {
		Write('PROC: '.$objP->NameFull());
		$arEx = $objP->Execute(TRUE);	// FALSE = debug mode -- don't actually write data
		WriteLn(' - '.$arEx['text']);

		if (array_key_exists('targ',$arEx)) {
		    $arT = $arEx['targ'];	// target tables updated
		    if (count($arT) > 0) {
    //		    WriteLn(' - updated:');
			// get list of procs that supply those tables
			foreach ($arT as $idT => $rowT) {
			    WriteLn(' - updated TABLE: ['.$idT.'] '.$rowT['Name']);
			    $rcT->Values($rowT);
			    $arP = $rcT->TargProcs();
			    if (is_array($arP)) {
				foreach ($arP as $dummy => $rowP) {
				    WriteLn(' -- used by PROC: '.$rowP->NameFull());
				}
				$arRunNext = ArrayJoin($arRunNext,$arP,TRUE,TRUE);	// replace = yes (probably n/a), append = yes
    //			    $isMore = TRUE;
			    }
			}
		    }
		}

		if (array_key_exists($idP,$arRunNext)) {
		    WriteLn(' - removing '.$objP->NameFull().' from next run list');
		    unset($arRunNext[$idP]);
		    $txt = '';
		    foreach ($arRunNext as $idP => $objP) {
			$txt .= ' '.$idP;
		    }
		    WriteLn(' - list is now:'.$txt);
		}

	    }
	    // ultimately, this list may need to be sorted too:
	    $arRun = $arRunNext;
	    $isMore = Count($arRun) > 0;
/*
	    Write('TO RUN NEXT:');
	    foreach ($arRun as $id => $objP) {
		Write(' '.$objP->Name());
	    }
	    WriteLn();
*/
	} while ($isMore);
    }
/*
    protected function FindFlowSources(array $iSrce) {
	$arOut = array();
	foreach ($iSrce as $id => $obj) {
//	    Write(' -- source ID='.$id.' - '.$obj->Value('Name'));
	    if ($obj->IsActive()) {
//		WriteLn('');
		$ar = $this->FindRoots($obj);
		foreach ($ar as $id => $row) {
		    if (!array_key_exists($id,$arOut)) {
			$arOut[$id] = $row;
		    }
		}
	    } else {
//		WriteLn(' - INACTIVE');
	    }
	}
	return $arOut;
    }
*/
}
class clsAdminCacheTable extends clsCacheTable {

// BOILERPLATE methods

    public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
	return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs);
    }
    public function AdminLink_Name($iPopup=NULL,array $iarArgs=NULL) {
	return $this->AdminLink($this->Value('Name'),$iPopup,$iarArgs);
    }
    public function DocLink() {
	return $this->Mgr()->TableLinkDoc($this->Value('Name'));
    }

// ACTION methods

    /*----
      ACTION: Run $this->UpdateData() and display results
    */
    public function UpdateData_Verbose() {
	global $vgPage, $vgUserName;

	$out = '';
	//$arRes = $this->Update_byID($iID,$vgUserName.': '.__METHOD__);
	$arRes = $this->UpdateData($vgUserName.': '.__METHOD__);
	$out .= $arRes['msgs'];
	if (is_array($arRes['proc'])) {
	    $arDone = $arRes['proc'];
	    $out .= "\n===Update Procedures Run===\n";
	    foreach($arDone AS $obj) {
		$out .= "\n* ".$obj->Value('Name');
	    }
	} else {
	    $out .= '<br>No procedures were executed.';
	}
	if (is_array($arRes['targ'])) {
	    $arDone = $arRes['targ'];
	    $out .= "\n===Tables Updated===\n";
	    foreach($arDone AS $id=>$row) {
		$out .= "\n* ".$row['Name'];
	    }
	} else {
	    $out .= '<br>No tables were updated.';
	}
	return $out;
    }

// ADMIN DISPLAY methods
    public function AdminPage() {
	global $wgRequest;
	global $vgPage,$vgOut;

	$vgPage->UseWiki();

	$out = '==Table: '.$this->Value('Name')."==\n";

	$out .= "'''Note''': ADD and DELETE have not yet been tested, and they do not yet log changes.\n";

	$idTbl = $this->Value('ID');
	$out .= '===Table Record===';
	$out .= "\n* '''ID''': $idTbl";
	$out .= "\n* '''Name''': ".$this->DocLink();
	$out .= "\n* '''Updated''': ".$this->Value('WhenUpdated');
	$out .= "\n* '''Notes''': ".$this->Value('Notes');

	$vgOut->AddText($out); $out='';

// check for any form input (adding flows/procs)
	$doAddSrce = $wgRequest->getBool('btnAddSrce');
	$doAddTarg = $wgRequest->getBool('btnAddTarg');
	if ($doAddSrce || $doAddTarg) {
	    $idProc = $wgRequest->getBool('ID_Proc');
	    $doWrite = $doAddSrce;	// if proc is a source, then it writes to this table
	    $txtNotes = $wgRequest->getText('Notes');
	    $this->Mgr()->Flows->Add($iProc,$this->ID,$doWrite,$txtNotes);
	}

	$vgPage->UseHTML();

// SOURCES cell (left):
	$out .= $vgOut->Header('Table Sources',3);
	$out .= $this->AdminSources();

// TARGETS cell (right):
	$out .= $vgOut->Header('Table Targets',3);
	$out .= $this->AdminTargets();

	$vgOut->AddText($out);
    }
    public function AdminSources() {
	$objRows = $this->Mgr()->Sources($this->KeyValue());
	return $objRows->AdminList('btnAddSrce');
    }
    public function AdminTargets() {
	$objRows = $this->Mgr()->Targets($this->KeyValue());
	return $objRows->AdminList('btnAddTarg');
    }
}
class clsAdminCacheProcs extends clsCacheProcs {
    public function __construct(clsCacheMgr $iMgr,$iName) {
	parent::__construct($iMgr,$iName);
	  $this->ClassSng('clsAdminCacheProc');
	  $this->ActionKey('cache.proc');
    }
}
class clsAdminCacheProc extends clsCacheProc {
    public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
	return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs);
    }
    public function AdminLink_Name($iPopup=NULL,array $iarArgs=NULL) {
	return $this->AdminLink($this->Value('Name'),$iPopup,$iarArgs);
    }
    public function DocLink() {
	return $this->Mgr()->ProcLinkDoc($this->Value('Name'));
    }
    public function AdminPage() {
	global $vgPage,$vgOut;

	$vgPage->UseHTML();

	$out = $vgOut->Header('Procedure: '.$this->Value('Name'));

	$out .= '<ul>';
	$out .= '<li> <b>ID</b>: '.$this->KeyValue();
	$out .= '<li> <b>Name</b>: '.$this->DocLink();
	$out .= '<li> <b>Active</b>: '.NoYes($this->Value('isActive'));
	$out .= '<li> <b>Clears</b>: '.NoYes($this->Value('doesClear'));
	$out .= '</ul>';

	$vgOut->AddText($out); $out='';

	$rcFlows = $this->Mgr()->Flow->Data_forProc($this->KeyValue());
	if ($rcFlows->HasRows()) {
	    $ar = $rcFlows->PoolMap();
/*
	    while ($rcFlows->NextRow()) {
		$idTbl = $rcFlows->Value('ID_Table');
		$objTbl = $this->Mgr()->Tables->GetItem($idTbl);
		if ($rcFlows->Value('doWrite')) {
		    // the proc writes to these tables
		    $arTarg[$idTbl] = $objTbl;
		} else {
		    // the proc reads from these tables
		    $arSrce[$idTbl] = $objTbl;
		}
	    }
*/
	    $arTarg = $ar['targ'];
	    $arSrce = $ar['srce'];
	    $dtNewest = NULL;
	    $dtOldest = NULL;

	    $out .= $vgOut->Header('Source Tables',3);
	    if (isset($arSrce)) {
		$out .= '<ul>';
		foreach ($arSrce as $id => $objTbl) {
		    $dtThis = $objTbl->Value('WhenUpdated');
		    if ($dtThis > $dtNewest) {
			$dtNewest = $dtThis;
		    }
		    $strTime = (is_null($dtThis)?'<i>never updated</i>':('updated '.$dtThis));
		    $out .= '<li>'.$objTbl->AdminLink_Name().' - '.$strTime;
		}
		$out .= '</ul>';
	    } else {
		$out .= 'No sources found.';
	    }

	    $out .= $vgOut->Header('Target Tables',3);
	    if (isset($arTarg)) {
		$out .= '<ul>';
		foreach ($arTarg as $id => $objTbl) {
		    $dtThis = $objTbl->Value('WhenUpdated');
		    if (($dtThis < $dtOldest) || (is_null($dtOldest))) {
			$dtOldest = $dtThis;
		    }
		    $strTime = (is_null($dtThis)?'<i>never updated</i>':('updated '.$dtThis));
		    $out .= '<li>'.$objTbl->AdminLink_Name().' - '.$strTime;
		}
		$out .= '</ul>';
	    } else {
		$out .= 'No targets found.';
	    }
	    $out .= $vgOut->Header('Status',3);
	    if ($dtOldest < $dtNewest) {
		$out .= '<b>Update needed.</b>';
	    } else {
		$out .= 'This table is up-to-date.';
	    }
	} else {
	    $out .= 'This procedure is not used.';
	}

	$vgOut->AddText($out);
    }
}
class clsAdminCacheFlows extends clsCacheFlows {
    public function __construct(clsCacheMgr $iMgr,$iName) {
	parent::__construct($iMgr,$iName);
	  $this->ClassSng('clsAdminCacheFlow');
	  $this->ActionKey('cache.flow');
    }
}
class clsAdminCacheFlow extends clsCacheFlow {
    public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
	return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs);
    }
    /*----
      ACTION: Render administrative controls for the current dataset of flows
      INPUT: name of button for adding another row.
	If no name given, does not display button.
      RETURNS: formatted text using $vgOut
    */
    public function AdminList($iAddBtn=NULL) {
	global $vgOut;

	$out = NULL;
	if ($this->hasRows()) {
	    $out .= $vgOut->TableOpen('class=sortable');
	    $out .= $vgOut->TblRowOpen(NULL,TRUE);
	    $out .= $vgOut->TblCell('Procedure');
	    $out .= $vgOut->TblCell('Action');
	    $out .= $vgOut->TblCell('notes');
	    $out .= $vgOut->TblRowShut();

	    $doBtn = !is_null($iAddBtn);

	    $objMgr = $this->Mgr();
	    assert('is_object($this->objMgr)');
	    $objProcs = $objMgr->Procs;
	    $arProcs = NULL;

	    $isOdd = TRUE;
	    while ($this->NextRow()) {
		$row = $this->Row;

		$ftStyle = $isOdd?'background:#ffffff;':'background:#eeeeee;';
		$htStyle = 'style="'.$ftStyle.'"';
		$isOdd = !$isOdd;

		$idProc = $this->Value('ID_Proc');
		$objProc = $objProcs->GetItem($idProc);
		$ftProc = $objProc->AdminLink_Name();

		// exclusion array for drop-down:
		$arProcs[$idProc] = TRUE;

		$ftAct = $this->AdminLink('del');

		$ftNotes = $this->Value('Notes');

		$out .= $vgOut->TblRowOpen($htStyle);
		$out .= $vgOut->TblCell($ftProc);
		$out .= $vgOut->TblCell($ftAct);
		$out .= $vgOut->TblCell($ftNotes);
		$out .= $vgOut->TblRowShut();
	    }

	    // display a row for adding a proc
	    if ($doBtn) {
		$out .= '<form method=POST>';
		$out .= $vgOut->TblRowOpen();
		$out .= $vgOut->TblCell($objProcs->DropDown('ID_Proc',NULL,$arProcs));
		$out .= $vgOut->TblCell('<input type=submit name="'.$iAddBtn.'" value="Add">');
		$out .= $vgOut->TblCell('<input name="notes">');
		$out .= $vgOut->TblRowShut();
		$out .= '</form>';
	    }
	    $out .= $vgOut->TableShut();
	} else {
	    $out .= 'none';
	}
	return $out;
    }
}
 
class clsAdminCacheEvents extends clsCacheEvents {
    public function __construct(clsCacheMgr $iMgr,$iName) {
	parent::__construct($iMgr,$iName);
	  $this->ClassSng('clsAdminCacheEvent');
	  $this->ActionKey('cache.event');
    }
}
class clsAdminCacheEvent extends clsCacheEvent {
    public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
	return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs);
    }
}