avatar-privacy/includes/avatar-privacy/class-factory.php

579 lines
20 KiB
PHP

<?php
/**
* This file is part of Avatar Privacy.
*
* Copyright 2018-2023 Peter Putzer.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***
*
* @package mundschenk-at/avatar-privacy
* @license http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Avatar_Privacy;
use Avatar_Privacy\Vendor\Dice\Dice;
use Avatar_Privacy\Core;
use Avatar_Privacy\Core\API;
use Avatar_Privacy\Core\Settings;
use Avatar_Privacy\Component;
use Avatar_Privacy\Components;
use Avatar_Privacy\Controller;
use Avatar_Privacy\CLI;
use Avatar_Privacy\Upload_Handlers\Upload_Handler;
use Avatar_Privacy\Avatar_Handlers\Avatar_Handler;
use Avatar_Privacy\Avatar_Handlers\Default_Icons;
use Avatar_Privacy\Avatar_Handlers\Default_Icons_Handler;
use Avatar_Privacy\Avatar_Handlers\Gravatar_Cache_Handler;
use Avatar_Privacy\Avatar_Handlers\Legacy_Icon_Handler;
use Avatar_Privacy\Avatar_Handlers\User_Avatar_Handler;
use Avatar_Privacy\Avatar_Handlers\Default_Icons\Generated_Icons;
use Avatar_Privacy\Avatar_Handlers\Default_Icons\Static_Icons;
use Avatar_Privacy\Data_Storage\Cache;
use Avatar_Privacy\Data_Storage\Database;
use Avatar_Privacy\Data_Storage\Filesystem_Cache;
use Avatar_Privacy\Data_Storage\Options;
use Avatar_Privacy\Data_Storage\Network_Options;
use Avatar_Privacy\Data_Storage\Transients;
use Avatar_Privacy\Data_Storage\Site_Transients;
use Avatar_Privacy\Exceptions\Object_Factory_Exception;
use Avatar_Privacy\Integrations;
use Avatar_Privacy\Tools;
use Avatar_Privacy\Tools\HTML\User_Form;
/**
* A factory for creating Avatar_Privacy instances via dependency injection.
*
* @since 1.0.0
* @since 2.1.0 Class made concrete.
* @since 2.3.0 Moved to Avatar_Privacy\Factory.
* @since 2.4.0 Named instances converted to use class constants.
*
* @author Peter Putzer <github@mundschenk.at>
*
* @phpstan-import-type ConfigData from User_Form
*/
class Factory extends Dice {
const SHARED = [ 'shared' => true ];
// Named instances.
const USERFORM_PROFILE_INSTANCE = '$UserProfileForm';
const USERFORM_FRONTEND_INSTANCE = '$FrontendUserForm';
const USERFORM_THEME_MY_LOGIN_PROFILES_INSTANCE = '$ThemeMyLoginProfilesUserForm';
const USERFORM_BBPRESS_PROFILE_INSTANCE = '$bbPressProfileForm';
const JDENTICON_INSTANCE = '$JdenticonIdenticon';
/**
* The factory instance.
*
* @var Factory|null
*/
private static $factory;
/**
* Creates a new instance.
*/
final protected function __construct() {
}
/**
* Retrieves a factory set up for creating Avatar_Privacy instances.
*
* @since 2.1.0 Parameter $full_plugin_path replaced with AVATAR_PRIVACY_PLUGIN_FILE constant.
* @since 2.5.1 Now throws an Object_Factory_Exception in case of error.
*
* @return Factory
*
* @throws Object_Factory_Exception An exception is thrown if the factory cannot
* be created.
*/
public static function get() {
if ( ! isset( self::$factory ) ) {
// Create factory.
$factory = new static();
$factory = $factory->addRules( $factory->get_rules() );
if ( $factory instanceof Factory ) {
self::$factory = $factory;
} else {
throw new Object_Factory_Exception( 'Could not create object factory.' ); // @codeCoverageIgnore
}
}
return self::$factory;
}
/**
* Retrieves the rules for setting up the plugin.
*
* @since 2.1.0
*
* @return array
*
* @phpstan-return array<class-string|string,mixed[]>
*/
protected function get_rules() {
return [
// Shared helpers.
Cache::class => self::SHARED,
Database\Table::class => self::SHARED,
Transients::class => self::SHARED,
Site_Transients::class => self::SHARED,
Options::class => self::SHARED,
Network_Options::class => self::SHARED,
Filesystem_Cache::class => self::SHARED,
// Core API.
API::class => self::SHARED,
Core::class => self::SHARED,
Settings::class => [
'constructParams' => [ $this->get_plugin_version( \AVATAR_PRIVACY_PLUGIN_FILE ) ],
],
// The plugin controller.
Controller::class => [
'constructParams' => [ $this->get_components() ],
],
// Components.
Component::class => self::SHARED,
Components\Block_Editor::class => [
'substitutions' => [
User_Form::class => [ self::INSTANCE => self::USERFORM_FRONTEND_INSTANCE ],
],
],
Components\Command_Line_Interface::class => [
'constructParams' => [ $this->get_cli_commands() ],
],
Components\Image_Proxy::class => [
'constructParams' => [ $this->get_avatar_handlers() ],
],
Components\Integrations::class => [
'constructParams' => [ $this->get_plugin_integrations() ],
],
Components\Setup::class => [
'constructParams' => [ $this->get_database_tables() ],
],
Components\Shortcodes::class => [
'substitutions' => [
User_Form::class => [ self::INSTANCE => self::USERFORM_FRONTEND_INSTANCE ],
],
],
Components\User_Profile::class => [
'substitutions' => [
User_Form::class => [ self::INSTANCE => self::USERFORM_PROFILE_INSTANCE ],
],
],
// Default icon providers.
Static_Icons\Mystery_Icon_Provider::class => self::SHARED,
Static_Icons\Speech_Bubble_Icon_Provider::class => self::SHARED,
Static_Icons\Bowling_Pin_Icon_Provider::class => self::SHARED,
Static_Icons\Silhouette_Icon_Provider::class => self::SHARED,
// Avatar handlers.
Avatar_Handler::class => self::SHARED,
Default_Icons_Handler::class => [
'constructParams' => [ $this->get_default_icons() ],
],
// Default icon generators.
Default_Icons\Generator::class => self::SHARED,
Default_Icons\Generators\Jdenticon::class => [
'substitutions' => [
\Avatar_Privacy\Vendor\Jdenticon\Identicon::class => [ self::INSTANCE => self::JDENTICON_INSTANCE ],
],
],
Default_Icons\Generators\Rings::class => [
'constructParams' => [
512, // The bounding box dimensions.
3, // The number of rings.
],
'call' => [
[ 'setMono', [ true ] ], // The rings should be monochrome.
],
],
// Icon components.
self::JDENTICON_INSTANCE => [
'instanceOf' => \Avatar_Privacy\Vendor\Jdenticon\Identicon::class,
'constructParams' => [
// Some extra styling for the Jdenticon instance.
[ 'style' => [ 'padding' => 0 ] ],
],
],
// Upload handlers.
Upload_Handler::class => self::SHARED,
// Form helpers.
User_Form::class => self::SHARED,
self::USERFORM_PROFILE_INSTANCE => [
'instanceOf' => User_Form::class,
'constructParams' => $this->get_user_form_parameters( self::USERFORM_PROFILE_INSTANCE ),
],
self::USERFORM_BBPRESS_PROFILE_INSTANCE => [
'instanceOf' => User_Form::class,
'constructParams' => $this->get_user_form_parameters( self::USERFORM_BBPRESS_PROFILE_INSTANCE ),
],
self::USERFORM_FRONTEND_INSTANCE => [
'instanceOf' => User_Form::class,
'constructParams' => $this->get_user_form_parameters( self::USERFORM_FRONTEND_INSTANCE ),
],
self::USERFORM_THEME_MY_LOGIN_PROFILES_INSTANCE => [
'instanceOf' => User_Form::class,
'constructParams' => $this->get_user_form_parameters( self::USERFORM_THEME_MY_LOGIN_PROFILES_INSTANCE ),
],
// Plugin integrations.
Integrations\Plugin_Integration::class => self::SHARED,
Integrations\BBPress_Integration::class => [
'substitutions' => [
User_Form::class => [ self::INSTANCE => self::USERFORM_BBPRESS_PROFILE_INSTANCE ],
],
],
Integrations\Theme_My_Login_Profiles_Integration::class => [
'substitutions' => [
User_Form::class => [ self::INSTANCE => self::USERFORM_THEME_MY_LOGIN_PROFILES_INSTANCE ],
],
],
// Shared tools.
Tools\Hasher::class => self::SHARED,
Tools\Number_Generator::class => self::SHARED,
Tools\Multisite::class => self::SHARED,
Tools\Images\Color::class => self::SHARED,
Tools\Images\Editor::class => self::SHARED,
Tools\Images\PNG::class => self::SHARED,
Tools\Network\Gravatar_Service::class => self::SHARED,
];
}
/**
* Retrieves the plugin version.
*
* @since 2.1.0
*
* @param string $plugin_file The full plugin path.
*
* @return string
*/
protected function get_plugin_version( $plugin_file ) {
// Load version from plugin data.
if ( ! \function_exists( 'get_plugin_data' ) ) {
require_once \ABSPATH . 'wp-admin/includes/plugin.php';
}
return \get_plugin_data( $plugin_file, false, false )['Version'];
}
/**
* Retrieves the list of plugin components run during normal operations
* (i.e. not including the Uninstallation component).
*
* @return array {
* An array of `Component` instances in `Dice` syntax.
*
* @type array {
* @type string $instance The classname.
* }
* }
*
* @phpstan-return array<int, array<string, class-string<Component>>>
*/
protected function get_components() {
return [
[ self::INSTANCE => Components\Setup::class ],
[ self::INSTANCE => Components\Image_Proxy::class ],
[ self::INSTANCE => Components\Avatar_Handling::class ],
[ self::INSTANCE => Components\Comments::class ],
[ self::INSTANCE => Components\User_Profile::class ],
[ self::INSTANCE => Components\Settings_Page::class ],
[ self::INSTANCE => Components\Network_Settings_Page::class ],
[ self::INSTANCE => Components\Privacy_Tools::class ],
[ self::INSTANCE => Components\Integrations::class ],
[ self::INSTANCE => Components\Shortcodes::class ],
[ self::INSTANCE => Components\Block_Editor::class ],
[ self::INSTANCE => Components\Command_Line_Interface::class ],
];
}
/**
* Retrieves a list of default icon providers suitable for inclusion in a `Dice` rule.
*
* @since 2.1.0
*
* @return array {
* An array of `Icon_Provider` instances in `Dice` syntax.
*
* @type array {
* @type string $instance The classname.
* }
* }
*
* @phpstan-return array<array<self::INSTANCE, class-string<Default_Icons\Icon_Provider>>>
*/
protected function get_default_icons() {
return [
// These are sorted as the should appear for selection in the discussion settings.
[ self::INSTANCE => Static_Icons\Mystery_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Identicon_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Wavatar_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Monster_ID_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Retro_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Rings_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Bird_Avatar_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Cat_Avatar_Icon_Provider::class ],
[ self::INSTANCE => Generated_Icons\Robohash_Icon_Provider::class ],
[ self::INSTANCE => Static_Icons\Speech_Bubble_Icon_Provider::class ],
[ self::INSTANCE => Static_Icons\Bowling_Pin_Icon_Provider::class ],
[ self::INSTANCE => Static_Icons\Silhouette_Icon_Provider::class ],
[ self::INSTANCE => Default_Icons\Custom_Icon_Provider::class ],
];
}
/**
* Retrieves a list of plugin integrations.
*
* @since 2.1.0
*
* @return array {
* An array of `Plugin_Integration` instances in `Dice` syntax.
*
* @type array {
* @type string $instance The classname.
* }
* }
*
* @phpstan-return array<array<self::INSTANCE, class-string<Integrations\Plugin_Integration>>>
*/
protected function get_plugin_integrations() {
return [
[ self::INSTANCE => Integrations\BBPress_Integration::class ],
[ self::INSTANCE => Integrations\BuddyPress_Integration::class ],
[ self::INSTANCE => Integrations\Simple_Author_Box_Integration::class ],
[ self::INSTANCE => Integrations\Simple_Local_Avatars_Integration::class ],
[ self::INSTANCE => Integrations\Simple_User_Avatar_Integration::class ],
[ self::INSTANCE => Integrations\Theme_My_Login_Profiles_Integration::class ],
[ self::INSTANCE => Integrations\Ultimate_Member_Integration::class ],
[ self::INSTANCE => Integrations\WPDiscuz_Integration::class ],
[ self::INSTANCE => Integrations\WP_User_Manager_Integration::class ],
];
}
/**
* Retrieves a list of CLI commands.
*
* @since 2.3.0
*
* @return array {
* An array of `Command` instances in `Dice` syntax.
*
* @type array {
* @type string $instance The classname.
* }
* }
*
* @phpstan-return array<array<self::INSTANCE, class-string<CLI\Command>>>
*/
protected function get_cli_commands() {
return [
[ self::INSTANCE => CLI\Cron_Command::class ],
[ self::INSTANCE => CLI\Database_Command::class ],
[ self::INSTANCE => CLI\Default_Command::class ],
[ self::INSTANCE => CLI\Uninstall_Command::class ],
[ self::INSTANCE => CLI\User_Command::class ],
];
}
/**
* Retrieves a list of database table handlers.
*
* @since 2.4.0
*
* @return array {
* An array of `Table` instances in `Dice` syntax.
*
* @type array {
* @type string $instance The classname.
* }
* }
*
* @phpstan-return array<array<self::INSTANCE, class-string<Database\Table>>>
*/
protected function get_database_tables() {
$classes = [
Database\Comment_Author_Table::class,
Database\Hashes_Table::class,
];
$tables = [];
foreach ( $classes as $table_class ) {
$tables[ $table_class::TABLE_BASENAME ] = [ self::INSTANCE => $table_class ];
}
return $tables;
}
/**
* Retrieves a list of avatar handlers.
*
* @since 2.4.0
*
* @return array {
* An array of `Avatar_Handler` instances (in `Dice` syntax), indexed by
* their filter hooks.
*
* @type array {
* @type array $hook The instance definition.
* }
* }
*
* @phpstan-return array<array<self::INSTANCE, class-string<Avatar_Handler>>>
*/
protected function get_avatar_handlers() {
return [
'avatar_privacy_user_avatar_icon_url' => [ self::INSTANCE => User_Avatar_Handler::class ],
'avatar_privacy_gravatar_icon_url' => [ self::INSTANCE => Gravatar_Cache_Handler::class ],
'avatar_privacy_default_icon_url' => [ self::INSTANCE => Default_Icons_Handler::class ],
'avatar_privacy_legacy_icon_url' => [ self::INSTANCE => Legacy_Icon_Handler::class ],
];
}
/**
* Retrieves the constructor parameters for configuring named user form instances.
*
* @since 2.4.0
*
* @param string $instance The named instance.
*
* @return array The constructor parameter array for the named instance.
*
* @throws \InvalidArgumentException An exception is raised when $instance is
* not one of the expected constants.
*
* @phpstan-return array{ 0: ConfigData, 1: ConfigData, 2: ConfigData }
*/
protected function get_user_form_parameters( $instance ) {
switch ( $instance ) {
case self::USERFORM_PROFILE_INSTANCE:
$use_gravatar = [
'nonce' => 'avatar_privacy_use_gravatar_nonce_',
'action' => 'avatar_privacy_edit_use_gravatar',
'field' => 'avatar-privacy-use-gravatar',
'partial' => 'admin/partials/profile/use-gravatar.php',
];
$allow_anonymous = [
'nonce' => 'avatar_privacy_allow_anonymous_nonce_',
'action' => 'avatar_privacy_edit_allow_anonymous',
'field' => 'avatar-privacy-allow-anonymous',
'partial' => 'admin/partials/profile/allow-anonymous.php',
];
$user_avatar = [
'nonce' => 'avatar_privacy_upload_avatar_nonce_',
'action' => 'avatar_privacy_upload_avatar',
'field' => 'avatar-privacy-user-avatar-upload',
'erase' => 'avatar-privacy-user-avatar-erase',
'partial' => 'admin/partials/profile/user-avatar-upload.php',
];
break;
case self::USERFORM_BBPRESS_PROFILE_INSTANCE:
$use_gravatar = [
'nonce' => 'avatar_privacy_bbpress_use_gravatar_nonce_',
'action' => 'avatar_privacy_bbpress_edit_use_gravatar',
'field' => 'avatar-privacy-bbpress-use-gravatar',
'partial' => 'public/partials/bbpress/profile/use-gravatar.php',
];
$allow_anonymous = [
'nonce' => 'avatar_privacy_bbpress_allow_anonymous_nonce_',
'action' => 'avatar_privacy_bbpress_edit_allow_anonymous',
'field' => 'avatar-privacy-bbpress-allow-anonymous',
'partial' => 'public/partials/bbpress/profile/allow-anonymous.php',
];
$user_avatar = [
'nonce' => 'avatar_privacy_bbpress_upload_avatar_nonce_',
'action' => 'avatar_privacy_bbpress_upload_avatar',
'field' => 'avatar-privacy-bbpress-user-avatar-upload',
'erase' => 'avatar-privacy-bbpress-user-avatar-erase',
'partial' => 'public/partials/bbpress/profile/user-avatar-upload.php',
];
break;
case self::USERFORM_FRONTEND_INSTANCE:
$use_gravatar = [
'nonce' => 'avatar_privacy_frontend_use_gravatar_nonce_',
'action' => 'avatar_privacy_frontend_edit_use_gravatar',
'field' => 'avatar-privacy-frontend-use-gravatar',
'partial' => 'public/partials/profile/use-gravatar.php',
];
$allow_anonymous = [
'nonce' => 'avatar_privacy_frontend_allow_anonymous_nonce_',
'action' => 'avatar_privacy_frontend_edit_allow_anonymous',
'field' => 'avatar_privacy-frontend-allow_anonymous',
'partial' => 'public/partials/profile/allow-anonymous.php',
];
$user_avatar = [
'nonce' => 'avatar_privacy_frontend_upload_avatar_nonce_',
'action' => 'avatar_privacy_frontend_upload_avatar',
'field' => 'avatar-privacy-frontend-user-avatar-upload',
'erase' => 'avatar-privacy-frontend-user-avatar-erase',
'partial' => 'public/partials/profile/user-avatar-upload.php',
];
break;
case self::USERFORM_THEME_MY_LOGIN_PROFILES_INSTANCE:
$use_gravatar = [
'nonce' => 'avatar_privacy_tml_profiles_use_gravatar_nonce_',
'action' => 'avatar_privacy_tml_profiles_edit_use_gravatar',
'field' => 'avatar-privacy-tml-profiles-use-gravatar',
'partial' => 'public/partials/tml-profiles/use-gravatar.php',
];
$allow_anonymous = [
'nonce' => 'avatar_privacy_tml_profiles_allow_anonymous_nonce_',
'action' => 'avatar_privacy_tml_profiles_edit_allow_anonymous',
'field' => 'avatar_privacy-tml-profiles-allow_anonymous',
'partial' => 'public/partials/tml-profiles/allow-anonymous.php',
];
$user_avatar = [
'nonce' => 'avatar_privacy_tml_profiles_upload_avatar_nonce_',
'action' => 'avatar_privacy_tml_profiles_upload_avatar',
'field' => 'avatar-privacy-tml-profiles-user-avatar-upload',
'erase' => 'avatar-privacy-tml-profiles-user-avatar-erase',
'partial' => 'public/partials/tml-profiles/user-avatar-upload.php',
];
break;
default:
throw new \InvalidArgumentException( "Invalid named instance {$instance}." );
}
return [ $use_gravatar, $allow_anonymous, $user_avatar ];
}
}