📜 ⬆️ ⬇️

Data transfer via features API to Drupal - add a new component for export

Recently, I needed to transfer the metatag module settings from a local server to a combat server. For this, I wanted to use the features module, but I was disappointed - the metatag module does not support the features API. Googling did nothing, I found only a few crutches, like "dump the metatags_config table and execute the query in combat". So I decided to figure out how to add a new entity for transferring through features.


I will tell how to do this on the example of the metatag module.
First you need to implement the features_api hook, it defines the components for export via features.
/ **
* Implements hook_features_api ().
* /
function metatag_features_api ( ) {
$ components = array (
'metatags' => array (
'name' => t ( 'metatags' ) ,
'features_source' => TRUE ,
'default_hook' => 'metatag_export_default' ,
'default_file' => FEATURES_DEFAULTS_INCLUDED ,
'file' => drupal_get_path ( 'module' , 'metatag' ) . '/metatag.features.inc' ,
) ,
) ;
return $ components ;
}

It is worth paying attention to the key of the default_hook array. It defines the hook that will be used to get the data from the feature. I think it is no secret to anyone that the "feature" is a module. We will implement the metatag_export_default hook in this module and will combine the exported data there. The rest of the hooks I brought to a separate file metatag.features.inc

Another important point is that hook_features_api is a regular hook and works like MODULE_NAME_features_api. The rest of the hooks to be discussed are formed using the name of the exported component instead of the module name as usual. For example, features_export_options hook.
')
In this hook, we return an array with items that can be transferred via a feature. In the case of the metatag module, this is an array of pointers to meta tag options for various types of pages (for example global, node, taxonomy_term).

/ **
* Implements hook_features_export_options ().
* /
function metatags_features_export_options ( ) {
$ instances = metatag_config_instance_info ( ) ;
foreach ( $ instances as $ key => $ instance ) {
$ options [ $ key ] = $ key ;
} ;
return $ options ;
}


These items will be available in the corresponding section metatags when creating a new "feature"



The next features_export_render hook, it generates a code for the features file in which the exported data is stored.

/ **
* Implements hook_features_export_render ().
* /
function metatags_features_export_render ( $ module_name , $ data , $ export = NULL ) {
$ code = array ( ) ;
$ code [ ] = '$ config = array ();' ;
$ code [ ] = '' ;

foreach ( $ data as $ key => $ name ) {
if ( is_object ( $ name ) ) {
$ name = $ name -> instance ;
}
if ( $ config = metatag_config_load ( $ name ) ) {
$ export = new stdClass ( ) ;
$ export -> instance = $ config -> instance ;
$ export -> config = $ config -> config ;
$ export = features_var_export ( $ export , '' ) ;
$ key = features_var_export ( $ name ) ;
$ code [ ] = "// Exported metatags config instance: {$ name} ." ;
$ code [ ] = " $ config [ {$ key} ] = {$ export} ;" ;
$ code [ ] = "" ;
}
}
$ code [ ] = 'return $ config;' ;
$ code = implode ( "n" , $ code ) ;
return array ( 'metatag_export_default' => $ code ) ;
}

The $ data array is passed to the hook. It contains the same items that you selected when creating the “features” in the first screenshot. On these points, approximately the following code is formed.



Please note that in the hook code and in the screenshot there is the same metatag_export_default hook, which we defined at the very beginning in features_api.

The features_export hook allows you to write data to the $ export array using the $ data array. Also here you can complicate the structure of the stored data by dividing them into categories.

/ **
* Implements hook_features_export
* /
function metatags_features_export ( $ data , & $ export , $ module_name = '' , $ type = 'metatags' ) {

foreach ( $ data as $ name ) {
$ export [ 'features' ] [ $ type ] [ $ name ] = metatag_config_load ( $ name ) ;
}
}

The items that were exported through the feature are transferred to the $ data array. For these items, the state is loaded which is stored in the database.

In order to find the differences between the state of "features" and the state in the database, the "features_export" and "metatag_export_default" hooks are used. The first one gets the state from the database, the second one returns the state of the data in the "feature". These states are compared and you can see the differences as in the screenshot.



If there are differences between "features" and the state in the database, two options are possible.
The first is to update the feature, for example, using the drush fu command FITNAME. In this case, features_export and features_export_render are used. As a result, the feature code will be updated in accordance with the state in the database.

The second option is revert - reset the state in the database to what is stored in the "feature". In order to revert, you will need features_revert hook.

/ **
* Implements hook_features_revert ().
* /
function metatags_features_revert ( $ module ) {
$ function = " {$ module} _metatag_export_default" ;
$ feature_conf = $ function ( ) ;
if ( $ default_config = features_get_default ( 'metatags' ) ) {
foreach ( array_keys ( $ default_config ) as $ config ) {
if ( $ conf = metatag_config_load ( $ config ) ) {
db_delete ( 'metatag_config' ) -> condition ( 'instance' , $ config ) -> execute ( ) ;
}
unset ( $ feature_conf [ $ config ] [ 'cid' ] ) ;
$ object = new stdClass ( ) ;
$ object -> cid = NULL ;
$ object -> instance = $ config ;
$ object -> config = $ feature_conf [ $ config ] [ 'config' ] ;
metatag_config_save ( $ object ) ;
}
}
}

In the hook itself, you will need to implement a code that updates the data in the database in accordance with the code in the feature.
That's all, I hope this article will be useful.

Link to the patch for the metatag module

Source: https://habr.com/ru/post/155709/


All Articles