%PDF- %PDF-
| Direktori : /home1/lightco1/www/administrator/components/com_akeeba/BackupEngine/Base/ |
| Current File : //home1/lightco1/www/administrator/components/com_akeeba/BackupEngine/Base/Part.php |
<?php
/**
* Akeeba Engine
* The modular PHP5 site backup engine
*
* @copyright Copyright (c)2006-2017 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or, at your option, any later version
* @package akeebaengine
*
*/
namespace Akeeba\Engine\Base;
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Factory;
use Psr\Log\LogLevel;
/**
* The superclass of all Akeeba Engine parts. The "parts" are intelligent stateful
* classes which perform a single procedure and have preparation, running and
* finalization phases. The transition between phases is handled automatically by
* this superclass' tick() final public method, which should be the ONLY public API
* exposed to the rest of the Akeeba Engine.
*/
abstract class Part extends BaseObject
{
/**
* Indicates whether this part has finished its initialisation cycle
*
* @var boolean
*/
protected $isPrepared = false;
/**
* Indicates whether this part has more work to do (it's in running state)
*
* @var boolean
*/
protected $isRunning = false;
/**
* Indicates whether this part has finished its finalization cycle
*
* @var boolean
*/
protected $isFinished = false;
/**
* Indicates whether this part has finished its run cycle
*
* @var boolean
*/
protected $hasRan = false;
/**
* The name of the engine part (a.k.a. Domain), used in return table
* generation.
*
* @var string
*/
protected $active_domain = "";
/**
* The step this engine part is in. Used verbatim in return table and
* should be set by the code in the _run() method.
*
* @var string
*/
protected $active_step = "";
/**
* A more detailed description of the step this engine part is in. Used
* verbatim in return table and should be set by the code in the _run()
* method.
*
* @var string
*/
protected $active_substep = "";
/**
* Any configuration variables, in the form of an array.
*
* @var array
*/
protected $_parametersArray = array();
/** @var string The database root key */
protected $databaseRoot = array();
/** @var int Last reported warning's position in array */
private $warnings_pointer = -1;
/** @var bool Should we log the step nesting? */
protected $nest_logging = false;
/** @var object Embedded installer preferences */
protected $installerSettings;
/** @var int How much milliseconds should we wait to reach the min exec time */
protected $waitTimeMsec = 0;
/** @var bool Should I ignore the minimum execution time altogether? */
protected $ignoreMinimumExecutionTime = false;
/**
* Public constructor
*
* @return Part
*/
public function __construct()
{
// Fetch the installer settings
$this->installerSettings = (object)array(
'installerroot' => 'installation',
'sqlroot' => 'installation/sql',
'databasesini' => 1,
'readme' => 1,
'extrainfo' => 1,
'password' => 0,
);
$config = Factory::getConfiguration();
$installerKey = $config->get('akeeba.advanced.embedded_installer');
$installerDescriptors = Factory::getEngineParamsProvider()->getInstallerList();
if (array_key_exists($installerKey, $installerDescriptors))
{
// The selected installer exists, use it
$this->installerSettings = (object)$installerDescriptors[$installerKey];
}
elseif (array_key_exists('angie', $installerDescriptors))
{
// The selected installer doesn't exist, but ANGIE exists; use that instead
$this->installerSettings = (object)$installerDescriptors['angie'];
}
}
/**
* Runs the preparation for this part. Should set _isPrepared
* to true
*
* @return void
*/
abstract protected function _prepare();
/**
* Runs the finalisation process for this part. Should set
* _isFinished to true.
*
* @return void
*/
abstract protected function _finalize();
/**
* Runs the main functionality loop for this part. Upon calling,
* should set the _isRunning to true. When it finished, should set
* the _hasRan to true. If an error is encountered, setError should
* be used.
*
* @return void
*/
abstract protected function _run();
/**
* Sets the BREAKFLAG, which instructs this engine part that the current step must break immediately,
* in fear of timing out.
*
* @return void
*/
protected function setBreakFlag()
{
$registry = Factory::getConfiguration();
$registry->set('volatile.breakflag', true);
}
/**
* Sets the engine part's internal state, in an easy to use manner
*
* @param string $state One of init, prepared, running, postrun, finished, error
* @param string $errorMessage The reported error message, should the state be set to error
*
* @return void
*/
protected function setState($state = 'init', $errorMessage = 'Invalid setState argument')
{
switch ($state)
{
case 'init':
$this->isPrepared = false;
$this->isRunning = false;
$this->isFinished = false;
$this->hasRan = false;
break;
case 'prepared':
$this->isPrepared = true;
$this->isRunning = false;
$this->isFinished = false;
$this->hasRan = false;
break;
case 'running':
$this->isPrepared = true;
$this->isRunning = true;
$this->isFinished = false;
$this->hasRan = false;
break;
case 'postrun':
$this->isPrepared = true;
$this->isRunning = false;
$this->isFinished = false;
$this->hasRan = true;
break;
case 'finished':
$this->isPrepared = true;
$this->isRunning = false;
$this->isFinished = true;
$this->hasRan = false;
break;
case 'error':
default:
$this->setError($errorMessage);
break;
}
}
/**
* The public interface to an engine part. This method takes care for
* calling the correct method in order to perform the initialisation -
* run - finalisation cycle of operation and return a proper response array.
*
* @param int $nesting
*
* @return array A response array
*/
public function tick($nesting = 0)
{
$this->waitTimeMsec = 0;
$configuration = Factory::getConfiguration();
$timer = Factory::getTimer();
// Call the right action method, depending on engine part state
switch ($this->getState())
{
case "init":
$this->_prepare();
break;
case "prepared":
$this->_run();
break;
case "running":
$this->_run();
break;
case "postrun":
$this->_finalize();
break;
}
// If there is still time, we are not finished and there is no break flag set, re-run the tick()
// method.
$breakFlag = $configuration->get('volatile.breakflag', false);
if (
!in_array($this->getState(), array('finished', 'error')) &&
($timer->getTimeLeft() > 0) &&
!$breakFlag &&
($nesting < 20) &&
($this->nest_logging)
)
{
// Nesting is only applied if $this->nest_logging == true (currently only Kettenrad has this)
$nesting++;
if ($this->nest_logging)
{
Factory::getLog()->log(LogLevel::DEBUG, "*** Batching successive steps (nesting level $nesting)");
}
$out = $this->tick($nesting);
}
else
{
// Return the output array
$out = $this->_makeReturnTable();
// Things to do for nest-logged parts (currently, only Kettenrad is)
if ($this->nest_logging)
{
if ($breakFlag)
{
Factory::getLog()->log(LogLevel::DEBUG, "*** Engine steps batching: Break flag detected.");
}
// Reset the break flag
$configuration->set('volatile.breakflag', false);
// Log that we're breaking the step
Factory::getLog()->log(LogLevel::DEBUG, "*** Batching of engine steps finished. I will now return control to the caller.");
// Do I need client-side sleep?
$serverSideSleep = true;
if (method_exists($this, 'getTag'))
{
$tag = $this->getTag();
$clientSideSleep = Factory::getConfiguration()->get('akeeba.basic.clientsidewait', 0);
if (in_array($tag, array('backend', 'restorepoint')) && $clientSideSleep)
{
$serverSideSleep = false;
}
}
// Enforce minimum execution time
if (!$this->ignoreMinimumExecutionTime)
{
$timer = Factory::getTimer();
$this->waitTimeMsec = (int)$timer->enforce_min_exec_time(true, $serverSideSleep);
}
}
}
// Send a Return Table back to the caller
return $out;
}
/**
* Returns a copy of the class's status array
*
* @return array The response array
*/
public function getStatusArray()
{
return $this->_makeReturnTable();
}
/**
* Sends any kind of setup information to the engine part. Using this,
* we avoid passing parameters to the constructor of the class. These
* parameters should be passed as an indexed array and should be taken
* into account during the preparation process only. This function will
* set the error flag if it's called after the engine part is prepared.
*
* @param array $parametersArray The parameters to be passed to the engine part.
*
* @return void
*/
public function setup($parametersArray)
{
if ($this->isPrepared)
{
$this->setState('error', get_class($this) . ":: Can't modify configuration after the preparation of " . $this->active_domain);
}
else
{
$this->_parametersArray = $parametersArray;
if (array_key_exists('root', $parametersArray))
{
$this->databaseRoot = $parametersArray['root'];
}
}
}
/**
* Returns the state of this engine part.
*
* @return string The state of this engine part. It can be one of error, init, prepared, running, postrun,
* finished.
*/
public function getState()
{
if ($this->getError())
{
return "error";
}
if (!($this->isPrepared))
{
return "init";
}
if (!($this->isFinished) && !($this->isRunning) && !($this->hasRan) && ($this->isPrepared))
{
return "prepared";
}
if (!($this->isFinished) && $this->isRunning && !($this->hasRan))
{
return "running";
}
if (!($this->isFinished) && !($this->isRunning) && $this->hasRan)
{
return "postrun";
}
if ($this->isFinished)
{
return "finished";
}
}
/**
* Constructs a Response Array based on the engine part's state.
*
* @return array The Response Array for the current state
*/
protected function _makeReturnTable()
{
// Get a list of warnings
$warnings = $this->getWarnings();
// Report only new warnings if there is no warnings queue size
if ($this->_warnings_queue_size == 0)
{
if (($this->warnings_pointer > 0) && ($this->warnings_pointer < (count($warnings))))
{
$warnings = array_slice($warnings, $this->warnings_pointer + 1);
$this->warnings_pointer += count($warnings);
}
else
{
$this->warnings_pointer = count($warnings);
}
}
$out = array(
'HasRun' => (!($this->isFinished)),
'Domain' => $this->active_domain,
'Step' => $this->active_step,
'Substep' => $this->active_substep,
'Error' => $this->getError(),
'Warnings' => $warnings
);
return $out;
}
/**
* Set the current domain of the engine
*
* @param string $new_domain The domain to set
*
* @return void
*/
protected function setDomain($new_domain)
{
$this->active_domain = $new_domain;
}
/**
* Get the current domain of the engine
*
* @return string The current domain
*/
public function getDomain()
{
return $this->active_domain;
}
/**
* Set the current step of the engine
*
* @param string $new_step The step to set
*
* @return void
*/
protected function setStep($new_step)
{
$this->active_step = $new_step;
}
/**
* Get the current step of the engine
*
* @return string The current step
*/
public function getStep()
{
return $this->active_step;
}
/**
* Set the current sub-step of the engine
*
* @param string $new_substep The sub-step to set
*
* @return void
*/
protected function setSubstep($new_substep)
{
$this->active_substep = $new_substep;
}
/**
* Get the current sub-step of the engine
*
* @return string The current sub-step
*/
public function getSubstep()
{
return $this->active_substep;
}
/**
* Implement this if your Engine Part can return the percentage of its work already complete
*
* @return float A number from 0 (nothing done) to 1 (all done)
*/
public function getProgress()
{
return 0;
}
/**
* @return boolean
*/
public function isIgnoreMinimumExecutionTime()
{
return $this->ignoreMinimumExecutionTime;
}
/**
* @param boolean $ignoreMinimumExecutionTime
*/
public function setIgnoreMinimumExecutionTime($ignoreMinimumExecutionTime)
{
$this->ignoreMinimumExecutionTime = $ignoreMinimumExecutionTime;
}
}