[ticket/14703] Refine the parent module selection for custom extension modules

PHPBB3-14703
This commit is contained in:
rxu 2016-07-03 17:29:15 +07:00
parent a3c10f575b
commit 652e3da28d
2 changed files with 81 additions and 71 deletions

View file

@ -60,6 +60,8 @@ $lang = array_merge($lang, array(
'MIGRATION_INVALID_DATA_UNDEFINED_METHOD' => 'A migration is invalid. An undefined migration tool method was encountered.',
'MODULE_ERROR' => 'An error occurred while creating a module: %s',
'MODULE_EXISTS' => 'A module already exists: %s',
'MODULE_EXIST_MULTIPLE' => 'Several modules with the given parent module langname already exist: %s. Try using before/after keys to clarify the module placement.',
'MODULE_INFO_FILE_NOT_EXIST' => 'A required module info file is missing: %2$s',
'MODULE_NOT_EXIST' => 'A required module does not exist: %s',

View file

@ -36,6 +36,9 @@ class module implements \phpbb\db\migration\tool\tool_interface
/** @var string */
protected $modules_table;
/** @var array */
protected $module_categories = array();
/**
* Constructor
*
@ -87,31 +90,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
$parent_sql = '';
if ($parent !== false)
{
// Allows '' to be sent as 0
$parent = $parent ?: 0;
if (!is_numeric($parent))
{
$sql = 'SELECT module_id
FROM ' . $this->modules_table . "
WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
AND module_class = '" . $this->db->sql_escape($class) . "'
AND module_basename = ''";
$result = $this->db->sql_query($sql);
$module_id = $this->db->sql_fetchfield('module_id');
$this->db->sql_freeresult($result);
if (!$module_id)
{
return false;
}
$parent_sql = 'AND parent_id = ' . (int) $module_id;
}
else
{
$parent_sql = 'AND parent_id = ' . (int) $parent;
}
$parent = $this->get_parent_module_id($parent);
$parent_sql = 'AND parent_id = ' . (int) $parent;
}
$sql = 'SELECT module_id
@ -172,15 +152,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
*/
public function add($class, $parent = 0, $data = array())
{
// Allows '' to be sent as 0
$parent = $parent ?: 0;
// allow sending the name as a string in $data to create a category
if (!is_array($data))
{
$data = array('module_langname' => $data);
}
$parent = $data['parent_id'] = $this->get_parent_module_id($parent);
if (!isset($data['module_langname']))
{
// The "automatic" way
@ -211,34 +190,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
}
// The "manual" way
// More than 1 module with the same module_basename may exist
// Thus use empty module_basename to select a category as a parent
if (!is_numeric($parent))
{
$sql = 'SELECT module_id
FROM ' . $this->modules_table . "
WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
AND module_class = '" . $this->db->sql_escape($class) . "'
AND module_basename = ''";
$result = $this->db->sql_query($sql);
$module_id = $this->db->sql_fetchfield('module_id');
$this->db->sql_freeresult($result);
if (!$module_id)
{
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
}
$parent = $data['parent_id'] = $module_id;
}
else if (!$this->exists($class, false, $parent))
if (!$this->exists($class, false, $parent))
{
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
}
if ($this->exists($class, $parent, $data['module_langname']))
{
return;
throw new \phpbb\db\migration\exception('MODULE_EXISTS', $module_id);
}
if (!class_exists('acp_modules'))
@ -377,27 +336,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
$parent_sql = '';
if ($parent !== false)
{
// Allows '' to be sent as 0
$parent = ($parent) ?: 0;
if (!is_numeric($parent))
{
$sql = 'SELECT module_id
FROM ' . $this->modules_table . "
WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
AND module_class = '" . $this->db->sql_escape($class) . "'
AND module_basename = ''";
$result = $this->db->sql_query($sql);
$module_id = $this->db->sql_fetchfield('module_id');
$this->db->sql_freeresult($result);
// we know it exists from the module_exists check
$parent_sql = 'AND parent_id = ' . (int) $module_id;
}
else
{
$parent_sql = 'AND parent_id = ' . (int) $parent;
}
$parent = $this->get_parent_module_id($parent);
$parent_sql = 'AND parent_id = ' . (int) $parent;
}
$module_ids = array();
@ -492,4 +432,72 @@ class module implements \phpbb\db\migration\tool\tool_interface
return array_pop($module);
}
/**
* Get the list of installed module categories
* key - module_langname
* value - module_id
*
* @return null
*/
protected function get_categories_list()
{
// Select the top level categories
// and 2nd level [sub]categories which exist for ACP only
$sql = 'SELECT m2.module_id, m2.module_langname
FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
WHERE m1.parent_id = 0
AND (m1.module_id = m2.module_id
OR m2.module_class = 'acp' AND m2.parent_id = m1.module_id)
ORDER BY m1.module_id, m2.module_id ASC";
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$this->module_categories[(int) $row['module_id']] = $row['module_langname'];
}
$this->db->sql_freeresult($result);
}
/**
* Get parent module id
*
* @param string|int $parent_id The parent module_id|module_langname
* @return int The parent module_id
* @throws \phpbb\db\migration\exception
*/
public function get_parent_module_id($parent_id)
{
// Allow '' to be sent as 0
$parent_id = $parent_id ?: 0;
if (!is_numeric($parent_id))
{
// Refresh the $module_categories array
$this->get_categories_list();
// Search for the parent module_langname
$ids = array_keys($this->module_categories, $parent_id);
switch (sizeof($ids))
{
// No parent with the given module_langname exist
case 0:
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
break;
// Return the module id
case 1:
$parent_id = (int) $ids[0];
break;
// Several modules with the given module_langname were found
default:
throw new \phpbb\db\migration\exception('MODULE_EXIST_MULTIPLE', $parent_id);
break;
}
}
return $parent_id;
}
}