"Unable to dump a service container if a parameter is an object or a resource." - symfony

I'm writing a bundle that deals with a lot of dates and times and I'm not sure it's particularly possible to easily represent this easily with Yaml or XML. For the configuration I'm defining it as a PHP file, included() into the ...Extension::Load() function:
<?php
// {BundleName}Extension.php
$openingHours = require $path->locate('business_days.php');
$container->setParameter($alias . '.days', $openingHours['days']);
// business_days.php:
return array(
'days' => array(
Carbon::MONDAY => array(
'name' => 'Monday',
'start' => (new Carbon('09:00'))->setDate(0, 0, 0)),
'end' => (new Carbon('17:00'))->setDate(0, 0, 0)),
),
....
);
When the system runs the configuration though (and successfully prepares the config), it then goes to dump the data to the file cache --
"Unable to dump a service container if a parameter is an object or a resource."
How can I - for this bundle - not have the configuration cached to disk, and so avoid the above error?

I don't think it is practical to turn off config caching on a per bundle basis. Use a factory instead.
Code is untested:
class BusinessDaysFactory
{
static function create()
{
return array(
'days' => array(
Carbon::MONDAY => array(
'name' => 'Monday',
'start' => (new Carbon('09:00'))->setDate(0, 0, 0)),
'end' => (new Carbon('17:00'))->setDate(0, 0, 0)),
),
....
# services.yml
business_days:
class: NeedAnEntry_ButItIsNotUsed
factory_class: Namespace\BusinessDaysFactory
factory_method: create
http://symfony.com/doc/current/components/dependency_injection/factories.html

Related

How do I hook up the code to change Drupal module behaviour?

Drupal does not allow me to delete extension (recurring_commerce) as some fields needs to be deleted manually. This issue is described in detalis below.
Solution is to add some code to a file as described in #11 of the issue below.
Basically I need to programmatically delete a field and I have never done it before. Writing kind of a hook (?).
I tried to paste the suggested code before, after the original code as well as replacing the original code with a suggested one.
Every time after changing the code I am restarting the server, running cron and clear cache.
Still I am unable to uninstall the exension from drupal as I have the following message:
The following reason prevents Commerce Recurring from being uninstalled:
The Billing period field type is used in the following fields: commerce_order.billing_period, commerce_order_item.billing_period
Details of the following issue:
please skip to #11
https://www.drupal.org/project/commerce_recurring/issues/2924965
Suggested code to apply:
function commerce_recurring_update_8101(&$sandbox) {
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order.recurring.billing_period')->delete();
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order.recurring.billing_schedule')->delete();
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order.recurring.order_items')->delete();
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order_item.recurring_standalone.billing_period')->delete();
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order_item.recurring_standalone.subscription')->delete();
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order_item.recurring_product_variation.billing_period')->delete();
\Drupal::entityManager()->getStorage('field_config')->load('commerce_order_item.recurring_product_variation.subscription')->delete();
}
function commerce_recurring_update_8102(&$sandbox) {
\Drupal::entityTypeManager()->getStorage('commerce_order_type')->load('recurring')->delete();
\Drupal::entityTypeManager()->getStorage('commerce_order_item_type')->load('recurring_standalone')->delete();
\Drupal::entityTypeManager()->getStorage('commerce_order_item_type')->load('recurring_product_variation')->delete();
}
Original code in my file:
/**
* Add the 'trial_starts' and "trial_ends" fields to subscriptions.
*/
function commerce_recurring_update_8101(&$sandbox) {
$fields = [];
$fields['trial_starts'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Trial starts'))
->setDescription(t('The time when the subscription trial starts.'))
->setRequired(FALSE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'timestamp',
'weight' => 0,
])
->setDisplayOptions('form', [
'type' => 'datetime_timestamp',
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE);
$fields['trial_ends'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Trial ends'))
->setDescription(t('The time when the subscription trial ends.'))
->setRequired(FALSE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'timestamp',
'weight' => 0,
])
->setDisplayOptions('form', [
'type' => 'datetime_timestamp',
'weight' => 0,
])
->setDisplayOptions('form', [
'type' => 'datetime_timestamp',
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE);
$update_manager = \Drupal::entityDefinitionUpdateManager();
foreach ($fields as $name => $storage_definition) {
$update_manager->installFieldStorageDefinition($name, 'commerce_subscription', 'commerce_recurring', $storage_definition);
}
}
/**
* Make the billing_schedule field required on subscriptions.
*/
function commerce_recurring_update_8102() {
$entity_definition_update = \Drupal::entityDefinitionUpdateManager();
$field_definition = $entity_definition_update->getFieldStorageDefinition('billing_schedule', 'commerce_subscription');
$field_definition->setRequired(TRUE);
$entity_definition_update->updateFieldStorageDefinition($field_definition);
}

hook_node_type_insert is not invoked

I try to add some fields to content type through this hook as it done in node_example module in Drupal 7 examples but it's not even invoked. What can be wrong?
function education_node_type_insert($content_type){
$fields = _anketa_installed_fields();
foreach($fields as $field){
field_create_field($field);
}
$instances = _anketa_installed_instances();
foreach($instances as $instance){
$instance['entity_type'] = 'node';
$instance['bundle'] = 'anketa';
field_create_field($instance);
}
}
When you disable a node module and uninstall it Drupal doesn't clear out the entries in the node_type table for the node types associated with your module (i would call this a bug in Drupal core). If those entries remain; the hook_node_type_insert hook does not get run when you re-enable the module.
If you first delete those entries manually from the node_type table; the hook should run.
Had you already run this before trying to add the fields? Because the education_node_type_insert($type) function is not called if the node type $type is already in the node_type database table, which it will be after the first time that this is run.
I think the correct way to do this is to add the fields in an implementation of hook_install instead (in yourmod.install, and checking at the same time whether they've already been added perhaps).
Also, during development, you need to uninstall-reinstall (e.g. drush dis -y yourmod && drush uninstall -y yourmod && drush en -y yourmod) every time you make a change to the fields.
Have you tried uninstalling (Not disable, but really uninstall after you disable it from Uninstall tab) the module and re-enabling it again?
When working on custom modules - whether building, debugging, QAing, migrating, updating, etc- the following steps often help. Without looking at your code closely, I'd suggest trying these steps:
Disable the module, uninstall/reinstall (if ok to wipe the module data from the DB), re-enable the module then run update.php. Check Drupal & PHP/MySQL logs, run cron.php clear browser & Drupal cache, logout & log back in, edit roles & perms. Rinse. Repeat... often knocks unexplainable issues loose.
Also this all assumes you've already confirmed overall module architecture & function name/spellings are ok. If all else fails, try installing on another instance to see if the issue can be replicated.
You will need to actually delete your node type manually after the first install.
function example_uninstall () {
node_type_delete ('my_type');
}
There are probably good reasons why Drupal doesn't do this by default: what's the correct behaviour?
Why don't you use hook_node_insert?
It's a working example for adding components to every new webform:
/**
* Implements hook_node_insert().
*/
function modulename_node_insert($node) {
if($node->type == 'webform' && $node->is_new) {
module_load_include('inc', 'webform', 'includes/webform.components');
$components = array();
$components[0] = array(
'name' => 'Submitted Page URL',
'nid' => $node->nid,
'form_key' => 'hidden_submitted_page_url',
'type' => 'hidden',
'mandatory' => 0,
'weight' => 99,
'pid' => 0,
'value' => '',
'required' => 0,
'extra' => array(
'hidden_type' => 'hidden',
'description' => '',
'wrapper_classes' => 'hidden-submitted-page-url-wrap',
'css_classes' => 'hidden-submitted-page-url',
'private' => 0,
),
);
$components[1] = array(
'name' => 'Referrer Page URL',
'nid' => $node->nid,
'form_key' => 'hidden_referrer_page_url',
'type' => 'hidden',
'mandatory' => 0,
'weight' => 99,
'pid' => 0,
'value' => '',
'required' => 0,
'extra' => array(
'hidden_type' => 'hidden',
'description' => '',
'wrapper_classes' => 'hidden-referrer-page-url-wrap',
'css_classes' => 'hidden-referrer-page-url',
'private' => 0,
),
);
foreach ($components as $component) {
webform_component_insert($component);
}
}
}

migrating url alias from drupal6 to drupal7 as a part of migration process

I have migrated nodes using migrate module v2. Currently i am running into a problem that the previous site used url aliases,which have not been migrated into drupal7 and will affect the site rank from SEO perspective.
Is there a way i can migrate the path aliases while running the migration classes itself?If not what would be the best way to do so?
You can migrate your legacy aliases directly into the Drupal 7 path field:
$this->addFieldMapping('path', 'my_legacy_alias_field');
Here is a very stripped down migration class that includes an easy method for bringing URLs along for the ride. Intended for use with the Migrate module.
class MyNodeMigration extends Migration {
public function __construct(array $arguments) {
$this->arguments = $arguments;
parent::__construct();
$source_fields = array('nid' => t('The node ID of the page'));
$query = Database::getConnection('default', 'legacy')
->select('node', 'n')
->fields('n');
$query->join('url_alias', 'a', "a.src = CONCAT('node/', n.nid)");
$query->addField('a', 'dst');
$this->source = new MigrateSourceSQL($query, $source_fields);
$this->destination = new MigrateDestinationNode('my_node_type');
$this->map = new MigrateSQLMap($this->machineName,
array('nid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'D6 Unique Node ID',
'alias' => 'n',
)),
MigrateDestinationNode::getKeySchema()
);
$this->addSimpleMappings(array('title', 'created', 'changed', 'status'));
$this->addUnmigratedDestinations(array('sticky', 'log', 'nid'));
$this->addFieldMapping('path', 'dst');
$this->addFieldMapping('is_new')->defaultValue(TRUE);
}
}
As I can see, the url_aliastable is globally the same, expect the name of fields whom changed from srcto sourceand dst to alias. So I guess you can easily copy the content from your Drupal 6 to your Drupal 7.
I never tried, but in theory it should work.
The best way (according to me) to have the same url aliases is :
1> install url_alias module.
2> configure the nodes with patterns similar to drupal6. Now, this step may trouble you, in case the new url-aliases have nids attached to them.(as in my case).
As a solution we can go ahead and create custom tokens using code where the source id can be fetched from the migrate map tables based on the new destination ids which are easily available.
Now, we can go ahead and bulk generate url-aliases.
An example for creating such custom token would be:
/**
* Implements hook_token_info().
*/
function custom_configuration_token_info() {
$type = array(
'node' => array (
'name' => t('Nodes'),
'description' => t('Tokens related to individual nodes.'),
'needs-data' => 'node',
),
'term' => array(
'name' => t('Taxonomy Terms'),
'description' => t('Tokens related to taxonomy terms.'),
'needs-data' => 'term',
)
);
// tokens for node legacy nid.
$tokens['node']['mapid'] = array(
'name' => t("mapid"),
'description' => t("The nid of the node prior to migration."),
);
$tokens['term']['mapid'] = array(
'name' => t('mapid'),
'description' => t('The tid of taxonomy terms prior to migration.'),
);
return array(
'types' => $type,
'tokens' => $tokens,
);
}
now,
function custom_configuration_tokens($type, $tokens, array $data = array(), array $options = array()) {
$url_options = array('absolute' => TRUE);
if (isset($options['language'])) {
$url_options['language'] = $options['language'];
$language_code = $options['language']->language;
}
else {
$language_code = NULL;
}
$sanitize = !empty($options['sanitize']);
$replacements = array();
if ($type == 'node' && !empty($data['node'])) {
$node = $data['node'];
foreach ($tokens as $name => $original) {
switch ($name) {
<write your custom code for the token conditioned by the name attribute in info function>
}
}
}
While writing your custom code, you mite also be needing the legacy table. Drupal 7 supports multiple databases, so just configure the legacy table credentials in settings.php file.
Use drupal_set_active while fetching data from the different tables.
Thanks.

hook_load/hook_view not called

I have a module with four node types declared. My problem is, hook_load, hook_view is never called. I used drupal_set_message to find out if certain hook is being called. And I found out hook_load, hook_view isn't. Just to give you clear picture, here's my structure of hook_load
HERE'S UPDATED ONE
function mymodule_node_info(){
return array(
'nodetype1' => array(
'name' => t('nodetype1'),
'module' => 'mymodule_nodetype1',
'description' => t('....'),
'has_title' => TRUE,
'title_label' => t('Title'),
'has_body' => TRUE,
'body_label' => t('Body'),
),
'nodetype2' => array(
......
'module' => 'mymodule_nodetype2',
......
),
'nodetype3' => array(
......
'module' => 'mymodule_nodetype3',
......
),
'nodetype4' => array(
......
'module' => 'mymodule_nodetype4',
.......
),
);
}
function mymodule_nodetype1_load($node){
$result = db_query('SELECT * from {nodetype1table} WHERE vid = %d'
$node->vid
);
drupal_set_message("hook_load is provoked.","status");
return db_fetch_object($result);
}
I don't know why it is not called. I wrote this code base on drupal module writing book and follow the instructions. I've tried sample code from that book and it works ok. Only my code isn't working. Probably because of multiple node types in one module. Any help would be highly appreciated.
Your code doesn't work because hook_load() and hook_view() aren't module hooks: they're node hooks. The invocation is based off of content type names, not module names.
So, first you need to have declared your content types using hook_node_info():
function mymodule_node_info() {
$items = array();
$items['nodetype1'] = array(
'name' => t('Node Type 2'),
'module' => 'mymodule_nodetype1',
'description' => t("Nodetype 1 description"),
);
$items['nodetype2'] = array(
'name' => t('Node Type 2'),
'module' => 'mymodule_nodetype2',
'description' => t("Nodetype 2 description"),
);
$items['nodetype3'] = array(
'name' => t('Node Type 2'),
'module' => 'mymodule_nodetype3',
'description' => t("Nodetype 3 description"),
);
return $items;
}
Then, you need to use the name of the module you specified for each content type declared in hook_node_info() for your node hooks. That is, mymodule_nodetype1_load(), mymodule_nodetype2_view(), etc.
Edit
If you're trying to have a non-node based module fire when a node is viewed or loaded, you need to use hook_nodeapi():
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch ($op) {
case 'view':
mymodule_view_function($node);
break;
case 'load':
mymodule_load_function($node);
break;
}
}
Replace mymodule_load_function() and mymodule_load_function() with your own custom functions that are designed to act on the $node object.
Edit 2
Besides the syntax error in your hook_load() implementations, there's a piece of your code outside of what you're providing that's preventing the correct invocation. The following code works (if you create a nodetype1 node, the message "mymodule_nodetype1_load invoked" appears on the node): perhaps you can compare your entire code to see what you're missing.
function mymodule_node_info() {
return array(
'mymodule_nodetype1' => array(
'name' => t('nodetype1'),
'module' => 'mymodule_nodetype1',
'description' => t('....'),
'has_title' => TRUE,
'title_label' => t('Title'),
'has_body' => TRUE,
'body_label' => t('Body'),
),
'mymodule_nodetype2' => array(
'name' => t('nodetype2'),
'module' => 'mymodule_nodetype2',
'description' => t('....'),
'has_title' => TRUE,
'title_label' => t('Title'),
'has_body' => TRUE,
'body_label' => t('Body'),
),
);
}
function mymodule_nodetype1_form(&$node, $form_state) {
// nodetype1 form elements go here
return $form;
}
function mymodule_nodetype2_form(&$node, $form_state) {
// nodetype2 form elements go here
return $form;
}
function mymodule_nodetype1_load($node) {
$additions = new stdClass();
drupal_set_message('mymodule_nodetype1_load invoked');
return $additions;
}
function mymodule_nodetype2_load($node) {
$additions = new stdClass();
drupal_set_message('mymodule_nodetype2_load invoked');
return $additions;
}
If you're not reseting your environment after changes to your module, you might be running into caching issues. You should test your code in a sandbox environment that can be reset to a clean Drupal installation to ensure you're not focusing on old cruft from previous, incorrect node implementations.
Additionally, you should only be using hook_nodeapi() if you are trying to act on content types that are not defined by your module. Your content types should be using the node hooks (hook_load(), hook_view(), etc.).
Finally, it may be the case that you're using the wrong hooks because you're expecting them to fire in places they are not designed to. If you've gone through everything above, please update your post with the functionality you're expecting to achieve and where you expect the hook to fire.
I found the culprit why your code doesn't work. It's because I was using the test data created by the old codes. In my old codes, because of node declaration inside hook_node_info uses the same module value, I could only create one hook_form implementation and use "switch" statement to return appropriate form. Just to give you clear picture of my old codes-
function mymodule_node_info(){
return array(
'nodetype1' => array(
.....
'module' => 'mymodule',
.....
),
'nodetype2' => array(
......
'module' => 'mymodule',
......
),
.......
);
}
function mymodule_form(&$node, $form_state){
switch($node->type){
case 'nodetype1':
return nodetype1_form();
break;
case 'nodetype2':
return nodetype2_form();
break;
.....
}
}
When I created new data after I made those changes you have provided, hook_load is called. It works! I've tested several times(testing with old data created by previous code and testing with new data created after those changes) to make sure if that's the root cause and, I got the same result.I think drupal store form_id or module entry value of node declaration along with data and determine the hook_load call. That's probably the reason why it doesn't think it's a data of this node and thus hook_load isn't invoked.
And Thank you so much for your help.

Please Explain Drupal schema and drupal_write_record

1) Where is the best place to populate a new database table when a module is first installed, enabled? I need to go and get some data from an external source and want to do it transparently when the user installs/enables my custom module.
I create the schema in {mymodule}_schema(), do drupal_install_schema({tablename}); in hook_install. Then I try to populate the table in hook_enable using drupal_write_record.
I confirmed the table was created, I get no errors when hook_enable executes, but when I query the new table, I get no rows back--it's empty.
Here's one variation of the code I've tried:
/**
* Implementation of hook_schema()
*/
function ncbi_subsites_schema() {
// we know it's MYSQL, so no need to check
$schema['ncbi_subsites_sites'] = array(
'description' => 'The base table for subsites',
'fields' => array(
'site_id' => array(
'description' => 'Primary id for site',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
), // end site_id
'title' => array(
'description' => 'The title of the subsite',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
), //end title field
'url' => array(
'description' => 'The URL of the subsite in Production',
'type' => 'varchar',
'length' => 255,
'default' => '',
), //end url field
), //end fields
'unique keys' => array(
'site_id'=> array('site_id'),
'title' => array('title'),
), //end unique keys
'primary_key' => array('site_id'),
); // end schema
return $schema;
}
Here's hook_install:
function ncbi_subsites_install() {
drupal_install_schema('ncbi_subsites');
}
Here's hook_enable:
function ncbi_subsites_enable() {
drupal_get_schema('ncbi_subsites_site');
// my helper function to get data for table (not shown)
$subsites = ncbi_subsites_get_subsites();
foreach( $subsites as $name=>$attrs ) {
$record = new stdClass();
$record->title = $name;
$record->url = $attrs['homepage'];
drupal_write_record( 'ncbi_subsites_sites', $record );
}
}
Can someone tell me what I'm missing?
If ncbi_subsites_get_subsites() is not in the .install file, you need to include whatever file its in with your module. Otherwise, it's returning nothing, in which case try dumping $subsites and exiting.
I think the answer is that drupal_write_record is not meant for install or enable hooks. I think when enabling or installing, you have to write SQL. That is the impression I am getting from reading some posts that mention that the schema is not available in these hooks.
First of all (assuming Drupal 6), drupal_write_record() cannot be called from hook_install() because Drupal would not find the database schema defined from the module, which is still going to be installed, and enabled.
Instead you need to use db_query() function. (the comments are speaking of a way to include default data by prviding it to hook_schema() serialized, but i've found no documentation on this.)
However, would you be using (the development version of) Drupal 7, you want to look at the db_insert() function instead.

Resources