Merge branch 'develop' into mark-internal-code

This commit is contained in:
Art4 2025-01-22 19:46:49 +00:00
commit 179ccbc08c
7 changed files with 158 additions and 25 deletions

View file

@ -52,4 +52,4 @@ $container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
$app = \Friendica\App::fromContainer($container); $app = \Friendica\App::fromContainer($container);
$app->processEjabberd(); $app->processEjabberd($_SERVER);

View file

@ -19,4 +19,4 @@ $container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
$app = \Friendica\App::fromContainer($container); $app = \Friendica\App::fromContainer($container);
$app->processConsole($_SERVER['argv'] ?? []); $app->processConsole($_SERVER);

View file

@ -26,11 +26,13 @@ require dirname(__DIR__) . '/vendor/autoload.php';
fwrite(STDOUT, '`bin/daemon.php` is deprecated since 2024.02 and will be removed in 5 months, please use `bin/console.php daemon` instead.' . \PHP_EOL); fwrite(STDOUT, '`bin/daemon.php` is deprecated since 2024.02 and will be removed in 5 months, please use `bin/console.php daemon` instead.' . \PHP_EOL);
// BC: Add console command as second argument
$argv = $_SERVER['argv'] ?? []; $argv = $_SERVER['argv'] ?? [];
array_splice($argv, 1, 0, "daemon"); array_splice($argv, 1, 0, "daemon");
$_SERVER['argv'] = $argv;
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__)); $container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
$app = \Friendica\App::fromContainer($container); $app = \Friendica\App::fromContainer($container);
$app->processConsole($argv); $app->processConsole($_SERVER);

View file

@ -21,11 +21,13 @@ require dirname(__DIR__) . '/vendor/autoload.php';
fwrite(STDOUT, '`bin/jetstream.php` is deprecated since 2024.02 and will be removed in 5 months, please use `bin/console.php jetstream` instead.' . \PHP_EOL); fwrite(STDOUT, '`bin/jetstream.php` is deprecated since 2024.02 and will be removed in 5 months, please use `bin/console.php jetstream` instead.' . \PHP_EOL);
// BC: Add console command as second argument
$argv = $_SERVER['argv'] ?? []; $argv = $_SERVER['argv'] ?? [];
array_splice($argv, 1, 0, "jetstream"); array_splice($argv, 1, 0, "jetstream");
$_SERVER['argv'] = $argv;
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__)); $container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
$app = \Friendica\App::fromContainer($container); $app = \Friendica\App::fromContainer($container);
$app->processConsole($argv); $app->processConsole($_SERVER);

View file

@ -23,11 +23,13 @@ require dirname(__DIR__) . '/vendor/autoload.php';
fwrite(STDOUT, '`bin/worker.php` is deprecated since 2024.02 and will be removed in 5 months, please use `bin/console.php worker` instead.' . \PHP_EOL); fwrite(STDOUT, '`bin/worker.php` is deprecated since 2024.02 and will be removed in 5 months, please use `bin/console.php worker` instead.' . \PHP_EOL);
// BC: Add console command as second argument
$argv = $_SERVER['argv'] ?? []; $argv = $_SERVER['argv'] ?? [];
array_splice($argv, 1, 0, "worker"); array_splice($argv, 1, 0, "worker");
$_SERVER['argv'] = $argv;
$container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__)); $container = \Friendica\Core\DiceContainer::fromBasePath(dirname(__DIR__));
$app = \Friendica\App::fromContainer($container); $app = \Friendica\App::fromContainer($container);
$app->processConsole($argv); $app->processConsole($_SERVER);

View file

@ -156,3 +156,97 @@ If you are interested in improving those clients, please contact the developers
* iOS: *currently no client* * iOS: *currently no client*
* SailfishOS: **Friendiy** [src](https://kirgroup.com/projects/fabrixxm/harbour-friendly) - developed by [Fabio](https://kirgroup.com/profile/fabrixxm/profile) * SailfishOS: **Friendiy** [src](https://kirgroup.com/projects/fabrixxm/harbour-friendly) - developed by [Fabio](https://kirgroup.com/profile/fabrixxm/profile)
* Windows: **Friendica Mobile** for Windows versions [before 8.1](http://windowsphone.com/s?appid=e3257730-c9cf-4935-9620-5261e3505c67) and [Windows 10](https://www.microsoft.com/store/apps/9nblggh0fhmn) - developed by [Gerhard Seeber](http://mozartweg.dyndns.org/friendica/profile/gerhard/profile) * Windows: **Friendica Mobile** for Windows versions [before 8.1](http://windowsphone.com/s?appid=e3257730-c9cf-4935-9620-5261e3505c67) and [Windows 10](https://www.microsoft.com/store/apps/9nblggh0fhmn) - developed by [Gerhard Seeber](http://mozartweg.dyndns.org/friendica/profile/gerhard/profile)
## Backward compatibility
### Backward Compatibility Promise
Friendica can be extended by addons.
These addons relies on many classes and conventions from Friendica.
As developers our work on Friendica should not break things in the addons without giving the addon maintainers a chance to fix their addons.
Our goal is to build trust for the addon maintainers but also allow Friendica developers to move on.
This is called the Backward Compatibility Promise.
Inspired by the [Symonfy BC promise](https://symfony.com/doc/current/contributing/code/bc.html) we promise BC for every class, interface, trait, enum, function, constant, etc., but with the exception of:
- Classes, interfaces, traits, enums, functions, methods, properties and constants marked as `@internal` or `@private`
- Extending or modifying a `final` class or method in any way
- Calling `private` methods (via Reflection)
- Accessing `private` properties (via Reflection)
- Accessing `private` methods (via Reflection)
- Accessing `private` constants (via Reflection)
- New properties on overridden `protected` methods
- Possible name collisions with new methods in an extended class (addon developers should prefix their custom methods in the extending classes in an appropriate way)
- Dropping support for every PHP version that has reached end of life
### Deprecation and removing features
As the development goes by Friendica needs to get rid of old code and concepts.
This will be done in 3 steps to give addon maintainers a chance to adjust their addons.
**1. Label deprecation**
If we as the Friendica maintainers decide to remove some functions, classes, interface, etc. we start this by adding a `@deprecated` PHPDoc note on the code.
For instance the class `Friendica\Core\Logger` should be removed, so we add the following note with a possible replacement:
```php
/**
* Logger functions
*
* @deprecated 2025.02 Use constructor injection or `DI::logger()` instead
*/
class Logger {/* ... */}
```
This way addon developers might be notified early by their IDE or other tools that the usage of the class is deprecated.
In Friendica we can now start to replace all occurrences and usage of this class with the alternative.
The deprecation label COULD be remain over multiple releases.
As long as the code that is labeled with `@deprecated` is used inside Friendica or the official addon repository, it SHOULD NOT be hard deprecated.
**2. Hard deprecation**
If the deprecated code is no longer used inside Friendica or the official addons it MUST be hard deprecated.
The code MUST NOT be deleted.
Starting from the next release, it MUST be stay for at least 5 months.
Hard deprecated code COULD remain longer than 5 months, depending on when a release appears.
Addon developer MUST NOT consider that they have more than 5 months to adjust their code.
Hard deprecation code means that the code triggers an `E_USER_DEPRECATION` error if it is called.
For instance with the deprecated class `Friendica\Core\Logger` the call of every method should trigger an error:
```php
/**
* Logger functions
*
* @deprecated 2025.02 Use constructor injection or `DI::logger()` instead
*/
class Logger {
public static function info(string $message, array $context = [])
{
trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.05 and will be removed after 5 months, use constructor injection or `DI::logger()` instead.', E_USER_DEPRECATED);
self::getInstance()->info($message, $context);
}
/* ... */
}
```
This way the maintainer or users of addons will be notified that the addon will stop working in one of the next releases.
The addon maintainer now has at least 5 months or at least one release to fix the deprecations.
Please note that the deprecation message contains the release that will be released next.
In the example the code was hard deprecated with release `2025.05`, so it COULD be removed earliest with the `2025.11` release.
**3. Code Removing**
We promise BC for deprecated code for at least 5 months, starting from the release the deprecation was announced.
After this time the deprecated code COULD be remove within the next release.
Breaking changes MUST be happen only in a new release but MUST be hard deprecated first.
The BC promise refers only to releases, respective the `stable` branch.
Deprecated code on other branches like `develop` or RC branches could be removed earlier.
This is not a BC break as long as the release will be published 5 months after the hard deprecation.
If a release breaks BC without deprecation or earlier than 5 months, this SHOULD considered as a bug and BC SHOULD be restored in a bugfix release.

View file

@ -165,16 +165,18 @@ class App
$this->session = $this->container->create(IHandleUserSessions::class); $this->session = $this->container->create(IHandleUserSessions::class);
$this->appHelper = $this->container->create(AppHelper::class); $this->appHelper = $this->container->create(AppHelper::class);
$this->loadSetupForFrontend( $this->load(
$request, $request->getServerParams(),
$this->container->create(DbaDefinition::class), $this->container->create(DbaDefinition::class),
$this->container->create(ViewDefinition::class), $this->container->create(ViewDefinition::class),
$this->mode,
$this->config,
$this->profiler,
$this->appHelper,
); );
$this->registerTemplateEngine(); $this->registerTemplateEngine();
$this->mode->setExecutor(Mode::INDEX);
$this->runFrontend( $this->runFrontend(
$this->container->create(IManagePersonalConfigValues::class), $this->container->create(IManagePersonalConfigValues::class),
$this->container->create(Page::class), $this->container->create(Page::class),
@ -188,8 +190,10 @@ class App
/** /**
* @internal * @internal
*/ */
public function processConsole(array $argv): void public function processConsole(array $serverParams): void
{ {
$argv = $serverParams['argv'] ?? [];
$this->setupContainerForAddons(); $this->setupContainerForAddons();
$this->setupLogChannel($this->determineLogChannel($argv)); $this->setupLogChannel($this->determineLogChannel($argv));
@ -198,6 +202,16 @@ class App
$this->registerErrorHandler(); $this->registerErrorHandler();
$this->load(
$serverParams,
$this->container->create(DbaDefinition::class),
$this->container->create(ViewDefinition::class),
$this->container->create(Mode::class),
$this->container->create(IManageConfigValues::class),
$this->container->create(Profiler::class),
$this->container->create(AppHelper::class),
);
$this->registerTemplateEngine(); $this->registerTemplateEngine();
(\Friendica\Core\Console::create($this->container, $argv))->execute(); (\Friendica\Core\Console::create($this->container, $argv))->execute();
@ -206,7 +220,7 @@ class App
/** /**
* @internal * @internal
*/ */
public function processEjabberd(): void public function processEjabberd(array $serverParams): void
{ {
$this->setupContainerForAddons(); $this->setupContainerForAddons();
@ -216,6 +230,16 @@ class App
$this->registerErrorHandler(); $this->registerErrorHandler();
$this->load(
$serverParams,
$this->container->create(DbaDefinition::class),
$this->container->create(ViewDefinition::class),
$this->container->create(Mode::class),
$this->container->create(IManageConfigValues::class),
$this->container->create(Profiler::class),
$this->container->create(AppHelper::class),
);
/** @var BasePath */ /** @var BasePath */
$basePath = $this->container->create(BasePath::class); $basePath = $this->container->create(BasePath::class);
@ -285,14 +309,21 @@ class App
/** /**
* Load the whole app instance * Load the whole app instance
*/ */
private function loadSetupForFrontend(ServerRequestInterface $request, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition) private function load(
{ array $serverParams,
if ($this->config->get('system', 'ini_max_execution_time') !== false) { DbaDefinition $dbaDefinition,
set_time_limit((int)$this->config->get('system', 'ini_max_execution_time')); ViewDefinition $viewDefinition,
Mode $mode,
IManageConfigValues $config,
Profiler $profiler,
AppHelper $appHelper
): void {
if ($config->get('system', 'ini_max_execution_time') !== false) {
set_time_limit((int) $config->get('system', 'ini_max_execution_time'));
} }
if ($this->config->get('system', 'ini_pcre_backtrack_limit') !== false) { if ($config->get('system', 'ini_pcre_backtrack_limit') !== false) {
ini_set('pcre.backtrack_limit', (int)$this->config->get('system', 'ini_pcre_backtrack_limit')); ini_set('pcre.backtrack_limit', (int) $config->get('system', 'ini_pcre_backtrack_limit'));
} }
// Normally this constant is defined - but not if "pcntl" isn't installed // Normally this constant is defined - but not if "pcntl" isn't installed
@ -303,11 +334,11 @@ class App
// Ensure that all "strtotime" operations do run timezone independent // Ensure that all "strtotime" operations do run timezone independent
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
$this->profiler->reset(); $profiler->reset();
if ($this->mode->has(Mode::DBAVAILABLE)) { if ($mode->has(Mode::DBAVAILABLE)) {
Core\Hook::loadHooks(); Core\Hook::loadHooks();
$loader = (new Config())->createConfigFileManager($this->appHelper->getBasePath(), $request->getServerParams()); $loader = (new Config())->createConfigFileManager($appHelper->getBasePath(), $serverParams);
Core\Hook::callAll('load_config', $loader); Core\Hook::callAll('load_config', $loader);
// Hooks are now working, reload the whole definitions with hook enabled // Hooks are now working, reload the whole definitions with hook enabled
@ -315,7 +346,7 @@ class App
$viewDefinition->load(true); $viewDefinition->load(true);
} }
$this->loadDefaultTimezone(); $this->loadDefaultTimezone($config, $appHelper);
} }
/** /**
@ -325,16 +356,16 @@ class App
* *
* @global string $default_timezone * @global string $default_timezone
*/ */
private function loadDefaultTimezone() private function loadDefaultTimezone(IManageConfigValues $config, AppHelper $appHelper)
{ {
if ($this->config->get('system', 'default_timezone')) { if ($config->get('system', 'default_timezone')) {
$timezone = $this->config->get('system', 'default_timezone', 'UTC'); $timezone = $config->get('system', 'default_timezone', 'UTC');
} else { } else {
global $default_timezone; global $default_timezone;
$timezone = $default_timezone ?? '' ?: 'UTC'; $timezone = $default_timezone ?? '' ?: 'UTC';
} }
$this->appHelper->setTimeZone($timezone); $appHelper->setTimeZone($timezone);
} }
/** /**
@ -361,6 +392,8 @@ class App
float $start_time, float $start_time,
ServerRequestInterface $request ServerRequestInterface $request
) { ) {
$this->mode->setExecutor(Mode::INDEX);
$httpInput = new HTTPInputData($request->getServerParams()); $httpInput = new HTTPInputData($request->getServerParams());
$serverVars = $request->getServerParams(); $serverVars = $request->getServerParams();
$queryVars = $request->getQueryParams(); $queryVars = $request->getQueryParams();