1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-03-21 08:00:46 +01:00

Merge pull request #3909 from Nicofuma/ticket/11150

[ticket/11150] Install extensions through composer
This commit is contained in:
Marc Alexander 2017-04-26 09:49:37 -04:00
commit 2cf47ffaa1
No known key found for this signature in database
GPG Key ID: 50E0D2423696F995
53 changed files with 3951 additions and 96 deletions

4
.gitignore vendored
View File

@ -19,6 +19,10 @@
!/phpBB/styles/all
node_modules
/phpBB/vendor
/phpBB/vendor-ext/*
!/phpBB/vendor-ext/.git-keep
/phpBB/composer-ext.json
/phpBB/composer-ext.lock
/tests/phpbb_unit_tests.sqlite*
/tests/test_config*.php
/tests/tmp/*

View File

@ -95,6 +95,7 @@
--ignore=${project.basedir}/phpBB/install/database_update.php
--ignore=${project.basedir}/phpBB/phpbb/*
--ignore=${project.basedir}/phpBB/vendor/*
--ignore=${project.basedir}/phpBB/vendor-ext/*
phpBB"
dir="." returnProperty="retval-php-legacy" passthru="true" />
<exec command="phpBB/vendor/bin/phpcs

View File

@ -0,0 +1,130 @@
{% include('overall_header.html') %}
<a id="maincontent"></a>
<h1>{{ lang( 'EXTENSIONS_CATALOG') }}</h1>
<p>{{ lang( 'EXTENSIONS_CATALOG_EXPLAIN') }}</p>
<fieldset class="quick quick-left">
<span class="small"><a href="https://www.phpbb.com/go/customise/extensions/{{ PHPBB_MAJOR }}" target="_blank">{{ lang('BROWSE_EXTENSIONS_DATABASE') }}</a> &bull; <a href="javascript:phpbb.toggleDisplay('catalog_settings');">{{ lang('SETTINGS') }}</a></span>
</fieldset>
{% if pagination is defined %}
<div class="pagination top-pagination">
{% include('pagination.html') %}
</div>
{% endif %}
<form id="catalog_settings" method="post" action="{{ U_ACTION }}" style="display:none">
<fieldset style="clear: both;">
<legend>{{ lang('EXTENSIONS_CATALOG_SETTINGS') }}</legend>
<dl>
<dt><label for="enable_on_install">{{ lang('ENABLE_ON_INSTALL') }}{{ lang('COLON') }}</label></dt>
<dd>
<label><input type="radio" id="enable_on_install" name="enable_on_install" class="radio" value="1"{% if settings.enable_on_install %} checked="checked" {% endif %} /> {{ lang('YES') }}</label>
<label><input type="radio" name="enable_on_install" class="radio" value="0"{% if not settings.enable_on_install %} checked="checked" {% endif %} /> {{ lang('NO') }}</label>
</dd>
</dl>
<dl>
<dt><label for="purge_on_remove">{{ lang('PURGE_ON_REMOVE') }}{{ lang('COLON') }}</label></dt>
<dd>
<label><input type="radio" id="purge_on_remove" name="purge_on_remove" class="radio" value="1"{% if settings.purge_on_remove %} checked="checked" {% endif %} /> {{ lang('YES') }}</label>
<label><input type="radio" name="purge_on_remove" class="radio" value="0"{% if not settings.purge_on_remove %} checked="checked" {% endif %} /> {{ lang('NO') }}</label>
</dd>
</dl>
<dl>
<dt>
<label for="repositories">{{ lang('COMPOSER_REPOSITORIES') }}{{ lang('COLON') }}</label><br />
<span class="explain">
{{ lang('COMPOSER_REPOSITORIES_EXPLAIN') }}
</span>
</dt>
<dd>
<textarea id="repositories" name="repositories" rows="5" cols="30">{{ settings.repositories|join('\n') }}</textarea>
</dd>
</dl>
<dl>
<dt>
<label for="enable_packagist">{{ lang('ENABLE_PACKAGIST') }}{{ lang('COLON') }}</label><br />
<span class="explain">
<strong class="error">{{ lang('WARNING') }}{{ lang('COLON') }}</strong> {{ lang('ENABLE_PACKAGIST_EXPLAIN') }}
</span>
</dt>
<dd>
<label><input type="radio" id="enable_packagist" name="enable_packagist" class="radio" value="1"{% if settings.enable_packagist %} checked="checked" {% endif %} /> {{ lang('YES') }}</label>
<label><input type="radio" name="enable_packagist" class="radio" value="0"{% if not settings.enable_packagist %} checked="checked" {% endif %} /> {{ lang('NO') }}</label>
</dd>
</dl>
<dl>
<dt>
<label for="minimum_stability">{{ lang('COMPOSER_MINIMUM_STABILITY') }}{{ lang('COLON') }}</label><br />
<span class="explain">
<strong class="error">{{ lang('WARNING') }}{{ lang('COLON') }}</strong> {{ lang('COMPOSER_MINIMUM_STABILITY_EXPLAIN') }}
</span>
</dt>
<dd>
<select id="minimum_stability" name="minimum_stability">
{% for stability in settings.stabilities %}
<option value="{{ stability }}"{% if stability === settings.minimum_stability %} selected='selected'{% endif %}>{{ lang('STABILITY_' ~ stability|upper) }}</option>
{% endfor %}
</select>
</dd>
</dl>
<p class="submit-buttons">
<input class="button1" type="submit" name="update" value="{{ lang('SUBMIT') }}" />&nbsp;
<input class="button2" type="reset" name="reset" value="{{ lang('RESET') }}" />
<input type="hidden" name="action" value="set_catalog_settings" />
{{ S_FORM_TOKEN }}
</p>
</fieldset>
</form>
{% if extensions is empty %}
<tr>
<td colspan="4"><div class="errorbox notice">{{ lang('NO_EXTENSION_AVAILABLE') }}</div></td>
</tr>
{% else %}
<table class="table1">
<col class="row1" ><col class="row1" ><col class="row1" ><col class="row2" >
<thead>
<tr>
<th style="width: 25%;">{{ lang("EXTENSION_NAME") }}</th>
<th style="text-align: center; width: 10%;">{{ lang("VERSION") }}</th>
<th>{{ lang("DESCRIPTION") }}</th>
<th style="text-align: center; width: 15%;">{{ lang("EXTENSION_ACTIONS") }}</th>
</tr>
</thead>
<tbody>
{% for extension in extensions %}
<tr>
<td>
<strong>{{ extension.display_name }}</strong><br />
{{ extension.name }}
</td>
<td style="text-align: center">{{ extension.version }}</td>
<td>{{ extension.description }} &bull; <a href="{{ extension.url }}">{{ lang('HOMEPAGE') }}</a></td>
<td style="text-align: center">
{% if extension.name in managed_extensions %}
<span style="color: #228822;">{{ lang('INSTALLED') }}</span>
{% elseif extension.name in installed_extensions -%}
<span style="color: #BC2A4D;">{{ lang('INSTALLED_MANUALLY') }}</span>
(<a href="{{ U_ACTION }}&amp;action=manage&amp;extension={{ extension.composer_name|url_encode }}">{{ lang('MANAGE') }}</a>)
{% elseif not enabled -%}
<a href="{{ U_ACTION }}&amp;action=install&amp;extension={{ extension.composer_name|url_encode }}">{{ lang('INSTALL') }}</a>
{%- endif -%}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if pagination is defined %}
<div class="pagination bottom-pagination">
{% include('pagination.html') %}
</div>
{% endif %}
{% include('overall_footer.html') %}

View File

@ -7,7 +7,7 @@
<p>{L_EXTENSIONS_EXPLAIN}</p>
<fieldset class="quick">
<span class="small"><a href="https://www.phpbb.com/go/customise/extensions/3.1" target="_blank">{L_BROWSE_EXTENSIONS_DATABASE}</a> &bull; <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE_ALL}</a> &bull; <a href="javascript:phpbb.toggleDisplay('version_check_settings');">{L_SETTINGS}</a></span>
<span class="small"><a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE_ALL}</a> &bull; <a href="javascript:phpbb.toggleDisplay('version_check_settings');">{L_SETTINGS}</a></span>
</fieldset>
<form id="version_check_settings" method="post" action="{U_ACTION}" style="display:none">
@ -59,7 +59,7 @@
<td style="text-align: center;"><a href="{enabled.U_DETAILS}">{L_DETAILS}</a></td>
<td style="text-align: center;">
<!-- BEGIN actions -->
<a href="{enabled.actions.U_ACTION}"<!-- IF enabled.actions.L_ACTION_EXPLAIN --> title="{enabled.actions.L_ACTION_EXPLAIN}"<!-- ENDIF -->>{enabled.actions.L_ACTION}</a>
<a href="{enabled.actions.U_ACTION}"<!-- IF enabled.actions.L_ACTION_EXPLAIN --> title="{enabled.actions.L_ACTION_EXPLAIN}"<!-- ENDIF --><!-- IF enabled.actions.COLOR --> style="color: {enabled.actions.COLOR};"<!-- ENDIF -->>{enabled.actions.L_ACTION}</a>
<!-- IF not enabled.actions.S_LAST_ROW -->&nbsp;|&nbsp;<!-- ENDIF -->
<!-- END actions -->
</td>
@ -86,7 +86,7 @@
</td>
<td style="text-align: center;">
<!-- BEGIN actions -->
<a href="{disabled.actions.U_ACTION}"<!-- IF disabled.actions.L_ACTION_EXPLAIN --> title="{disabled.actions.L_ACTION_EXPLAIN}"<!-- ENDIF -->>{disabled.actions.L_ACTION}</a>
<a href="{disabled.actions.U_ACTION}"<!-- IF disabled.actions.L_ACTION_EXPLAIN --> title="{disabled.actions.L_ACTION_EXPLAIN}"<!-- ENDIF --><!-- IF disabled.actions.COLOR --> style="color: {disabled.actions.COLOR};"<!-- ENDIF -->>{disabled.actions.L_ACTION}</a>
<!-- IF not disabled.actions.S_LAST_ROW -->&nbsp;|&nbsp;<!-- ENDIF -->
<!-- END actions -->
</td>

View File

@ -1333,6 +1333,18 @@ p.quick {
text-align: left;
}
fieldset.quick-left,
p.quick-left {
float: left;
margin: 15px 0 5px;
padding: 0;
}
.rtl fieldset.quick-left,
.rtl p.quick-left {
float: right;
}
fieldset.quick legend {
display: none;
}
@ -2959,3 +2971,10 @@ fieldset.permissions .permissions-switch {
/* stylelint-enable selector-no-qualifying-type */
/* stylelint-enable declaration-property-unit-blacklist */
/* stylelint-enable declaration-property-unit-whitelist */
.console-output {
font-family: monospace;
background-color: #2a2a2a;
color: #f1f1f1;
overflow-x: scroll;
}

View File

@ -0,0 +1,14 @@
<!-- INCLUDE overall_header.html -->
<div {% if S_USER_NOTICE %}class="successbox"{% else %}class="errorbox"{% endif %}>
<h3>{{ MESSAGE_TITLE }}</h3>
<p>{{ MESSAGE_TEXT }}</p>
</div>
<div>
<fieldset class="console-output">
<pre>{{ MESSAGE_DETAIL }}</pre>
</fieldset>
</div>
<!-- INCLUDE overall_footer.html -->

View File

@ -71,6 +71,11 @@ require($phpbb_root_path . 'includes/compatibility_globals.' . $phpEx);
register_compatibility_globals();
if (@is_file($phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php'))
{
require_once($phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php');
}
/** @var \phpbb\language\language $language */
$language = $phpbb_container->get('language');
$language->add_lang(array('common', 'acp/common', 'cli'));

View File

@ -141,6 +141,11 @@ require($phpbb_root_path . 'includes/compatibility_globals.' . $phpEx);
register_compatibility_globals();
if (@is_file($phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php'))
{
require_once($phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php');
}
// Add own hook handler
require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
$phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));

0
phpBB/composer-ext.json Normal file
View File

0
phpBB/composer-ext.lock Normal file
View File

View File

@ -27,6 +27,7 @@
"require": {
"php": ">=5.5.9",
"bantu/ini-get-wrapper": "1.0.*",
"composer/composer": "^1.0",
"google/recaptcha": "~1.1",
"guzzlehttp/guzzle": "~6.2",
"lusitanian/oauth": "^0.8.1",

563
phpBB/composer.lock generated
View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "c53f2fa544168309d695bb1855c98c24",
"content-hash": "4bc93e90a4852f936c13986c3823831b",
"hash": "fb27e08d4d657b78f87a3327a41d9e20",
"content-hash": "274c9cfc16d9a9cd40daffe7383d568a",
"packages": [
{
"name": "bantu/ini-get-wrapper",
@ -37,6 +37,263 @@
"description": "Convenience wrapper around ini_get()",
"time": "2014-09-15 13:12:35"
},
{
"name": "composer/ca-bundle",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
"reference": "5df9ed0ed0c9506ea6404a23450854e5df15cc12"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/5df9ed0ed0c9506ea6404a23450854e5df15cc12",
"reference": "5df9ed0ed0c9506ea6404a23450854e5df15cc12",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"ext-pcre": "*",
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"symfony/process": "^2.5 || ^3.0"
},
"suggest": {
"symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\CaBundle\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
"keywords": [
"cabundle",
"cacert",
"certificate",
"ssl",
"tls"
],
"time": "2016-07-18 23:07:53"
},
{
"name": "composer/composer",
"version": "1.3.3",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
"reference": "989d68725bc8ebf97e795d4feb386f52adb096e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/composer/zipball/989d68725bc8ebf97e795d4feb386f52adb096e3",
"reference": "989d68725bc8ebf97e795d4feb386f52adb096e3",
"shasum": ""
},
"require": {
"composer/ca-bundle": "^1.0",
"composer/semver": "^1.0",
"composer/spdx-licenses": "^1.0",
"justinrainbow/json-schema": "^1.6 || ^2.0 || ^3.0 || ^4.0",
"php": "^5.3.2 || ^7.0",
"psr/log": "^1.0",
"seld/cli-prompt": "^1.0",
"seld/jsonlint": "^1.4",
"seld/phar-utils": "^1.0",
"symfony/console": "^2.7 || ^3.0",
"symfony/filesystem": "^2.7 || ^3.0",
"symfony/finder": "^2.7 || ^3.0",
"symfony/process": "^2.7 || ^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5",
"phpunit/phpunit-mock-objects": "^2.3 || ^3.0"
},
"suggest": {
"ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
"ext-zip": "Enabling the zip extension allows you to unzip archives",
"ext-zlib": "Allow gzip compression of HTTP requests"
},
"bin": [
"bin/composer"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\": "src/Composer"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.",
"homepage": "https://getcomposer.org/",
"keywords": [
"autoload",
"dependency",
"package"
],
"time": "2017-03-08 10:06:43"
},
{
"name": "composer/semver",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5",
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"keywords": [
"semantic",
"semver",
"validation",
"versioning"
],
"time": "2016-08-30 16:08:34"
},
{
"name": "composer/spdx-licenses",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/composer/spdx-licenses.git",
"reference": "88c26372b1afac36d8db601cdf04ad8716f53d88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/88c26372b1afac36d8db601cdf04ad8716f53d88",
"reference": "88c26372b1afac36d8db601cdf04ad8716f53d88",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5",
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Spdx\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "SPDX licenses list and validation library.",
"keywords": [
"license",
"spdx",
"validator"
],
"time": "2016-05-04 12:27:30"
},
{
"name": "google/recaptcha",
"version": "1.1.2",
@ -253,6 +510,72 @@
],
"time": "2016-06-24 23:00:38"
},
{
"name": "justinrainbow/json-schema",
"version": "2.0.5",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/6b2a33e6a768f96bdc2ead5600af0822eed17d67",
"reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"json-schema/json-schema-test-suite": "1.2.0",
"phpdocumentor/phpdocumentor": "~2",
"phpunit/phpunit": "^4.8.22"
},
"bin": [
"bin/validate-json"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bruno Prieto Reis",
"email": "bruno.p.reis@gmail.com"
},
{
"name": "Justin Rainbow",
"email": "justin.rainbow@gmail.com"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Robert Schönthal",
"email": "seroscho@googlemail.com"
}
],
"description": "A library to validate a json schema.",
"homepage": "https://github.com/justinrainbow/json-schema",
"keywords": [
"json",
"schema"
],
"time": "2016-06-02 10:59:52"
},
{
"name": "lusitanian/oauth",
"version": "v0.8.10",
@ -703,6 +1026,144 @@
],
"time": "2017-01-22 17:12:21"
},
{
"name": "seld/cli-prompt",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/cli-prompt.git",
"reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4",
"reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Seld\\CliPrompt\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type",
"keywords": [
"cli",
"console",
"hidden",
"input",
"prompt"
],
"time": "2016-04-18 09:31:41"
},
{
"name": "seld/jsonlint",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/jsonlint.git",
"reference": "66834d3e3566bb5798db7294619388786ae99394"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394",
"reference": "66834d3e3566bb5798db7294619388786ae99394",
"shasum": ""
},
"require": {
"php": "^5.3 || ^7.0"
},
"bin": [
"bin/jsonlint"
],
"type": "library",
"autoload": {
"psr-4": {
"Seld\\JsonLint\\": "src/Seld/JsonLint/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "JSON Linter",
"keywords": [
"json",
"linter",
"parser",
"validator"
],
"time": "2015-11-21 02:21:41"
},
{
"name": "seld/phar-utils",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/phar-utils.git",
"reference": "7009b5139491975ef6486545a39f3e6dad5ac30a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a",
"reference": "7009b5139491975ef6486545a39f3e6dad5ac30a",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Seld\\PharUtils\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "PHAR file format utilities, for when PHP phars you up",
"keywords": [
"phra"
],
"time": "2015-10-13 18:44:15"
},
{
"name": "symfony/config",
"version": "v3.2.0",
@ -1294,6 +1755,55 @@
],
"time": "2016-11-14 01:06:16"
},
{
"name": "symfony/process",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/04c2dfaae4ec56a5c677b0c69fac34637d815758",
"reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2016-07-28 11:13:48"
},
{
"name": "symfony/proxy-manager-bridge",
"version": "v3.2.0",
@ -3231,55 +3741,6 @@
"homepage": "https://symfony.com",
"time": "2016-11-25 12:32:42"
},
{
"name": "symfony/process",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "02ea84847aad71be7e32056408bb19f3a616cdd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/02ea84847aad71be7e32056408bb19f3a616cdd3",
"reference": "02ea84847aad71be7e32056408bb19f3a616cdd3",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2016-11-24 10:40:28"
},
{
"name": "webmozart/assert",
"version": "1.2.0",

View File

@ -8,6 +8,7 @@ imports:
- { resource: services_cron.yml }
- { resource: services_db.yml }
- { resource: services_event.yml }
- { resource: services_extensions.yml }
- { resource: services_feed.yml }
- { resource: services_files.yml }
- { resource: services_filesystem.yml }
@ -98,18 +99,6 @@ services:
- '%core.root_path%'
- '@template'
ext.manager:
class: phpbb\extension\manager
arguments:
- '@service_container'
- '@dbal.conn'
- '@config'
- '@filesystem'
- '%tables.ext%'
- '%core.root_path%'
- '%core.php_ext%'
- '@cache'
file_downloader:
class: phpbb\file_downloader

View File

@ -141,6 +141,33 @@ services:
tags:
- { name: console.command }
console.command.extension.install:
class: phpbb\console\command\extension\install
arguments:
- '@user'
- '@ext.composer.manager'
- '@language'
tags:
- { name: console.command }
console.command.extension.list_available:
class: phpbb\console\command\extension\list_available
arguments:
- '@user'
- '@ext.composer.manager'
- '@language'
tags:
- { name: console.command }
console.command.extension.manage:
class: phpbb\console\command\extension\manage
arguments:
- '@user'
- '@ext.composer.manager'
- '@language'
tags:
- { name: console.command }
console.command.extension.purge:
class: phpbb\console\command\extension\purge
arguments:
@ -150,6 +177,15 @@ services:
tags:
- { name: console.command }
console.command.extension.remove:
class: phpbb\console\command\extension\remove
arguments:
- '@user'
- '@ext.composer.manager'
- '@language'
tags:
- { name: console.command }
console.command.extension.show:
class: phpbb\console\command\extension\show
arguments:
@ -159,6 +195,15 @@ services:
tags:
- { name: console.command }
console.command.extension.update:
class: phpbb\console\command\extension\update
arguments:
- '@user'
- '@ext.composer.manager'
- '@language'
tags:
- { name: console.command }
console.command.fixup.recalculate_email_hash:
class: phpbb\console\command\fixup\recalculate_email_hash
arguments:

View File

@ -0,0 +1,48 @@
services:
ext.manager:
class: phpbb\extension\manager
arguments:
- '@service_container'
- '@dbal.conn'
- '@config'
- '@filesystem'
- '%tables.ext%'
- '%core.root_path%'
- '%core.php_ext%'
- '@cache'
ext.composer.installer:
class: phpbb\composer\installer
arguments:
- '%core.root_path%'
- '@filesystem'
- '@request'
- '@config'
ext.composer.manager:
class: phpbb\composer\extension_manager
arguments:
- '@ext.composer.installer'
- '@cache.driver'
- '@ext.manager'
- '@filesystem'
- phpbb-extension
- EXTENSIONS_
- '%core.root_path%'
- '@config'
style.composer.manager:
class: phpbb\composer\manager
arguments:
- '@ext.composer.installer'
- '@cache.driver'
- phpbb-style
- STYLES_
lang.composer.manager:
class: phpbb\composer\manager
arguments:
- '@ext.composer.installer'
- '@cache.driver'
- phpbb-language
- LANGUAGES_

View File

@ -11,3 +11,7 @@ core:
debug: true
auto_reload: true
enable_debug_extension: true
extensions:
composer_debug: true
composer_verbose: true

View File

@ -99,6 +99,11 @@ if (isset($_GET['avatar']))
/* @var $phpbb_avatar_manager \phpbb\avatar\manager */
$phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
if (@is_file($phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php'))
{
require_once($phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php');
}
$filename = $request->variable('avatar', '');
$avatar_group = false;
$exit = false;

View File

@ -24,23 +24,32 @@ if (!defined('IN_PHPBB'))
class acp_extensions
{
var $u_action;
var $tpl_name;
var $page_title;
public $u_action;
private $db;
/** @var phpbb\config\config */
private $config;
/** @var \phpbb\template\twig\twig */
private $template;
private $user;
private $log;
/** @var \phpbb\request\request */
private $request;
private $phpbb_dispatcher;
private $ext_manager;
function main()
/** @var \phpbb\extension\manager */
private $ext_manager;
private $u_catalog_action;
function main($id, $mode)
{
// Start the page
global $config, $user, $template, $request, $phpbb_extension_manager, $phpbb_root_path, $phpbb_log, $phpbb_dispatcher;
global $config, $user, $template, $request, $phpbb_extension_manager, $db, $phpbb_log, $phpbb_dispatcher;
$this->db = $db;
$this->config = $config;
$this->template = $template;
$this->user = $user;
@ -49,7 +58,22 @@ class acp_extensions
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->ext_manager = $phpbb_extension_manager;
$this->user->add_lang(array('install', 'acp/extensions', 'migrator'));
$this->user->add_lang(['install', 'acp/extensions', 'migrator']);
switch ($mode)
{
case 'catalog':
$this->catalog_mode($id, $mode);
break;
default:
$this->main_mode($id, $mode);
break;
}
}
public function main_mode($id, $mode)
{
global $phpbb_extension_manager, $phpbb_container, $phpbb_admin_path, $phpEx;
$this->page_title = 'ACP_EXTENSIONS';
@ -110,6 +134,8 @@ class acp_extensions
}
}
$this->u_catalog_action = append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&amp;mode=catalog");
// What are we doing?
switch ($action)
{
@ -133,7 +159,7 @@ class acp_extensions
$this->config->set('extension_force_unstable', false);
trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
}
break;
break;
case 'list':
default:
@ -143,15 +169,27 @@ class acp_extensions
trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
}
$this->list_enabled_exts();
$this->list_disabled_exts();
$this->list_available_exts();
/** @var \phpbb\composer\manager $composer_manager */
$composer_manager = $phpbb_container->get('ext.composer.manager');
$managed_packages = [];
if ($composer_manager->check_requirements())
{
$managed_packages = $composer_manager->get_managed_packages();
}
$this->list_enabled_exts($phpbb_extension_manager, $managed_packages);
$this->list_disabled_exts($phpbb_extension_manager, $managed_packages);
$this->list_available_exts($phpbb_extension_manager, $managed_packages);
$this->template->assign_vars(array(
'U_VERSIONCHECK_FORCE' => $this->u_action . '&amp;action=list&amp;versioncheck_force=1',
'FORCE_UNSTABLE' => $this->config['extension_force_unstable'],
'U_ACTION' => $this->u_action,
'MANAGED_EXTENSIONS' => $managed_packages,
'U_CATALOG_ACTION' => $this->u_catalog_action,
));
$this->request->disable_super_globals();
$this->tpl_name = 'acp_ext_list';
break;
@ -382,11 +420,340 @@ class acp_extensions
}
/**
* Lists all the enabled extensions and dumps to the template
*
* @return null
*/
public function list_enabled_exts()
* Handles the catalog mode of the extensions list
*
* @param string $id
* @param string $mode
*/
public function catalog_mode($id, $mode)
{
global $phpbb_container;
$action = $this->request->variable('action', 'list');
/** @var \phpbb\language\language $language */
$language = $phpbb_container->get('language');
/** @var \phpbb\composer\manager $composer_manager */
$composer_manager = $phpbb_container->get('ext.composer.manager');
/** @var \phpbb\extension\manager $extensions_manager */
$extensions_manager = $phpbb_container->get('ext.manager');
if (!$composer_manager->check_requirements())
{
$this->page_title = 'ACP_EXTENSIONS_CATALOG';
$this->tpl_name = 'message_body';
$this->template->assign_vars([
'MESSAGE_TITLE' => $language->lang('EXTENSIONS_CATALOG_NOT_AVAILABLE'),
'MESSAGE_TEXT' => $language->lang('EXTENSIONS_COMPOSER_NOT_WRITABLE'),
]);
return;
}
switch ($action)
{
case 'install':
$this->page_title = 'ACP_EXTENSIONS_INSTALL';
$extension = $this->request->variable('extension', '');
if (empty($extension))
{
redirect($this->u_action);
}
$formatter = new \phpbb\composer\io\html_output_formatter([
'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow')
]);
$composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter);
try
{
$composer_manager->install((array) $extension, $composer_io);
}
catch (\phpbb\exception\runtime_exception $e)
{
$this->display_composer_exception($language, $e, $composer_io);
return;
}
$this->tpl_name = 'detailed_message_body';
$this->template->assign_vars(array(
'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_INSTALL'),
'MESSAGE_TEXT' => $language->lang('EXTENSIONS_INSTALLED') . adm_back_link($this->u_action),
'MESSAGE_DETAIL' => $composer_io->getOutput(),
'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'),
'S_USER_NOTICE' => true,
)
);
break;
case 'remove':
$this->page_title = 'ACP_EXTENSIONS_REMOVE';
$extension = $this->request->variable('extension', '');
if (empty($extension))
{
redirect($this->u_action);
}
$formatter = new \phpbb\composer\io\html_output_formatter([
'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow')
]);
$composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter);
try
{
$composer_manager->remove((array) $extension, $composer_io);
}
catch (\phpbb\exception\runtime_exception $e)
{
$this->display_composer_exception($language, $e, $composer_io);
return;
}
$this->tpl_name = 'detailed_message_body';
$this->template->assign_vars(array(
'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_REMOVE'),
'MESSAGE_TEXT' => $language->lang('EXTENSIONS_REMOVED') . adm_back_link($this->u_action),
'MESSAGE_DETAIL' => $composer_io->getOutput(),
'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'),
'S_USER_NOTICE' => true,
)
);
break;
case 'update':
$this->page_title = 'ACP_EXTENSIONS_UPDATE';
$extension = $this->request->variable('extension', '');
if (empty($extension))
{
redirect($this->u_action);
}
$formatter = new \phpbb\composer\io\html_output_formatter([
'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow')
]);
$composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter);
try
{
$composer_manager->update((array) $extension, $composer_io);
}
catch (\phpbb\exception\runtime_exception $e)
{
$this->display_composer_exception($language, $e, $composer_io);
return;
}
$this->tpl_name = 'detailed_message_body';
$this->template->assign_vars(array(
'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_UPDATE'),
'MESSAGE_TEXT' => $language->lang('EXTENSIONS_UPDATED') . adm_back_link($this->u_action),
'MESSAGE_DETAIL' => $composer_io->getOutput(),
'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'),
'S_USER_NOTICE' => true,
)
);
break;
case 'manage':
$this->page_title = 'ACP_EXTENSIONS_MANAGE';
$extension = $this->request->variable('extension', '');
if (empty($extension))
{
redirect($this->u_action);
}
$formatter = new \phpbb\composer\io\html_output_formatter([
'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow')
]);
$composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter);
try
{
$composer_manager->start_managing($extension, $composer_io);
}
catch (\phpbb\exception\runtime_exception $e)
{
$this->display_composer_exception($language, $e, $composer_io);
return;
}
$this->tpl_name = 'detailed_message_body';
$this->template->assign_vars(array(
'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_MANAGE'),
'MESSAGE_TEXT' => $language->lang('EXTENSION_MANAGED_SUCCESS', $extension) . adm_back_link($this->u_action),
'MESSAGE_DETAIL' => $composer_io->getOutput(),
'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'),
'S_USER_NOTICE' => true,
)
);
break;
case 'list':
default:
if (!$this->config['exts_composer_packagist'] && $this->request->is_set('enable_packagist') && confirm_box(true))
{
$this->config->set('exts_composer_packagist', true);
$composer_manager->reset_cache();
trigger_error($language->lang('CONFIG_UPDATED') . adm_back_link($this->u_action));
}
$submit = $this->request->is_set('update');
if ($submit)
{
if (!check_form_key('catalog_settings'))
{
trigger_error($language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING);
}
$enable_packagist = $this->request->variable('enable_packagist', false);
$enable_on_install = $this->request->variable('enable_on_install', false);
$purge_on_remove = $this->request->variable('purge_on_remove', false);
$minimum_stability = $this->request->variable('minimum_stability', 'stable');
$repositories = array_unique(
array_filter(
array_map(
'trim',
explode("\n", $this->request->variable('repositories', ''))
)
)
);
$previous_minimum_stability = $this->config['exts_composer_minimum_stability'];
$previous_repositories = $this->config['exts_composer_repositories'];
$previous_enable_packagist = $this->config['exts_composer_packagist'];
$this->config->set('exts_composer_enable_on_install', $enable_on_install);
$this->config->set('exts_composer_purge_on_remove', $purge_on_remove);
$this->config->set('exts_composer_minimum_stability', $minimum_stability);
$this->config->set('exts_composer_repositories', json_encode($repositories, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
if ($minimum_stability != $previous_minimum_stability
|| $repositories != $previous_repositories
|| $enable_packagist != $previous_enable_packagist)
{
$composer_manager->reset_cache();
}
if (!$this->config['exts_composer_packagist'] && $enable_packagist)
{
$s_hidden_fields = build_hidden_fields(array(
'enable_packagist' => $enable_packagist
));
confirm_box(false, $language->lang('ENABLE_PACKAGIST_CONFIRM'), $s_hidden_fields);
}
else
{
$this->config->set('exts_composer_packagist', $enable_packagist);
trigger_error($language->lang('CONFIG_UPDATED') . adm_back_link($this->u_action));
}
}
/** @var \phpbb\composer\extension_manager $manager */
$manager = $phpbb_container->get('ext.composer.manager');
/** @var \phpbb\pagination $pagination */
$pagination = $phpbb_container->get('pagination');
$start = $this->request->variable('start', 0);
$base_url = $this->u_action;
$available_extensions = $manager->get_available_packages();
$managed_packages = $manager->get_managed_packages();
$extensions = array_slice($available_extensions, $start, 20);
$pagination->generate_template_pagination($base_url, 'pagination', 'start', count($available_extensions), 20, $start);
$this->page_title = 'ACP_EXTENSIONS_CATALOG';
$this->tpl_name = 'acp_ext_catalog';
$this->template->assign_vars([
'extensions' => $extensions,
'managed_extensions' => array_keys($managed_packages),
'installed_extensions' => array_keys($extensions_manager->all_available()),
'U_ACTION' => $this->u_action,
'settings' => [
'enable_packagist' => $this->config['exts_composer_packagist'],
'enable_on_install' => $this->config['exts_composer_enable_on_install'],
'purge_on_remove' => $this->config['exts_composer_purge_on_remove'],
'minimum_stability' => $this->config['exts_composer_minimum_stability'],
'stabilities' => array_keys(\Composer\Package\BasePackage::$stabilities),
'repositories' => json_decode($this->config['exts_composer_repositories'], true),
],
]);
add_form_key('catalog_settings');
break;
}
}
/**
* Display an exception raised by the composer manager
*
* @param \phpbb\language\language $language
* @param \phpbb\exception\runtime_exception $e
* @param \phpbb\composer\io\web_io $composer_io
*/
private function display_composer_exception(\phpbb\language\language $language, \phpbb\exception\runtime_exception $e, \phpbb\composer\io\web_io $composer_io)
{
$this->tpl_name = 'detailed_message_body';
if ($e->getPrevious())
{
$message_title = $language->lang_array($e->getMessage(), $e->get_parameters());
if ($e->getPrevious() instanceof \phpbb\exception\exception_interface)
{
$message_text = $language->lang_array($e->getPrevious()->getMessage(), $e->getPrevious()->get_parameters()) . adm_back_link($this->u_action);
}
else
{
$message_text = $e->getPrevious()->getMessage() . adm_back_link($this->u_action);
}
}
else
{
$message_title = $language->lang('INFORMATION');
$message_text = $language->lang_array($e->getMessage(), $e->get_parameters()) . adm_back_link($this->u_action);
}
$this->template->assign_vars(array(
'MESSAGE_TITLE' => $message_title,
'MESSAGE_TEXT' => $message_text,
'MESSAGE_DETAIL' => $composer_io->getOutput(),
'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'),
'S_USER_ERROR' => true,
)
);
}
/**
* Lists all the enabled extensions and dumps to the template
*
* @param \phpbb\extension\manager $phpbb_extension_manager An instance of the extension manager
* @param array $managed_packages List of managed packages
*
* @return null
*/
public function list_enabled_exts(\phpbb\extension\manager $phpbb_extension_manager, array $managed_packages)
{
$enabled_extension_meta_data = array();
@ -400,6 +767,7 @@ class acp_extensions
$enabled_extension_meta_data[$name] = array(
'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'),
'META_VERSION' => $meta['version'],
'META_NAME' => $md_manager->get_metadata('name'),
);
if (isset($meta['extra']['version-check']))
@ -449,15 +817,29 @@ class acp_extensions
$this->output_actions('enabled', array(
'DISABLE' => $this->u_action . '&amp;action=disable_pre&amp;ext_name=' . urlencode($name),
));
if (isset($managed_packages[$block_vars['META_NAME']]))
{
$this->output_actions('enabled', [
'UPDATE' => $this->u_catalog_action . '&amp;action=update&amp;extension=' . urlencode($block_vars['META_NAME']),
'REMOVE' => [
'url' => $this->u_catalog_action . '&amp;action=remove&amp;extension=' . urlencode($block_vars['META_NAME']),
'color' => '#BC2A4D;',
]
]);
}
}
}
/**
* Lists all the disabled extensions and dumps to the template
*
* @return null
*/
public function list_disabled_exts()
* Lists all the disabled extensions and dumps to the template
*
* @param \phpbb\extension\manager $phpbb_extension_manager An instance of the extension manager
* @param array $managed_packages List of managed packages
*
* @return null
*/
public function list_disabled_exts(\phpbb\extension\manager $phpbb_extension_manager, array $managed_packages)
{
$disabled_extension_meta_data = array();
@ -471,6 +853,7 @@ class acp_extensions
$disabled_extension_meta_data[$name] = array(
'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'),
'META_VERSION' => $meta['version'],
'META_NAME' => $md_manager->get_metadata('name'),
);
if (isset($meta['extra']['version-check']))
@ -518,15 +901,29 @@ class acp_extensions
'ENABLE' => $this->u_action . '&amp;action=enable_pre&amp;ext_name=' . urlencode($name),
'DELETE_DATA' => $this->u_action . '&amp;action=delete_data_pre&amp;ext_name=' . urlencode($name),
));
if (isset($managed_packages[$block_vars['META_NAME']]))
{
$this->output_actions('disabled', [
'UPDATE' => $this->u_catalog_action . '&amp;action=update&amp;extension=' . urlencode($block_vars['META_NAME']),
'REMOVE' => [
'url' => $this->u_catalog_action . '&amp;action=remove&amp;extension=' . urlencode($block_vars['META_NAME']),
'color' => '#BC2A4D;',
]
]);
}
}
}
/**
* Lists all the available extensions and dumps to the template
*
* @return null
*/
public function list_available_exts()
* Lists all the available extensions and dumps to the template
*
* @param \phpbb\extension\manager $phpbb_extension_manager An instance of the extension manager
* @param array $managed_packages List of managed packages
*
* @return null
*/
public function list_available_exts(\phpbb\extension\manager $phpbb_extension_manager, array $managed_packages)
{
$uninstalled = array_diff_key($this->ext_manager->all_available(), $this->ext_manager->all_configured());
@ -542,6 +939,7 @@ class acp_extensions
$available_extension_meta_data[$name] = array(
'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'),
'META_VERSION' => $meta['version'],
'META_NAME' => $md_manager->get_metadata('name'),
);
if (isset($meta['extra']['version-check']))
@ -595,13 +993,26 @@ class acp_extensions
*/
private function output_actions($block, $actions)
{
foreach ($actions as $lang => $url)
foreach ($actions as $lang => $options)
{
$this->template->assign_block_vars($block . '.actions', array(
$url = $options;
if (is_array($options))
{
$url = $options['url'];
}
$vars = array(
'L_ACTION' => $this->user->lang('EXTENSION_' . $lang),
'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $lang . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $lang . '_EXPLAIN') : '',
'U_ACTION' => $url,
));
);
if (isset($options['color']))
{
$vars['COLOR'] = $options['color'];
}
$this->template->assign_block_vars($block . '.actions', $vars);
}
}

View File

@ -20,6 +20,7 @@ class acp_extensions_info
'title' => 'ACP_EXTENSION_MANAGEMENT',
'modes' => array(
'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_EXTENSION_MANAGEMENT')),
'catalog' => array('title' => 'ACP_EXTENSIONS_CATALOG', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_EXTENSION_MANAGEMENT')),
),
);
}

View File

@ -4324,6 +4324,9 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
$controller_helper = $phpbb_container->get('controller.helper');
$notification_mark_hash = generate_link_hash('mark_all_notifications_read');
$phpbb_version_parts = explode('.', PHPBB_VERSION, 3);
$phpbb_major = $phpbb_version_parts[0] . '.' . $phpbb_version_parts[1];
// The following assigns all _common_ variables that may be used at any point in a template.
$template->assign_vars(array(
'SITENAME' => $config['sitename'],
@ -4357,6 +4360,8 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
'SESSION_ID' => $user->session_id,
'ROOT_PATH' => $web_path,
'BOARD_URL' => $board_url,
'PHPBB_VERSION' => PHPBB_VERSION,
'PHPBB_MAJOR' => $phpbb_major,
'L_LOGIN_LOGOUT' => $l_login_logout,
'L_INDEX' => ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['FORUM_INDEX'],

View File

@ -66,6 +66,9 @@ function adm_page_header($page_title)
}
}
$phpbb_version_parts = explode('.', PHPBB_VERSION, 3);
$phpbb_major = $phpbb_version_parts[0] . '.' . $phpbb_version_parts[1];
$template->assign_vars(array(
'PAGE_TITLE' => $page_title,
'USERNAME' => $user->data['username'],
@ -75,6 +78,8 @@ function adm_page_header($page_title)
'SESSION_ID' => $user->session_id,
'ROOT_PATH' => $phpbb_root_path,
'ADMIN_ROOT_PATH' => $phpbb_admin_path,
'PHPBB_VERSION' => PHPBB_VERSION,
'PHPBB_MAJOR' => $phpbb_major,
'U_LOGOUT' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout'),
'U_ADM_LOGOUT' => append_sid("{$phpbb_admin_path}index.$phpEx", 'action=admlogout'),

View File

@ -281,6 +281,12 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('use_system_cron',
INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.3.0-a1-dev');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_expire_days', '90');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_gc', '14400');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('exts_composer_repositories', '[]');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('exts_composer_packagist', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('exts_composer_json_file', 'composer-ext.json');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('exts_composer_vendor_dir', 'vendor-ext/');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('exts_composer_enable_on_install', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('exts_composer_purge_on_remove', '1');
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('cache_last_gc', '0', 1);
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('cron_lock', '0', 1);

View File

@ -88,6 +88,11 @@ $lang = array_merge($lang, array(
'ACP_EXTENSION_GROUPS' => 'Manage attachment extension groups',
'ACP_EXTENSION_MANAGEMENT' => 'Extension management',
'ACP_EXTENSIONS' => 'Manage extensions',
'ACP_EXTENSIONS_CATALOG' => 'Extensions catalog',
'ACP_EXTENSIONS_INSTALL' => 'Install extensions',
'ACP_EXTENSIONS_REMOVE' => 'Remove extensions',
'ACP_EXTENSIONS_UPDATE' => 'Update extensions',
'ACP_EXTENSIONS_MANAGE' => 'Manage extension automatically',
'ACP_FORUM_BASED_PERMISSIONS' => 'Forum based permissions',
'ACP_FORUM_LOGS' => 'Forum logs',
@ -240,6 +245,17 @@ $lang = array_merge($lang, array(
'EXCEPTION' => 'Exception',
'COLOUR_SWATCH' => 'Web-safe colour swatch',
'COMPOSER_UNSUPPORTED_OPERATION' => 'Operation unsupported for the package type “%s”.',
'COMPOSER_UPDATING_DEPENDENCIES' => 'Updating packages',
'COMPOSER_LOADING_REPOSITORIES' => 'Loading remote repositories with package information',
'COMPOSER_ERROR_CONFLICT' => 'Your requirements could not be resolved to an installable set of packages.',
'COMPOSER_REPOSITORY_UNAVAILABLE' => 'An error occurred while fetching the repository %s.',
'COMPOSER_INSTALLING_PACKAGE' => ' - Installing %1$s (%2$s)',
'COMPOSER_DELETING' => ' - Deleting %s',
'COMPOSER_UPDATE_NOTHING' => 'Nothing to update',
'COMPOSER_OUTPUT' => 'Composer output',
'CONFIG_UPDATED' => 'Configuration updated successfully.',
'CRON_LOCK_ERROR' => 'Could not obtain cron lock.',
'CRON_NO_SUCH_TASK' => 'Could not find cron task “%s”.',

View File

@ -35,6 +35,22 @@ if (empty($lang) || !is_array($lang))
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
$lang = array_merge($lang, array(
'EXTENSION_ALREADY_INSTALLED' => 'The “%s” extension has already been installed.',
'EXTENSION_ALREADY_INSTALLED_MANUALLY' => 'The “%s” extension has already been installed manually.',
'EXTENSION_ALREADY_MANAGED' => 'The “%s” extension is already managed.',
'EXTENSION_CANNOT_MANAGE_FILESYSTEM_ERROR' => 'The “%s” extension cannot be managed because the existing files could not be removed from the filesystem.',
'EXTENSION_CANNOT_MANAGE_INSTALL_ERROR' => 'The “%s” extension could not be installed. The prior installation of this extension has been restored.',
'EXTENSION_MANAGED_WITH_CLEAN_ERROR' => 'The “%1$s” extension has been installed but an error occurred and the old files could not be removed. You might want to delete the “%2$s” files manually.',
'EXTENSION_MANAGED_WITH_ENABLE_ERROR' => 'The “%s” extension has been installed but an error occurred while enabling it.',
'EXTENSION_NOT_INSTALLED' => 'The “%s” extension is not installed.',
'ENABLING_EXTENSIONS' => 'Enabling extensions',
'DISABLING_EXTENSIONS' => 'Disabling extensions',
'EXTENSIONS_CATALOG' => 'Extensions Catalog',
'EXTENSIONS_CATALOG_EXPLAIN' => 'Here you can browse all of the extensions available for your phpBB board. Extensions can easily be installed or removed with just a click. Adjust the settings to allow instant enabling and purging of extensions.',
'EXTENSION' => 'Extension',
'EXTENSIONS' => 'Extensions',
'EXTENSIONS_ADMIN' => 'Extensions Manager',
@ -43,7 +59,6 @@ $lang = array_merge($lang, array(
'EXTENSION_NOT_AVAILABLE' => 'The selected extension is not available for this board, please verify your phpBB and PHP versions are allowed (see the details page).',
'EXTENSION_DIR_INVALID' => 'The selected extension has an invalid directory structure and cannot be enabled.',
'EXTENSION_NOT_ENABLEABLE' => 'The selected extension cannot be enabled, please verify the extensions requirements.',
'EXTENSION_NOT_INSTALLED' => 'The extension %s is not available. Please check that you have installed it correctly.',
'DETAILS' => 'Details',
@ -53,6 +68,8 @@ $lang = array_merge($lang, array(
'EXTENSION_DELETE_DATA' => 'Delete data',
'EXTENSION_DISABLE' => 'Disable',
'EXTENSION_ENABLE' => 'Enable',
'EXTENSION_UPDATE' => 'Update',
'EXTENSION_REMOVE' => 'Remove',
'EXTENSION_DELETE_DATA_EXPLAIN' => 'Deleting an extensions data removes all of its data and settings. The extension files are retained so it can be enabled again.',
'EXTENSION_DISABLE_EXPLAIN' => 'Disabling an extension retains its files, data and settings but removes any functionality added by the extension.',
@ -94,6 +111,9 @@ $lang = array_merge($lang, array(
'EXTENSION_ENABLE_CONFIRM' => 'Are you sure that you wish to enable the “%s” extension?',
'EXTENSION_FORCE_UNSTABLE_CONFIRM' => 'Are you sure that you wish to force the use of unstable version?',
'INSTALLED' => 'Installed',
'INSTALLED_MANUALLY' => 'Installed manually',
'RETURN_TO_EXTENSION_LIST' => 'Return to the extension list',
'EXT_DETAILS' => 'Extension Details',
@ -130,4 +150,32 @@ $lang = array_merge($lang, array(
'META_FIELD_NOT_SET' => 'Required meta field %s has not been set.',
'META_FIELD_INVALID' => 'Meta field %s is invalid.',
'EXTENSIONS_CATALOG_SETTINGS' => 'Extensions catalog settings',
'ENABLE_ON_INSTALL' => 'Enable extensions while installing',
'PURGE_ON_REMOVE' => 'Purge extensions while removing',
'ENABLE_PACKAGIST' => 'Search packagist',
'ENABLE_PACKAGIST_EXPLAIN' => 'Search packagist for phpBB extensions. Beware that packagist may contain extensions not validated by the phpBB Extension Customisations Team.',
'ENABLE_PACKAGIST_CONFIRM' => 'Are you sure you want to search packagist?',
'COMPOSER_REPOSITORIES' => 'Repositories',
'COMPOSER_REPOSITORIES_EXPLAIN' => 'Add URLs to Composer repositories of phpBB extensions to search here, one per line (must be the base url of the packages.json file).',
'NO_EXTENSION_AVAILABLE' => 'There are no extension available for your board',
'EXTENSION_MANAGED_SUCCESS' => 'The extension %s is now being managed automatically.',
'EXTENSIONS_INSTALLED' => 'Extensions successfully installed.',
'EXTENSIONS_REMOVED' => 'Extensions successfully removed.',
'EXTENSIONS_UPDATED' => 'Extensions successfully updated.',
'EXTENSIONS_CATALOG_NOT_AVAILABLE' => 'The extensions catalog is not available',
'EXTENSIONS_COMPOSER_NOT_WRITABLE' => 'In order to use the catalog, the following files and directories must be writable: ext/ vendor-ext/ composer-ext.json and composer-ext.lock',
'STABILITY_STABLE' => 'stable',
'STABILITY_RC' => 'RC',
'STABILITY_BETA' => 'beta',
'STABILITY_ALPHA' => 'alpha',
'STABILITY_DEV' => 'dev',
'COMPOSER_MINIMUM_STABILITY' => 'Minimum stability',
'COMPOSER_MINIMUM_STABILITY_EXPLAIN' => 'Always use <samp>stable</samp> versions on a live forum. Non-stable versions may still be in development and could cause unexpected problems with your forum and should only be used for development purposes in local or staging environments.',
));

View File

@ -157,6 +157,18 @@ $lang = array_merge($lang, array(
1 => 'Re-cleaning complete. %d username was cleaned.',
2 => 'Re-cleaning complete. %d usernames were cleaned.',
],
'CLI_DESCRIPTION_EXTENSION_MANAGE' => 'Manages an extension',
'CLI_DESCRIPTION_EXTENSION_MANAGE_ARGUMENT' => 'Extension to manage',
'CLI_DESCRIPTION_EXTENSION_INSTALL' => 'Install the specified extension(s).',
'CLI_DESCRIPTION_EXTENSION_INSTALL_OPTION_ENABLE' => 'Enable extension(s) after installation',
'CLI_DESCRIPTION_EXTENSION_INSTALL_ARGUMENT' => 'Extension(s) to install, e.g.: vendor/package',
'CLI_DESCRIPTION_EXTENSION_LIST_AVAILABLE' => 'List extensions available for installation.',
'CLI_DESCRIPTION_EXTENSION_REMOVE' => 'Remove the specified extension(s).',
'CLI_DESCRIPTION_EXTENSION_REMOVE_OPTION_PURGE' => 'Purge extension(s) when removing them',
'CLI_DESCRIPTION_EXTENSION_REMOVE_ARGUMENT' => 'Extension(s) to remove, e.g.: vendor/package',
'CLI_DESCRIPTION_EXTENSION_UPDATE' => 'Update the specified extension(s).',
'CLI_DESCRIPTION_EXTENSION_UPDATE_ARGUMENT' => 'Extension(s) to update, e.g.: vendor/package',
));
// Additional help for commands.

View File

@ -153,6 +153,7 @@ $lang = array_merge($lang, array(
'BYTES_SHORT' => 'B',
'CANCEL' => 'Cancel',
'CANNOT_RENAME_FILE' => 'Cannot rename %s',
'CHANGE' => 'Change',
'CHANGE_FONT_SIZE' => 'Change font size',
'CHANGING_PREFERENCES' => 'Changing board preferences',

View File

@ -0,0 +1,35 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\exception;
/**
* Packaged managed with success but error occurred when cleaning the filesystem
*/
class managed_with_clean_error_exception extends managed_with_error_exception
{
/**
* Constructor
*
* @param string $prefix The language string prefix
* @param string $message The Exception message to throw (must be a language variable).
* @param array $parameters The parameters to use with the language var.
* @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining.
* @param integer $code The Exception code.
*/
public function __construct($prefix, $message = '', array $parameters = [], \Exception $previous = null, $code = 0)
{
parent::__construct($prefix . $message, $parameters, $previous, $code);
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\exception;
/**
* Packaged managed with success but error occurred when re-enabling the extension
*/
class managed_with_enable_error_exception extends managed_with_error_exception
{
/**
* Constructor
*
* @param string $prefix The language string prefix
* @param string $message The Exception message to throw (must be a language variable).
* @param array $parameters The parameters to use with the language var.
* @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining.
* @param integer $code The Exception code.
*/
public function __construct($prefix, $message = '', array $parameters = [], \Exception $previous = null, $code = 0)
{
parent::__construct($prefix . $message, $parameters, $previous, $code);
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\exception;
/**
* Packaged managed with success but errored at some point
*/
class managed_with_error_exception extends runtime_exception
{
/**
* Constructor
*
* @param string $prefix The language string prefix
* @param string $message The Exception message to throw (must be a language variable).
* @param array $parameters The parameters to use with the language var.
* @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining.
* @param integer $code The Exception code.
*/
public function __construct($prefix, $message = '', array $parameters = [], \Exception $previous = null, $code = 0)
{
parent::__construct($prefix . $message, $parameters, $previous, $code);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\exception;
use phpbb\exception\runtime_exception as base;
/**
* Base class for exceptions thrown when managing packages through composer
*/
class runtime_exception extends base
{
/**
* Constructor
*
* @param string $prefix The language string prefix
* @param string $message The Exception message to throw (must be a language variable).
* @param array $parameters The parameters to use with the language var.
* @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining.
* @param integer $code The Exception code.
*/
public function __construct($prefix, $message = '', array $parameters = [], \Exception $previous = null, $code = 0)
{
parent::__construct($prefix . $message, $parameters, $previous, $code);
}
}

View File

@ -0,0 +1,316 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer;
use Composer\IO\IOInterface;
use phpbb\cache\driver\driver_interface;
use phpbb\composer\exception\managed_with_clean_error_exception;
use phpbb\composer\exception\managed_with_enable_error_exception;
use phpbb\composer\exception\runtime_exception;
use phpbb\config\config;
use phpbb\extension\manager as ext_manager;
use phpbb\filesystem\exception\filesystem_exception;
use phpbb\filesystem\filesystem;
/**
* Class to safely manage extensions through composer.
*/
class extension_manager extends manager
{
/**
* @var \phpbb\extension\manager
*/
protected $extension_manager;
/**
* @var \phpbb\filesystem\filesystem
*/
protected $filesystem;
/**
* @var array
*/
private $enabled_extensions;
/**
* @var bool Enables extensions when installing them?
*/
private $enable_on_install = false;
/**
* @var bool Purges extensions data when removing them?
*/
private $purge_on_remove = true;
/**
* @param installer $installer Installer object
* @param driver_interface $cache Cache object
* @param ext_manager $extension_manager phpBB extension manager
* @param filesystem $filesystem Filesystem object
* @param string $package_type Composer type of managed packages
* @param string $exception_prefix Exception prefix to use
* @param string $root_path phpBB root path
* @param config $config Config object
*/
public function __construct(installer $installer, driver_interface $cache, ext_manager $extension_manager, filesystem $filesystem, $package_type, $exception_prefix, $root_path, config $config = null)
{
$this->extension_manager = $extension_manager;
$this->filesystem = $filesystem;
$this->root_path = $root_path;
if ($config)
{
$this->enable_on_install = (bool) $config['exts_composer_enable_on_install'];
$this->purge_on_remove = (bool) $config['exts_composer_purge_on_remove'];
}
parent::__construct($installer, $cache, $package_type, $exception_prefix);
}
/**
* {@inheritdoc}
*/
public function pre_install(array $packages, IOInterface $io = null)
{
$installed_manually = array_intersect(array_keys($this->extension_manager->all_available()), array_keys($packages));
if (count($installed_manually) !== 0)
{
throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED_MANUALLY', [implode('|', array_keys($installed_manually))]);
}
}
/**
* {@inheritdoc}
*/
public function post_install(array $packages, IOInterface $io = null)
{
if ($this->enable_on_install)
{
$io->writeError([['ENABLING_EXTENSIONS', [], 1]], true);
foreach ($packages as $package => $version)
{
try
{
$this->extension_manager->enable($package);
}
catch (\phpbb\exception\runtime_exception $e)
{
$io->writeError([[$e->getMessage(), $e->get_parameters(), 4]], true);
}
catch (\Exception $e)
{
$io->writeError([[$e->getMessage(), [], 4]], true);
}
}
}
}
/**
* {@inheritdoc}
*/
protected function pre_update(array $packages, IOInterface $io = null)
{
$io->writeError([['DISABLING_EXTENSIONS', [], 1]], true);
$this->enabled_extensions = [];
foreach ($packages as $package => $version)
{
try
{
if ($this->extension_manager->is_enabled($package))
{
$this->enabled_extensions[] = $package;
$this->extension_manager->disable($package);
}
}
catch (\phpbb\exception\runtime_exception $e)
{
$io->writeError([[$e->getMessage(), $e->get_parameters(), 4]], true);
}
catch (\Exception $e)
{
$io->writeError([[$e->getMessage(), [], 4]], true);
}
}
}
/**
* {@inheritdoc}
*/
protected function post_update(array $packages, IOInterface $io = null)
{
$io->writeError([['ENABLING_EXTENSIONS', [], 1]], true);
foreach ($this->enabled_extensions as $package)
{
try
{
$this->extension_manager->enable($package);
}
catch (\phpbb\exception\runtime_exception $e)
{
$io->writeError([[$e->getMessage(), $e->get_parameters(), 4]], true);
}
catch (\Exception $e)
{
$io->writeError([[$e->getMessage(), [], 4]], true);
}
}
}
/**
* {@inheritdoc}
*/
public function remove(array $packages, IOInterface $io = null)
{
$packages = $this->normalize_version($packages);
$not_installed = array_diff(array_keys($packages), array_keys($this->extension_manager->all_available()));
if (count($not_installed) !== 0)
{
throw new runtime_exception($this->exception_prefix, 'NOT_INSTALLED', [implode('|', array_keys($not_installed))]);
}
parent::remove($packages, $io);
}
/**
* {@inheritdoc}
*/
public function pre_remove(array $packages, IOInterface $io = null)
{
if ($this->purge_on_remove)
{
$io->writeError([['DISABLING_EXTENSIONS', [], 1]], true);
}
foreach ($packages as $package => $version)
{
try
{
if ($this->extension_manager->is_enabled($package))
{
if ($this->purge_on_remove)
{
$this->extension_manager->purge($package);
}
else
{
$this->extension_manager->disable($package);
}
}
}
catch (\phpbb\exception\runtime_exception $e)
{
$io->writeError([[$e->getMessage(), $e->get_parameters(), 4]], true);
}
catch (\Exception $e)
{
$io->writeError([[$e->getMessage(), [], 4]], true);
}
}
}
/**
* {@inheritdoc}
*/
public function start_managing($package, $io)
{
if (!$this->extension_manager->is_available($package))
{
throw new runtime_exception($this->exception_prefix, 'NOT_INSTALLED', [$package]);
}
if ($this->is_managed($package))
{
throw new runtime_exception($this->exception_prefix, 'ALREADY_MANAGED', [$package]);
}
$enabled = false;
if ($this->extension_manager->is_enabled($package))
{
$enabled = true;
$io->writeError([['DISABLING_EXTENSIONS', [], 1]], true);
$this->extension_manager->disable($package);
}
$ext_path = $this->extension_manager->get_extension_path($package, true);
$backup_path = rtrim($ext_path, '/') . '__backup__';
try
{
$this->filesystem->rename($ext_path, $backup_path);
}
catch (filesystem_exception $e)
{
throw new runtime_exception($this->exception_prefix, 'CANNOT_MANAGE_FILESYSTEM_ERROR', [$package], $e);
}
try
{
$this->install((array) $package, $io);
$this->filesystem->remove($backup_path);
}
catch (runtime_exception $e)
{
$this->filesystem->rename($backup_path, $ext_path);
throw new runtime_exception($this->exception_prefix, 'CANNOT_MANAGE_INSTALL_ERROR', [$package], $e);
}
catch (filesystem_exception $e)
{
throw new managed_with_clean_error_exception($this->exception_prefix, 'MANAGED_WITH_CLEAN_ERROR', [$package, $backup_path], $e);
}
if ($enabled)
{
try
{
$io->writeError([['ENABLING_EXTENSIONS', [], 1]], true);
$this->extension_manager->enable($package);
}
catch (\Exception $e)
{
throw new managed_with_enable_error_exception($this->exception_prefix, 'MANAGED_WITH_ENABLE_ERROR', [$package], $e);
}
}
}
/**
* {@inheritdoc}
*/
public function check_requirements()
{
return parent::check_requirements() && $this->filesystem->is_writable($this->root_path . 'ext/');
}
/**
* Enable the extensions when installing
*
* Warning: Only the explicitly required extensions will be enabled
*
* @param bool $enable
*/
public function set_enable_on_install($enable)
{
$this->enable_on_install = $enable;
}
/**
* Purge the extension when disabling it
*
* @param bool $purge
*/
public function set_purge_on_remove($purge)
{
$this->purge_on_remove = $purge;
}
}

View File

@ -0,0 +1,710 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer;
use Composer\Composer;
use Composer\Factory;
use Composer\IO\IOInterface;
use Composer\IO\NullIO;
use Composer\Json\JsonFile;
use Composer\Package\BasePackage;
use Composer\Package\CompletePackage;
use Composer\Repository\ComposerRepository;
use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Util\RemoteFilesystem;
use phpbb\composer\io\null_io;
use phpbb\config\config;
use phpbb\exception\runtime_exception;
use phpbb\filesystem\filesystem;
use phpbb\request\request;
use Seld\JsonLint\ParsingException;
/**
* Class to install packages through composer while freezing core dependencies.
*/
class installer
{
const PHPBB_TYPES = 'phpbb-extension,phpbb-style,phpbb-language';
/**
* @var array Repositories to look packages from
*/
protected $repositories = [];
/**
* @var bool Indicates whether packagist usage is allowed or not
*/
protected $packagist = false;
/**
* @var string Composer filename used to manage the packages
*/
protected $composer_filename = 'composer-ext.json';
/**
* @var string Directory where to install packages vendors
*/
protected $packages_vendor_dir = 'vendor-ext/';
/**
* @var string Minimum stability
*/
protected $minimum_stability = 'stable';
/**
* @var string phpBB root path
*/
protected $root_path;
/**
* @var string Stores the original working directory in case it has been changed through move_to_root()
*/
private $original_cwd;
/**
* @var array Stores the content of the ext json file before generate_ext_json_file() overrides it
*/
private $ext_json_file_backup;
/**
* @var request phpBB request object
*/
private $request;
/**
* @param string $root_path phpBB root path
* @param filesystem $filesystem Filesystem object
* @param request $request phpBB request object
* @param config $config Config object
*/
public function __construct($root_path, filesystem $filesystem, request $request, config $config = null)
{
if ($config)
{
$repositories = json_decode($config['exts_composer_repositories'], true);
if (is_array($repositories) && !empty($repositories))
{
$this->repositories = (array) $repositories;
}
$this->packagist = (bool) $config['exts_composer_packagist'];
$this->composer_filename = $config['exts_composer_json_file'];
$this->packages_vendor_dir = $config['exts_composer_vendor_dir'];
$this->minimum_stability = $config['exts_composer_minimum_stability'];
}
$this->root_path = $root_path;
$this->request = $request;
putenv('COMPOSER_HOME=' . $filesystem->realpath($root_path) . '/store/composer');
}
/**
* Update the current installed set of packages
*
* @param array $packages Packages to install.
* Each entry may be a name or an array associating a version constraint to a name
* @param array $whitelist White-listed packages (packages that can be installed/updated/removed)
* @param IOInterface $io IO object used for the output
*
* @throws runtime_exception
*/
public function install(array $packages, $whitelist, IOInterface $io = null)
{
$this->wrap(function() use ($packages, $whitelist, $io) {
$this->do_install($packages, $whitelist, $io);
});
}
/**
* Update the current installed set of packages
*
* /!\ Doesn't change the current working directory
*
* @param array $packages Packages to install.
* Each entry may be a name or an array associating a version constraint to a name
* @param array $whitelist White-listed packages (packages that can be installed/updated/removed)
* @param IOInterface $io IO object used for the output
*
* @throws runtime_exception
*/
protected function do_install(array $packages, $whitelist, IOInterface $io = null)
{
if (!$io)
{
$io = new null_io();
}
$this->generate_ext_json_file($packages);
$composer = Factory::create($io, $this->get_composer_ext_json_filename(), false);
$install = \Composer\Installer::create($io, $composer);
$composer->getDownloadManager()->setOutputProgress(false);
$install
->setVerbose(true)
->setPreferSource(false)
->setPreferDist(true)
->setDevMode(false)
->setUpdate(true)
->setUpdateWhitelist($whitelist)
->setWhitelistDependencies(false)
->setIgnorePlatformRequirements(false)
->setOptimizeAutoloader(true)
->setDumpAutoloader(true)
->setPreferStable(true)
->setRunScripts(false)
->setDryRun(false);
try
{
$result = $install->run();
}
catch (\Exception $e)
{
$this->restore_ext_json_file();
throw new runtime_exception('COMPOSER_CANNOT_INSTALL', [], $e);
}
if ($result !== 0)
{
$this->restore_ext_json_file();
throw new runtime_exception($io->get_composer_error(), []);
}
}
/**
* Returns the list of currently installed packages
*
* @param string|array $types Returns only the packages with the given type(s)
*
* @return array The installed packages associated to their version.
*
* @throws runtime_exception
*/
public function get_installed_packages($types)
{
return $this->wrap(function() use ($types) {
return $this->do_get_installed_packages($types);
});
}
/**
* Returns the list of currently installed packages
*
* /!\ Doesn't change the current working directory
*
* @param string|array $types Returns only the packages with the given type(s)
*
* @return array The installed packages associated to their version.
*/
protected function do_get_installed_packages($types)
{
$types = (array) $types;
try
{
$io = new NullIO();
$composer = Factory::create($io, $this->get_composer_ext_json_filename(), false);
$installed = [];
/** @var \Composer\Package\Link[] $required_links */
$required_links = $composer->getPackage()->getRequires();
$installed_packages = $composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();
foreach ($installed_packages as $package)
{
if (in_array($package->getType(), $types, true))
{
$version = array_key_exists($package->getName(), $required_links) ?
$required_links[$package->getName()]->getPrettyConstraint() : '*';
$installed[$package->getName()] = $version;
}
}
return $installed;
}
catch (\Exception $e)
{
return [];
}
}
/**
* Gets the list of the available packages of the configured type in the configured repositories
*
* /!\ Doesn't change the current working directory
*
* @param string $type Returns only the packages with the given type
*
* @return array The name of the available packages, associated to their definition. Ordered by name.
*
* @throws runtime_exception
*/
public function get_available_packages($type)
{
return $this->wrap(function() use ($type) {
return $this->do_get_available_packages($type);
});
}
/**
* Gets the list of the available packages of the configured type in the configured repositories
*
* @param string $type Returns only the packages with the given type
*
* @return array The name of the available packages, associated to their definition. Ordered by name.
*/
protected function do_get_available_packages($type)
{
try
{
$this->generate_ext_json_file($this->do_get_installed_packages(explode(',', self::PHPBB_TYPES)));
$io = new NullIO();
$composer = Factory::create($io, $this->get_composer_ext_json_filename(), false);
/** @var ConstraintInterface $core_constraint */
$core_constraint = $composer->getPackage()->getRequires()['phpbb/phpbb']->getConstraint();
$core_stability = $composer->getPackage()->getMinimumStability();
$available = [];
$compatible_packages = [];
$repositories = $composer->getRepositoryManager()->getRepositories();
/** @var \Composer\Repository\RepositoryInterface $repository */
foreach ($repositories as $repository)
{
try
{
if ($repository instanceof ComposerRepository && $repository->hasProviders())
{
// Special case for packagist which exposes an api to retrieve all packages of a given type.
// For the others composer repositories with providers we can't do anything. It would be too slow.
$r = new \ReflectionObject($repository);
$repo_url = $r->getProperty('url');
$repo_url->setAccessible(true);
if ($repo_url->getValue($repository) === 'http://packagist.org')
{
$url = 'https://packagist.org/packages/list.json?type=' . $type;
$rfs = new RemoteFilesystem($io);
$hostname = parse_url($url, PHP_URL_HOST) ?: $url;
$json = $rfs->getContents($hostname, $url, false);
/** @var \Composer\Package\PackageInterface $package */
foreach (JsonFile::parseJson($json, $url)['packageNames'] as $package)
{
$versions = $repository->findPackages($package);
$compatible_packages = $this->get_compatible_versions($compatible_packages, $core_constraint, $core_stability, $package, $versions);
}
}
}
else
{
// Pre-filter repo packages by their type
$packages = [];
/** @var \Composer\Package\PackageInterface $package */
foreach ($repository->getPackages() as $package)
{
if ($package->getType() === $type)
{
$packages[$package->getName()][] = $package;
}
}
// Filter the compatibles versions
foreach ($packages as $package => $versions)
{
$compatible_packages = $this->get_compatible_versions($compatible_packages, $core_constraint, $core_stability, $package, $versions);
}
}
}
catch (\Exception $e)
{
// If a repo fails, just skip it.
continue;
}
}
foreach ($compatible_packages as $name => $versions)
{
// Determine the highest version of the package
/** @var CompletePackage $highest_version */
$highest_version = null;
/** @var CompletePackage $version */
foreach ($versions as $version)
{
if (!$highest_version || version_compare($version->getVersion(), $highest_version->getVersion(), '>'))
{
$highest_version = $version;
}
}
// Generates the entry
$available[$name] = [];
$available[$name]['name'] = $highest_version->getPrettyName();
$available[$name]['display_name'] = $highest_version->getExtra()['display-name'];
$available[$name]['composer_name'] = $highest_version->getName();
$available[$name]['version'] = $highest_version->getPrettyVersion();
if ($version instanceof CompletePackage)
{
$available[$name]['description'] = $highest_version->getDescription();
$available[$name]['url'] = $highest_version->getHomepage();
$available[$name]['authors'] = $highest_version->getAuthors();
}
else
{
$available[$name]['description'] = '';
$available[$name]['url'] = '';
$available[$name]['authors'] = [];
}
}
usort($available, function($a, $b)
{
return strcasecmp($a['display_name'], $b['display_name']);
});
return $available;
}
catch (\Exception $e)
{
return [];
}
}
/**
* Checks the requirements of the manager and returns true if it can be used.
*
* @return bool
*/
public function check_requirements()
{
$filesystem = new \phpbb\filesystem\filesystem();
return $filesystem->is_writable([
$this->root_path . $this->composer_filename,
$this->root_path . $this->packages_vendor_dir,
$this->root_path . substr($this->composer_filename, 0, -5) . '.lock',
]);
}
/**
* Updates $compatible_packages with the versions of $versions compatibles with the $core_constraint
*
* @param array $compatible_packages List of compatibles versions
* @param ConstraintInterface $core_constraint Constraint against the phpBB version
* @param string $core_stability Core stability
* @param string $package_name Considered package
* @param array $versions List of available versions
*
* @return array
*/
private function get_compatible_versions(array $compatible_packages, ConstraintInterface $core_constraint, $core_stability, $package_name, array $versions)
{
$core_stability_value = BasePackage::$stabilities[$core_stability];
/** @var \Composer\Package\PackageInterface $version */
foreach ($versions as $version)
{
try
{
if (BasePackage::$stabilities[$version->getStability()] > $core_stability_value)
{
continue;
}
if (array_key_exists('phpbb/phpbb', $version->getRequires()))
{
/** @var ConstraintInterface $package_constraint */
$package_constraint = $version->getRequires()['phpbb/phpbb']->getConstraint();
if (!$package_constraint->matches($core_constraint))
{
continue;
}
}
$compatible_packages[$package_name][] = $version;
}
catch (\Exception $e)
{
// Do nothing (to log when a true debug logger is available)
}
}
return $compatible_packages;
}
/**
* Generates and write the json file used to install the set of packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
*/
protected function generate_ext_json_file(array $packages)
{
$io = new NullIO();
$composer = Factory::create($io, null, false);
$core_packages = $this->get_core_packages($composer);
$ext_json_data = [
'require' => array_merge(
['php' => $this->get_core_php_requirement($composer)],
$core_packages,
$this->get_extra_dependencies(),
$packages),
'replace' => $core_packages,
'repositories' => $this->get_composer_repositories(),
'config' => [
'vendor-dir'=> $this->packages_vendor_dir,
],
'minimum-stability' => $this->minimum_stability,
];
$this->ext_json_file_backup = null;
$json_file = new JsonFile($this->get_composer_ext_json_filename());
try
{
$ext_json_file_backup = $json_file->read();
}
catch (ParsingException $e)
{
$ext_json_file_backup = '{}';
$lockFile = new JsonFile(substr($this->get_composer_ext_json_filename(), 0, -5) . '.lock');
$lockFile->write([]);
}
$json_file->write($ext_json_data);
$this->ext_json_file_backup = $ext_json_file_backup;
}
/**
* Restore the json file overridden by generate_ext_json_file()
*/
protected function restore_ext_json_file()
{
if ($this->ext_json_file_backup)
{
try
{
$json_file = new JsonFile($this->get_composer_ext_json_filename());
$json_file->write($this->ext_json_file_backup);
}
catch (\Exception $e)
{
}
$this->ext_json_file_backup = null;
}
}
/**
* Get the core installed packages
*
* @param Composer $composer Composer object to load the dependencies
* @return array The core packages with their version
*/
protected function get_core_packages(Composer $composer)
{
$core_deps = [];
$packages = $composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();
foreach ($packages as $package)
{
$core_deps[$package->getName()] = $package->getPrettyVersion();
}
$core_deps['phpbb/phpbb'] = PHPBB_VERSION;
return $core_deps;
}
/**
* Get the PHP version required by the core
*
* @param Composer $composer Composer object to load the dependencies
* @return string The PHP version required by the core
*/
protected function get_core_php_requirement(Composer $composer)
{
return $composer->getLocker()->getLockData()['platform']['php'];
}
/**
* Generate the repositories entry of the packages json file
*
* @return array repositories entry
*/
protected function get_composer_repositories()
{
$repositories = [];
if (!$this->packagist)
{
$repositories[]['packagist'] = false;
}
foreach ($this->repositories as $repository)
{
if (preg_match('#^' . get_preg_expression('url') . '$#iu', $repository))
{
$repositories[] = [
'type' => 'composer',
'url' => $repository,
];
}
}
return $repositories;
}
/**
* Get the name of the json file used for the packages.
*
* @return string The json filename
*/
protected function get_composer_ext_json_filename()
{
return $this->composer_filename;
}
/**
* Get extra dependencies required to install the packages
*
* @return array Array of composer dependencies
*/
protected function get_extra_dependencies()
{
return [];
}
/**
* Sets the customs repositories
*
* @param array $repositories An array of composer repositories to use
*/
public function set_repositories(array $repositories)
{
$this->repositories = $repositories;
}
/**
* Allow or disallow packagist
*
* @param boolean $packagist
*/
public function set_packagist($packagist)
{
$this->packagist = $packagist;
}
/**
* Sets the name of the managed packages' json file
*
* @param string $composer_filename
*/
public function set_composer_filename($composer_filename)
{
$this->composer_filename = $composer_filename;
}
/**
* Sets the location of the managed packages' vendors
*
* @param string $packages_vendor_dir
*/
public function set_packages_vendor_dir($packages_vendor_dir)
{
$this->packages_vendor_dir = $packages_vendor_dir;
}
/**
* Sets the phpBB root path
*
* @param string $root_path
*/
public function set_root_path($root_path)
{
$this->root_path = $root_path;
}
/**
* Change the current directory to phpBB root
*/
protected function move_to_root()
{
if ($this->original_cwd === null)
{
$this->original_cwd = getcwd();
chdir($this->root_path);
}
}
/**
* Restore the current working directory if move_to_root() have been called
*/
protected function restore_cwd()
{
if ($this->original_cwd)
{
chdir($this->original_cwd);
$this->original_cwd = null;
}
}
/**
* Wraps a callable in order to adjust the context needed by composer
*
* @param callable $callable
*
* @return mixed
*/
protected function wrap(callable $callable)
{
// The composer installers works with a path relative to the current directory
$this->move_to_root();
// The composer installers uses some super globals
$super_globals = $this->request->super_globals_disabled();
$this->request->enable_super_globals();
try
{
return $callable();
}
finally
{
$this->restore_cwd();
if ($super_globals)
{
$this->request->disable_super_globals();
}
}
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\io;
use Composer\IO\ConsoleIO;
use phpbb\language\language;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class console_io extends ConsoleIO implements io_interface
{
use translate_composer_trait;
/**
* Constructor.
*
* @param InputInterface $input The input instance
* @param OutputInterface $output The output instance
* @param HelperSet $helperSet The helperSet instance
* @param language $language Language object
*/
public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet, language $language)
{
$this->language = $language;
parent::__construct($input, $output, $helperSet);
}
}

View File

@ -0,0 +1,86 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\io;
class html_output_formatter extends \Composer\Console\HtmlOutputFormatter
{
protected static $availableForegroundColors = [
30 => 'black',
31 => 'red',
32 => 'green',
33 => 'orange',
34 => 'blue',
35 => 'magenta',
36 => 'cyan',
37 => 'white',
];
protected static $availableBackgroundColors = [
40 => 'black',
41 => 'red',
42 => 'green',
43 => 'yellow',
44 => 'blue',
45 => 'magenta',
46 => 'cyan',
47 => 'white',
];
protected static $availableOptions
= [
1 => 'bold',
4 => 'underscore',
];
/**
* {@inheritdoc}
*/
public function format($message)
{
$formatted = parent::format($message);
return preg_replace_callback("{[\033\e]\[([0-9;]+)m(.*?)[\033\e]\[[0-9;]+m}s", [$this, 'formatHtml'], $formatted);
}
protected function formatHtml($matches)
{
$out = '<span style="';
foreach (explode(';', $matches[1]) as $code)
{
if (isset(self::$availableForegroundColors[$code]))
{
$out .= 'color:' . self::$availableForegroundColors[$code] . ';';
}
else if (isset(self::$availableBackgroundColors[$code]))
{
$out .= 'background-color:' . self::$availableBackgroundColors[$code] . ';';
}
else if (isset(self::$availableOptions[$code]))
{
switch (self::$availableOptions[$code])
{
case 'bold':
$out .= 'font-weight:bold;';
break;
case 'underscore':
$out .= 'text-decoration:underline;';
break;
}
}
}
return $out . '">' . $matches[2] . '</span>';
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\io;
use Composer\IO\IOInterface;
interface io_interface extends IOInterface
{
/**
* Returns the composer errors that occurred since the last tcall of the method.
*
* @return string
*/
public function get_composer_error();
}

View File

@ -0,0 +1,27 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\io;
use Composer\IO\NullIO;
class null_io extends NullIO implements io_interface
{
/**
* {@inheritdoc}
*/
public function get_composer_error()
{
return '';
}
}

View File

@ -0,0 +1,245 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\io;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Trait to translate the composer Output
*/
trait translate_composer_trait
{
/**
* @var \phpbb\language\language
*/
protected $language;
/**
* @var array
*/
protected $composer_error = [];
/**
* {@inheritdoc}
*/
public function write($messages, $newline = true, $verbosity = self::NORMAL)
{
$messages = (array) $messages;
$translated_messages = [];
foreach ($messages as $message)
{
$level = 0;
if (is_array($message))
{
$lang_key = $message[0];
$parameters = $message[1];
if (count($message) > 2)
{
$level = $message[2];
}
}
else
{
$lang_key = $message;
$parameters = [];
}
$message = trim($this->strip_format($lang_key), "\n\r");
if ($this->output->getVerbosity() === OutputInterface::VERBOSITY_DEBUG)
{
// Do nothing
}
else if (strpos($message, 'Deleting ') === 0)
{
$elements = explode(' ', $message);
$lang_key = 'COMPOSER_DELETING';
$parameters = [$elements[1]];
}
$translated_message = $this->language->lang_array($lang_key, $parameters);
switch ($level)
{
case 1:
$translated_message = '<info>' . $translated_message . '</info>';
break;
case 2:
$translated_message = '<comment>' . $translated_message . '</comment>';
break;
case 3:
$translated_message = '<warning>' . $translated_message . '</warning>';
break;
case 4:
$translated_message = '<error>' . $translated_message . '</error>';
break;
}
$translated_messages[] = $translated_message;
}
parent::write($translated_messages, $newline);
}
/**
* {@inheritdoc}
*/
public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
{
$messages = (array) $messages;
$translated_messages = [];
foreach ($messages as $message)
{
$level = 0;
if (is_array($message))
{
$lang_key = $message[0];
$parameters = $message[1];
if (count($message) > 2)
{
$level = $message[2];
}
}
else
{
$lang_key = $message;
$parameters = [];
}
$message = trim($this->strip_format($lang_key), "\n\r");
if ($message === 'Your requirements could not be resolved to an installable set of packages.')
{
$this->composer_error[] = ['COMPOSER_ERROR_CONFLICT', []];
if ($this->output->getVerbosity() < OutputInterface::VERBOSITY_DEBUG)
{
continue;
}
}
else if (strpos($message, ' Problem ') === 0)
{
if ($this->output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE)
{
continue;
}
$lang_key = "\n" . htmlentities($message) . "\n";
$level = 4;
}
else if ($message === 'Updating dependencies')
{
$lang_key = 'COMPOSER_UPDATING_DEPENDENCIES';
$level = 1;
}
else if ($message === 'Loading composer repositories with package information')
{
$lang_key = 'COMPOSER_LOADING_REPOSITORIES';
$level = 1;
}
else if (strpos($message, 'could not be fully loaded, package information was loaded from the local cache and may be out of date') !== false)
{
$end_repo = strpos($message, 'could not be fully loaded, package information was loaded from the local cache and may be out of date');
$repo = substr($message, 0, $end_repo - 1);
$lang_key = 'COMPOSER_REPOSITORY_UNAVAILABLE';
$parameters = [$repo];
$level = 3;
}
else if (strpos($message, 'file could not be downloaded') !== false)
{
continue;
}
else if (strpos($message, ' - Installing ') === 0)
{
$elements = explode(' ', $message);
$lang_key = 'COMPOSER_INSTALLING_PACKAGE';
$parameters = [$elements[4], trim($elements[5], '()')];
}
else if ($message === 'Nothing to install or update')
{
$lang_key = 'COMPOSER_UPDATE_NOTHING';
$level = 3;
}
else if ($message === ' Downloading')
{
continue;
}
else if ($message === ' Loading from cache')
{
continue;
}
else if ($message === 'Writing lock file')
{
continue;
}
else if ($message === ' Extracting archive')
{
continue;
}
else if (empty($message))
{
continue;
}
$translated_message = $this->language->lang_array($lang_key, $parameters);
switch ($level)
{
case 1:
$translated_message = '<info>' . $translated_message . '</info>';
break;
case 2:
$translated_message = '<comment>' . $translated_message . '</comment>';
break;
case 3:
$translated_message = '<warning>' . $translated_message . '</warning>';
break;
case 4:
$translated_message = '<error>' . $translated_message . '</error>';
break;
}
$translated_messages[] = $translated_message;
}
parent::writeError($translated_messages, $newline);
}
public function get_composer_error()
{
$error = '';
foreach ($this->composer_error as $error_line)
{
$error .= $this->language->lang_array($error_line[0], $error_line[1]);
$error .= "\n";
}
$this->composer_error = [];
return $error;
}
protected function strip_format($message)
{
return str_replace([
'<info>', '</info>',
'<warning>', '</warning>',
'<comment>', '</comment>',
'<error>', '</error>',
], '', $message);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer\io;
use Composer\IO\BufferIO;
use phpbb\language\language;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Output\StreamOutput;
class web_io extends BufferIO implements io_interface
{
use translate_composer_trait;
/**
* @param language $language Language object
* @param string $input Input string
* @param int $verbosity Verbosity level
* @param OutputFormatterInterface $formatter Output formatter
*/
public function __construct(language $language, $input = '', $verbosity = StreamOutput::VERBOSITY_NORMAL, OutputFormatterInterface $formatter = null)
{
$this->language = $language;
parent::__construct($input, $verbosity, $formatter);
}
}

View File

@ -0,0 +1,332 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer;
use Composer\IO\IOInterface;
use phpbb\cache\driver\driver_interface;
use phpbb\composer\exception\runtime_exception;
/**
* Class to manage packages through composer.
*/
class manager implements manager_interface
{
/**
* @var installer Composer packages installer
*/
protected $installer;
/**
* @var driver_interface Cache instance
*/
protected $cache;
/**
* @var string Type of packages (phpbb-packages per example)
*/
protected $package_type;
/**
* @var string Prefix used for the exception's language string
*/
protected $exception_prefix;
/**
* @var array Caches the managed packages list (for the current type)
*/
private $managed_packages;
/**
* @var array Caches the managed packages list (for all phpBB types)
*/
private $all_managed_packages;
/**
* @var array Caches the available packages list
*/
private $available_packages;
/**
* @param installer $installer Installer object
* @param driver_interface $cache Cache object
* @param string $package_type Composer type of managed packages
* @param string $exception_prefix Exception prefix to use
*/
public function __construct(installer $installer, driver_interface $cache, $package_type, $exception_prefix)
{
$this->installer = $installer;
$this->cache = $cache;
$this->package_type = $package_type;
$this->exception_prefix = $exception_prefix;
}
/**
* {@inheritdoc}
*/
public function install(array $packages, IOInterface $io = null)
{
$packages = $this->normalize_version($packages);
$already_managed = array_intersect(array_keys($this->get_managed_packages()), array_keys($packages));
if (count($already_managed) !== 0)
{
throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED', [implode('|', $already_managed)]);
}
$this->pre_install($packages, $io);
$managed_packages = array_merge($this->get_all_managed_packages(), $packages);
ksort($managed_packages);
$this->installer->install($managed_packages, array_keys($packages), $io);
$this->post_install($packages, $io);
$this->managed_packages = null;
}
/**
* Hook called before installing the packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*/
protected function pre_install(array $packages, IOInterface $io = null)
{
}
/**
* Hook called after installing the packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*/
protected function post_install(array $packages, IOInterface $io = null)
{
}
/**
* {@inheritdoc}
*/
public function update(array $packages, IOInterface $io = null)
{
$packages = $this->normalize_version($packages);
$not_managed = array_diff_key($packages, $this->get_managed_packages());
if (count($not_managed) !== 0)
{
throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]);
}
$this->pre_update($packages, $io);
$managed_packages = array_merge($this->get_all_managed_packages(), $packages);
ksort($managed_packages);
$this->installer->install($managed_packages, array_keys($packages), $io);
$this->post_update($packages, $io);
}
/**
* Hook called before updating the packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*/
protected function pre_update(array $packages, IOInterface $io = null)
{
}
/**
* Hook called after updating the packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*/
protected function post_update(array $packages, IOInterface $io = null)
{
}
/**
* {@inheritdoc}
*/
public function remove(array $packages, IOInterface $io = null)
{
$packages = $this->normalize_version($packages);
$not_managed = array_diff_key($packages, $this->get_managed_packages());
if (count($not_managed) !== 0)
{
throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]);
}
$this->pre_remove($packages, $io);
$managed_packages = array_diff_key($this->get_all_managed_packages(), $packages);
ksort($managed_packages);
$this->installer->install($managed_packages, array_keys($packages), $io);
$this->post_remove($packages, $io);
$this->managed_packages = null;
}
/**
* Hook called before removing the packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*/
protected function pre_remove(array $packages, IOInterface $io = null)
{
}
/**
* Hook called after removing the packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*/
protected function post_remove(array $packages, IOInterface $io = null)
{
}
/**
* {@inheritdoc}
*/
public function is_managed($package)
{
return array_key_exists($package, $this->get_managed_packages());
}
/**
* {@inheritdoc}
*/
public function get_managed_packages()
{
if ($this->managed_packages === null)
{
$this->managed_packages = $this->installer->get_installed_packages($this->package_type);
}
return $this->managed_packages;
}
/**
* {@inheritdoc}
*/
public function get_all_managed_packages()
{
if ($this->all_managed_packages === null)
{
$this->all_managed_packages = $this->installer->get_installed_packages(explode(',', installer::PHPBB_TYPES));
}
return $this->all_managed_packages;
}
/**
* {@inheritdoc}
*/
public function get_available_packages()
{
if ($this->available_packages === null)
{
$this->available_packages = $this->cache->get('_composer_' . $this->package_type . '_available');
if (!$this->available_packages)
{
$this->available_packages = $this->installer->get_available_packages($this->package_type);
$this->cache->put('_composer_' . $this->package_type . '_available', $this->available_packages, 24*60*60);
}
}
return $this->available_packages;
}
/**
* {@inheritdoc}
*/
public function reset_cache()
{
$this->cache->destroy('_composer_' . $this->package_type . '_available');
$this->available_packages = null;
$this->managed_packages = null;
$this->all_managed_packages = null;
}
/**
* {@inheritdoc}
*/
public function start_managing($package, $io)
{
throw new \phpbb\exception\runtime_exception('COMPOSER_UNSUPPORTED_OPERATION', (array) $this->package_type);
}
/**
* {@inheritdoc}
*/
public function check_requirements()
{
return $this->installer->check_requirements();
}
/**
* Normalize a packages/version array. Every entry can have 3 different forms:
* - $package => $version
* - $indice => $package:$version
* - $indice => $package
* They are converted to he form:
* - $package => $version ($version is set to '*' for the third form)
*
* @param array $packages
*
* @return array
*/
protected function normalize_version(array $packages)
{
$normalized_packages = [];
foreach ($packages as $package => $version)
{
if (is_numeric($package))
{
if (strpos($version, ':') !== false)
{
$parts = explode(':', $version);
$normalized_packages[$parts[0]] = $parts[1];
}
else
{
$normalized_packages[$version] = '*';
}
}
else
{
$normalized_packages[$package] = $version;
}
}
return $normalized_packages;
}
}

View File

@ -0,0 +1,110 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\composer;
use Composer\IO\IOInterface;
use phpbb\composer\exception\runtime_exception;
/**
* Class to manage packages through composer.
*/
interface manager_interface
{
/**
* Installs (if necessary) a set of packages
*
* @param array $packages Packages to install.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*
* @throws runtime_exception
*/
public function install(array $packages, IOInterface $io = null);
/**
* Updates or installs a set of packages
*
* @param array $packages Packages to update.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*
* @throws runtime_exception
*/
public function update(array $packages, IOInterface $io = null);
/**
* Removes a set of packages
*
* @param array $packages Packages to remove.
* Each entry may be a name or an array associating a version constraint to a name
* @param IOInterface $io IO object used for the output
*
* @throws runtime_exception
*/
public function remove(array $packages, IOInterface $io = null);
/**
* Tells whether or not a package is managed by Composer.
*
* @param string $packages Package name
*
* @return bool
*/
public function is_managed($packages);
/**
* Returns the list of managed packages for the current type
*
* @return array The managed packages associated to their version.
*/
public function get_managed_packages();
/**
* Returns the list of managed packages for all phpBB types
*
* @return array The managed packages associated to their version.
*/
public function get_all_managed_packages();
/**
* Returns the list of available packages
*
* @return array The name of the available packages, associated to their definition. Ordered by name.
*/
public function get_available_packages();
/**
* Reset the cache
*/
public function reset_cache();
/**
* Start managing a manually installed package
*
* Remove a package installed manually and reinstall it using composer.
*
* @param string $package Package to manage
* @param IOInterface $io IO object used for the output
*
* @throws runtime_exception
*/
public function start_managing($package, $io);
/**
* Checks the requirements of the manager and returns true if it can be used.
*
* @return bool
*/
public function check_requirements();
}

View File

@ -0,0 +1,103 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\console\command\extension;
use phpbb\composer\extension_manager;
use phpbb\composer\io\console_io;
use phpbb\language\language;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class install extends \phpbb\console\command\command
{
/**
* @var extension_manager Composer extensions manager
*/
protected $manager;
/**
* @var \phpbb\language\language
*/
protected $language;
public function __construct(\phpbb\user $user, extension_manager $manager, language $language)
{
$this->manager = $manager;
$this->language = $language;
$language->add_lang('acp/extensions');
parent::__construct($user);
}
/**
* Sets the command name and description
*
* @return null
*/
protected function configure()
{
$this
->setName('extension:install')
->setDescription($this->language->lang('CLI_DESCRIPTION_EXTENSION_INSTALL'))
->addOption(
'enable',
null,
InputOption::VALUE_NONE,
$this->language->lang('CLI_DESCRIPTION_EXTENSION_INSTALL_OPTION_ENABLE'))
->addArgument(
'extensions',
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
$this->language->lang('CLI_DESCRIPTION_EXTENSION_INSTALL_ARGUMENT'))
;
}
/**
* Executes the command extension:install
*
* @param InputInterface $input
* @param OutputInterface $output
* @return integer
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->getFormatter()->setStyle('warning', new OutputFormatterStyle('black', 'yellow'));
$io = new SymfonyStyle($input, $output);
if (!$this->manager->check_requirements())
{
$io->error($this->language->lang('EXTENSIONS_COMPOSER_NOT_WRITABLE'));
return 1;
}
$composer_io = new console_io($input, $output, $this->getHelperSet(), $this->language);
$extensions = $input->getArgument('extensions');
if ($input->getOption('enable'))
{
$this->manager->set_enable_on_install(true);
}
$this->manager->install($extensions, $composer_io);
$io->success($this->language->lang('EXTENSIONS_INSTALLED'));
return 0;
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\console\command\extension;
use phpbb\composer\manager_interface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class list_available extends \phpbb\console\command\command
{
/**
* @var manager_interface Composer extensions manager
*/
protected $manager;
public function __construct(\phpbb\user $user, manager_interface $manager)
{
$this->manager = $manager;
$user->add_lang('acp/extensions');
parent::__construct($user);
}
/**
* Sets the command name and description
*
* @return null
*/
protected function configure()
{
$this
->setName('extension:list-available')
->setDescription($this->user->lang('CLI_DESCRIPTION_EXTENSION_LIST_AVAILABLE'))
;
}
/**
* Executes the command extension:install
*
* @param InputInterface $input
* @param OutputInterface $output
* @return integer
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$extensions = [];
foreach ($this->manager->get_available_packages() as $package)
{
$extensions[] = '<info>' . $package['name'] . '</info> (<comment>' . $package['version'] . '</comment>) ' . $package['url'] .
($package['description'] ? "\n" . $package['description'] : '');
}
$io->listing($extensions);
return 0;
}
}

View File

@ -0,0 +1,99 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\console\command\extension;
use phpbb\composer\exception\managed_with_error_exception;
use phpbb\composer\io\console_io;
use phpbb\composer\manager_interface;
use phpbb\language\language;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class manage extends \phpbb\console\command\command
{
/**
* @var manager_interface Composer extensions manager
*/
protected $manager;
/**
* @var \phpbb\language\language
*/
protected $language;
public function __construct(\phpbb\user $user, manager_interface $manager, language $language)
{
$this->manager = $manager;
$this->language = $language;
$language->add_lang('acp/extensions');
parent::__construct($user);
}
/**
* Sets the command name and description
*
* @return null
*/
protected function configure()
{
$this
->setName('extension:manage')
->setDescription($this->language->lang('CLI_DESCRIPTION_EXTENSION_MANAGE'))
->addArgument(
'extension',
InputArgument::REQUIRED,
$this->language->lang('CLI_DESCRIPTION_EXTENSION_MANAGE_ARGUMENT'))
;
}
/**
* Executes the command extension:install
*
* @param InputInterface $input
* @param OutputInterface $output
* @return integer
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
if (!$this->manager->check_requirements())
{
$io->error($this->language->lang('EXTENSIONS_COMPOSER_NOT_WRITABLE'));
return 1;
}
$composer_io = new console_io($input, $output, $this->getHelperSet(), $this->language);
$extension = $input->getArgument('extension');
try
{
$this->manager->start_managing($extension, $composer_io);
}
catch (managed_with_error_exception $e)
{
$io->warning($this->language->lang_array($e->getMessage(), $e->get_parameters()));
return 1;
}
$io->success($this->language->lang('EXTENSION_MANAGED_SUCCESS', $extension));
return 0;
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\console\command\extension;
use phpbb\composer\extension_manager;
use phpbb\composer\io\console_io;
use phpbb\language\language;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class remove extends \phpbb\console\command\command
{
/**
* @var extension_manager Composer extensions manager
*/
protected $manager;
/**
* @var \phpbb\language\language
*/
protected $language;
public function __construct(\phpbb\user $user, extension_manager $manager, language $language)
{
$this->manager = $manager;
$this->language = $language;
$language->add_lang('acp/extensions');
parent::__construct($user);
}
/**
* Sets the command name and description
*
* @return null
*/
protected function configure()
{
$this
->setName('extension:remove')
->setDescription($this->language->lang('CLI_DESCRIPTION_EXTENSION_REMOVE'))
->addOption(
'purge',
null,
InputOption::VALUE_NONE,
$this->language->lang('CLI_DESCRIPTION_EXTENSION_REMOVE_OPTION_PURGE'))
->addArgument(
'extensions',
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
$this->language->lang('CLI_DESCRIPTION_EXTENSION_REMOVE_ARGUMENT'))
;
}
/**
* Executes the command extension:install
*
* @param InputInterface $input
* @param OutputInterface $output
* @return integer
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->getFormatter()->setStyle('warning', new OutputFormatterStyle('black', 'yellow'));
$io = new SymfonyStyle($input, $output);
if (!$this->manager->check_requirements())
{
$io->error($this->language->lang('EXTENSIONS_COMPOSER_NOT_WRITABLE'));
return 1;
}
$composer_io = new console_io($input, $output, $this->getHelperSet(), $this->language);
$extensions = $input->getArgument('extensions');
if ($input->getOption('purge'))
{
$this->manager->set_purge_on_remove(true);
}
$this->manager->remove($extensions, $composer_io);
$io->success($this->language->lang('EXTENSIONS_REMOVED'));
return 0;
}
}

View File

@ -0,0 +1,90 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\console\command\extension;
use phpbb\composer\io\console_io;
use phpbb\composer\manager_interface;
use phpbb\language\language;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class update extends \phpbb\console\command\command
{
/**
* @var manager_interface Composer extensions manager
*/
protected $manager;
/**
* @var \phpbb\language\language
*/
protected $language;
public function __construct(\phpbb\user $user, manager_interface $manager, language $language)
{
$this->manager = $manager;
$this->language = $language;
parent::__construct($user);
}
/**
* Sets the command name and description
*
* @return null
*/
protected function configure()
{
$this
->setName('extension:update')
->setDescription($this->user->lang('CLI_DESCRIPTION_EXTENSION_UPDATE'))
->addArgument(
'extensions',
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
$this->user->lang('CLI_DESCRIPTION_EXTENSION_UPDATE_ARGUMENT'))
;
}
/**
* Executes the command extension:install
*
* @param InputInterface $input
* @param OutputInterface $output
* @return integer
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->getFormatter()->setStyle('warning', new OutputFormatterStyle('black', 'yellow'));
$io = new SymfonyStyle($input, $output);
if (!$this->manager->check_requirements())
{
$io->error($this->language->lang('EXTENSIONS_COMPOSER_NOT_WRITABLE'));
return 1;
}
$composer_io = new console_io($input, $output, $this->getHelperSet(), $this->language);
$extensions = $input->getArgument('extensions');
$this->manager->update($extensions, $composer_io);
$io->success($this->language->lang('EXTENSIONS_UPDATED'));
return 0;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\db\migration\data\v330;
class extensions_composer extends \phpbb\db\migration\migration
{
public function update_data()
{
return array(
array('config.add', array('exts_composer_repositories', json_encode([
'https://www.phpbb.com/customise/db/composer/',
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))),
array('config.add', array('exts_composer_packagist', false)),
array('config.add', array('exts_composer_json_file', 'composer-ext.json')),
array('config.add', array('exts_composer_vendor_dir', 'vendor-ext/')),
array('config.add', array('exts_composer_enable_on_install', false)),
array('config.add', array('exts_composer_purge_on_remove', true)),
array('module.add', array(
'acp',
'ACP_EXTENSION_MANAGEMENT',
array(
'module_basename' => 'acp_extensions',
'modes' => array('catalog'),
),
)),
);
}
}

View File

@ -415,6 +415,12 @@ class container_builder
$ext_container->register('cache.driver', '\\phpbb\\cache\\driver\\dummy');
$ext_container->compile();
$config = $ext_container->get('config');
if (@is_file($this->phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php'))
{
require_once($this->phpbb_root_path . $config['exts_composer_vendor_dir'] . '/autoload.php');
}
$extensions = $ext_container->get('ext.manager')->all_enabled();
// Load each extension found

View File

@ -45,6 +45,13 @@ class container_configuration implements ConfigurationInterface
->booleanNode('enable_debug_extension')->defaultValue(false)->end()
->end()
->end()
->arrayNode('extensions')
->addDefaultsIfNotSet()
->children()
->booleanNode('composer_debug')->defaultValue(false)->end()
->booleanNode('composer_verbose')->defaultValue(false)->end()
->end()
->end()
->end()
;
return $treeBuilder;

View File

@ -15,6 +15,7 @@ namespace phpbb\di\extension;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@ -92,6 +93,18 @@ class core extends Extension
$definition->addTag('twig.extension');
}
$composer_output = OutputInterface::VERBOSITY_NORMAL;
if ($config['extensions']['composer_verbose'])
{
$composer_output = OutputInterface::VERBOSITY_VERBOSE;
}
if ($config['extensions']['composer_debug'])
{
$composer_output = OutputInterface::VERBOSITY_DEBUG;
}
$container->setParameter('extensions.composer.output', $composer_output);
// Set the debug options
foreach ($config['debug'] as $name => $value)
{

View File

View File

@ -19,6 +19,11 @@ services:
ext.manager:
class: phpbb\extension\manager_mock
config:
class: phpbb\config\config
arguments:
- []
template.twig.environment:
class: Exception
arguments:

View File

@ -16,6 +16,11 @@ services:
dispatcher:
class: phpbb\db\driver\container_mock
config:
class: phpbb\config\config
arguments:
- []
template.twig.environment:
class: Exception
arguments:

View File

@ -19,6 +19,11 @@ services:
ext.manager:
class: phpbb\extension\manager_mock
config:
class: phpbb\config\config
arguments:
- []
template.twig.environment:
class: Exception
arguments: