Skip to content

Commit

Permalink
Merge pull request #6221 from piwik/component_factory
Browse files Browse the repository at this point in the history
Refs #6078, extract factory logic from Report::factory and move to ComponentFactory utility class. Also reuse in Dimension to allow creating Dimension instances by human readable string IDs.
  • Loading branch information
Benaka committed Sep 15, 2014
2 parents 451f607 + 718c1bb commit d0b5527
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 168 deletions.
43 changes: 43 additions & 0 deletions core/Columns/Dimension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*/
namespace Piwik\Columns;

use Exception;
use Piwik\Plugin\ComponentFactory;
use Piwik\Plugin\Dimension\ActionDimension;
use Piwik\Plugin\Dimension\ConversionDimension;
use Piwik\Plugin\Dimension\VisitDimension;
Expand All @@ -20,6 +22,8 @@
*/
abstract class Dimension
{
const COMPONENT_SUBNAMESPACE = 'Columns';

// TODO that we have quite a few @ignore in public methods might show we should maybe split some code into two
// classes.

Expand Down Expand Up @@ -136,6 +140,31 @@ public function getName()
return '';
}

/**
* Returns a unique string ID for this dimension. The ID is built using the namespaced class name
* of the dimension, but is modified to be more human readable
*
* @return string eg, `"Referrers.Keywords"`
* @throws Exception if the plugin and simple class name of this instance cannot be determined.
* This would only happen if the dimension is located in the wrong directory.
* @api
*/
public function getId()
{
$className = get_class($this);

// parse plugin name & dimension name
$regex = "/Piwik\\\\Plugins\\\\([^\\\\]+)\\\\" . self::COMPONENT_SUBNAMESPACE . "\\\\([^\\\\]+)/";
if (!preg_match($regex, $className, $matches)) {
throw new Exception("'$className' is located in the wrong directory.");
}

$pluginName = $matches[1];
$dimensionName = $matches[2];

return $pluginName . '.' . $dimensionName;
}

/**
* Gets an instance of all available visit, action and conversion dimension.
* @return Dimension[]
Expand All @@ -158,4 +187,18 @@ public static function getAllDimensions()

return $dimensions;
}

/**
* Creates a Dimension instance from a string ID (see {@link getId()}).
*
* @param string $dimensionId See {@link getId()}.
* @return Dimension|null The created instance or null if there is no Dimension for
* $dimensionId or if the plugin that contains the Dimension is
* not loaded.
*/
public static function factory($dimensionId)
{
list($module, $dimension) = explode('.', $dimensionId);
return ComponentFactory::factory($module, $dimension, __CLASS__);
}
}
68 changes: 68 additions & 0 deletions core/Plugin/ComponentFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugin;

use Piwik\Log;
use Piwik\Plugin\Manager as PluginManager;
use Exception;

/**
* Factory class with methods to find and instantiate Plugin components.
*/
class ComponentFactory
{
/**
* Create a component instance that exists within a specific plugin. Uses the component's
* unqualified class name and expected base type.
*
* This method will only create a class if it is located within the component type's
* associated subdirectory.
*
* @param string $pluginName The name of the plugin the component is expected to belong to,
* eg, `'UserSettings'`.
* @param string $componentClassSimpleName The component's class name w/o namespace, eg,
* `"GetKeywords"`.
* @param string $componentTypeClass The fully qualified class name of the component type, eg,
* `"Piwik\Plugin\Report"`.
* @return mixed|null A new instance of the desired component or null if not found. If the
* plugin is not loaded or activated or the component is not located in
* in the sub-namespace specified by `$componentTypeClass::COMPONENT_SUBNAMESPACE`,
* this method will return null.
*/
public static function factory($pluginName, $componentClassSimpleName, $componentTypeClass)
{
if (empty($pluginName) || empty($componentClassSimpleName)) {
return null;
}

$pluginManager = PluginManager::getInstance();

try {
if (!$pluginManager->isPluginActivated($pluginName)) {
return null;
}

$plugin = $pluginManager->getLoadedPlugin($pluginName);
} catch (Exception $e) {
Log::debug($e);

return null;
}

$subnamespace = $componentTypeClass::COMPONENT_SUBNAMESPACE;
$desiredComponentClass = 'Piwik\\Plugins\\' . $pluginName . '\\' . $subnamespace . '\\' . $componentClassSimpleName;

$components = $plugin->findMultipleComponents($subnamespace, $componentTypeClass);
foreach ($components as $class) {
if ($class == $desiredComponentClass) {
return new $class();
}
}
return null;
}
}
31 changes: 6 additions & 25 deletions core/Plugin/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
*/
class Report
{
/**
* The sub-namespace name in a plugin where Report components are stored.
*/
const COMPONENT_SUBNAMESPACE = 'Reports';

/**
* The name of the module which is supposed to be equal to the name of the plugin. The module is detected
* automatically.
Expand Down Expand Up @@ -579,31 +584,7 @@ public function getActionToLoadSubTables()
*/
public static function factory($module, $action)
{
if (empty($module) || empty($action)) {
return;
}

$pluginManager = PluginManager::getInstance();

try {
if (!$pluginManager->isPluginActivated($module)) {
return;
}

$plugin = $pluginManager->getLoadedPlugin($module);

} catch (Exception $e) {
return;
}

$reports = $plugin->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report');
$action = ucfirst($action);

foreach ($reports as $reportClass) {
if ($reportClass == 'Piwik\\Plugins\\' . $module . '\\Reports\\' . $action) {
return new $reportClass();
}
}
return ComponentFactory::factory($module, ucfirst($action), __CLASS__);
}

/**
Expand Down
Loading

0 comments on commit d0b5527

Please sign in to comment.