Skip to content

Commit

Permalink
Trying to add deterministic initialization. (#14168)
Browse files Browse the repository at this point in the history
* Trying to add deterministic initialization.

This change tries several new ways to initialize objects by using hooks instead of initalizing manually.

* Fixed the order in which init happens, fixed tests.

* Fixes standalone sync suite test run and removes redundant init call.

* Added a config package to assist with initialization.

* Added basic configuration to the config package.

* Additional init parameter for the Actions class.

* Brought the init call back because we need at least one, props @kbrown9.

* Reverted Sync changes related to passing instances.

* Rollback and taking a different direction: separate instances where possible, feature requirement instead of configuration.

* Added a Jetpack::configure call to the bootstrap, props @kbrown9 for the fix!

* Added a README file for the config package.

* Update composer.lock after rebasing against master

* Refactored the way we initalize classes and added one time init protection.

* Added a README part about adding your package to the Config class.

* Updated priority number in the README, props @kbrown9 for spotting that!

* Fixed the comment.

* Fixed the ensure_class method, removed the feature variable that is no longer available.

* Added feature ensure constants to make ensure call return values more logical.

* Updated the version number in the filter comment.

Co-authored-by: Brandon Kraft <public@brandonkraft.com>
  • Loading branch information
zinigor and kraftbj authored Jan 10, 2020
1 parent 8bc4962 commit c99e4c9
Show file tree
Hide file tree
Showing 16 changed files with 419 additions and 69 deletions.
65 changes: 37 additions & 28 deletions class.jetpack.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<?php
use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
use Automattic\Jetpack\Config;
use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Connection\REST_Connector as REST_Connector;
use Automattic\Jetpack\Connection\XMLRPC_Connector as XMLRPC_Connector;
use Automattic\Jetpack\Connection\Utils as Connection_Utils;
use Automattic\Jetpack\Constants;
use Automattic\Jetpack\Partner;
Expand Down Expand Up @@ -48,8 +47,6 @@ class Jetpack {

public $HTTP_RAW_POST_DATA = null; // copy of $GLOBALS['HTTP_RAW_POST_DATA']

private $tracking;

/**
* @var array The handles of styles that are concatenated into jetpack.css.
*
Expand Down Expand Up @@ -561,17 +558,7 @@ private function __construct() {
*/
add_action( 'init', array( $this, 'deprecated_hooks' ) );

/*
* Enable enhanced handling of previewing sites in Calypso
*/
if ( self::is_active() ) {
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-iframe-embed.php';
add_action( 'init', array( 'Jetpack_Iframe_Embed', 'init' ), 9, 0 );
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-keyring-service-helper.php';
add_action( 'init', array( 'Jetpack_Keyring_Service_Helper', 'init' ), 9, 0 );
}

add_action( 'plugins_loaded', array( $this, 'after_plugins_loaded' ) );
add_action( 'plugins_loaded', array( __CLASS__, 'configure' ), 1 );
add_action( 'plugins_loaded', array( $this, 'late_initialization' ), 90 );

add_filter(
Expand Down Expand Up @@ -737,23 +724,33 @@ function( $callable ) {
}

/**
* Runs after all the plugins have loaded but before init.
* Before everything else starts getting initalized, we need to initialize Jetpack using the
* Config object.
*/
function after_plugins_loaded() {
public static function configure() {
$config = new Config();

Partner::init();
$terms_of_service = new Terms_Of_Service();
$tracking = new Plugin_Tracking();
if ( $terms_of_service->has_agreed() ) {
add_action( 'init', array( $tracking, 'init' ) );
} else {
/**
* Initialize tracking right after the user agrees to the terms of service.
*/
add_action( 'jetpack_agreed_to_terms_of_service', array( $tracking, 'init' ) );
foreach (
array(
'sync',
'tracking',
'tos',
)
as $feature
) {
$config->ensure( $feature );
}

/*
* Enable enhanced handling of previewing sites in Calypso
*/
if ( self::is_active() ) {
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-iframe-embed.php';
add_action( 'init', array( 'Jetpack_Iframe_Embed', 'init' ), 9, 0 );
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-keyring-service-helper.php';
add_action( 'init', array( 'Jetpack_Keyring_Service_Helper', 'init' ), 9, 0 );
}

add_filter( 'map_meta_cap', array( $this, 'jetpack_custom_caps' ), 1, 4 );
}

/**
Expand All @@ -763,6 +760,11 @@ function after_plugins_loaded() {
* @action plugins_loaded
*/
public function late_initialization() {
self::plugin_textdomain();
self::load_modules();

Partner::init();

/**
* Fires when Jetpack is fully loaded and ready. This is the point where it's safe
* to instantiate classes from packages and namespaces that are managed by the Jetpack Autoloader.
Expand All @@ -772,6 +774,8 @@ public function late_initialization() {
* @param Jetpack $jetpack the main plugin class object.
*/
do_action( 'jetpack_loaded', $this );

add_filter( 'map_meta_cap', array( $this, 'jetpack_custom_caps' ), 1, 4 );
}

/**
Expand Down Expand Up @@ -5129,6 +5133,11 @@ public static function xmlrpc_api_url() {
return self::connection()->xmlrpc_api_url();
}

/**
* Returns the connection manager object.
*
* @return Automattic\Jetpack\Connection\Manager
*/
public static function connection() {
return self::init()->connection_manager;
}
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"automattic/jetpack-autoloader": "@dev",
"automattic/jetpack-backup": "@dev",
"automattic/jetpack-compat": "@dev",
"automattic/jetpack-config": "@dev",
"automattic/jetpack-connection": "@dev",
"automattic/jetpack-constants": "@dev",
"automattic/jetpack-error": "@dev",
Expand Down
22 changes: 21 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions load-jetpack.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ function jetpack_should_use_minified_assets() {
require_once JETPACK__PLUGIN_DIR . 'class.jetpack-connection-banner.php';
require_once JETPACK__PLUGIN_DIR . 'class.jetpack-plan.php';

Automattic\Jetpack\Sync\Main::init();

if ( is_admin() ) {
require_once JETPACK__PLUGIN_DIR . 'class.jetpack-admin.php';
$jitm = new Automattic\Jetpack\JITM();
Expand Down
1 change: 0 additions & 1 deletion packages/autoloader/src/autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ function autoloader( $class_name ) {
'Jetpack_Options',
'Jetpack_Signature',
'Jetpack_XMLRPC_Server',
'Automattic\Jetpack\Sync\Main',
'Automattic\Jetpack\Constants',
'Automattic\Jetpack\Tracking',
),
Expand Down
126 changes: 126 additions & 0 deletions packages/config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Jetpack Configuration

Allows for enabling and initializing of Jetpack features provided by
other packages.

# Usage

Add this package as a dependency to your project:

```
composer require automattic/jetpack-config
```

Add every other package you're planning to configure:

```
composer require automattic/jetpack-sync
composer require automattic/jetpack-tracking
composer require automattic/jetpack-terms-of-service
```

In your code initialize the configuration package at or before
plugins_loaded priority 1:

```
use Automattic/Jetpack/Config;
// Configuring Jetpack as early as plugins_loaded priority 1
// to make sure every action handler gets properly set.
add_action( 'plugins_loaded', 'configure_jetpack', 1 );
function configure_jetpack() {
$config = new Config();
foreach (
array(
'sync',
'tracking',
'tos',
)
as $feature
) {
$config->ensure( $feature );
}
}
```

# Adding your package to the config class

You can have your package initialized using the Config class by
adding several things.

## The configure method

It's better to have one static configure method in your package
class. That method will be called early on the `plugins_loaded`
hook. This way you can add your own `plugins_loaded` handlers with
standard priority and they will get executed:

```
class Configurable_Package {
public static function configure() {
add_action( 'plugins_loaded', array( __CLASS__, 'on_plugins_loaded' );
}
public static function on_plugins_loaded() {
self::do_interesting_stuff();
}
}
```

## The feature enabling method

An enabling method should be added to the Config class and should only contain your configuration method call.

```
public function enable_configurable_package() {
Configurable_Package::configure();
return true;
}
```

Note that the method name should use the feature slug, in this case
your feature slug is `configurable_package` for the sake of
simplicity. When you're adding your feature it should be unique and
recognizable, like `sync` or `tracking`.

## The feature slug

To make sure the feature is supported by the Config class, you need to
add its slug to the config class property:

```
/**
* The initial setting values.
*
* @var Array
*/
protected $config = array(
// ...
'configurable_package' => false,
// ...
);
```

## The ensure call

Finally you need to add a block that will check if your package is
loaded and mark it to be initialized:

```
if ( $this->config['configurable_package'] ) {
$this->ensure_class( 'Configurable_Package' ) && $this->ensure_feature( 'configurable_package' );
}
```

This code does three things: it checks whether the current setup has
requested your package to be loaded. Next it checks if the class that
you need for the package to run is present, and then it adds the hook
handlers that initialize your class. After that you can use the config
package's interface in a Jetpack package consumer application and load
your package as shown in the first section of this README.
13 changes: 13 additions & 0 deletions packages/config/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "automattic/jetpack-config",
"description": "Jetpack configuration package that initializes other packages and configures Jetpack's functionality. Can be used as a base for all variants of Jetpack package usage.",
"type": "library",
"license": "GPL-2.0-or-later",
"minimum-stability": "dev",
"require": {},
"autoload": {
"classmap": [
"src/"
]
}
}
Loading

0 comments on commit c99e4c9

Please sign in to comment.