I have a very strange case in new developpement of an site web. I had made a block (with a custom module) and I make a node_load. Here all is ok, the node is load, the block is display. But for if I change nid of node (by exemple set null) and do nothing else (no node_save, no function call, NOTHING with this object), I have some notice of different module (like 3 or 4 modules). I know it's just notice, but I would understand why the simply fact of change variables wich is never uses, trigger some error..... Exemple :
$tmp = node_load(arg(1));
$tmp->nid=null;
=> error (lot of "Trying to get property of non-object in..." in diffrent name function)
$tmp = node_load(arg(1));
$node=$tmp;
$node->nid=null;
=> error (lot of "Trying to get property of non-object in..." in diffrent name function)
$tmp = node_load(arg(1));
$node = new stdClass();
//Copy via une boucle sinon on a des erreurs.
foreach ($tmp as $key => $value) {
if ($key != 'nid') $node->{$key} = $value;
}
=> all is ok
Ok finally it the comportement of references object php, we must applicate method Clone php on an object to make an copy, or the object will be refeerences
Related
Thanks for taking the time to read my problem.
I'm trying to write a module that import content from an old version of Drupal to a new Drupal 9 website.
I managed to extract all content from the old database. It is stored in an array that I pass to a function reponsible for creating the node in the new DB. The problem I'm having is that the body of the node is not saved. Records are created in the tables node, node_field_data, node_revision, node_field_revision but nothing is created in node__body.
I tried two different methods :
1-
$node = Node::create(['type' => 'article_epingle']);
$node->langcode = $a["lang"];
$node->title = $a["title"];
// ... status, promote, ...
$node->body = array("value" => $a["body"], "format" => 'full_html');
// ... a few custom fields
$node->enforceIsNew();
$node->save();
Or
$node = Node::create(['type' => 'article_epingle']);
$node->langcode = $a["lang"];
$node->title = $a["title"];
// ... status, promote, ...
$node->body->value = $a["body"];
$node->body->format = 'full_html';
// ... a few custom fields
$node->enforceIsNew();
$node->save();
And 2 -
$node = \Drupal::entityTypeManager()
->getStorage('node')
->create(['type' => 'article_epingle',
'title' => $a["title"],
'body' => $a["body"],
// ... other fields
]);
$node->save();
The result is the same everytime, the body is not saved in DB. The save() method returns "1" and the newly created node appears in /admin/content but can't be displayed. The following error is returned if I try to display the node :
Error: Call to a member function displaySubmitted() on null in template_preprocess_node() (line 528 of core/modules/node/node.module).
Does anyone already had the same problem ?
Thanks in advance for your input !
I solved my problem.
I guess I did something wrong while installing Drupal because my code works fine after installing everything again.
I am getting below mention notice on /admin/reports/status page.
Notice: unserialize(): Error at offset 0 of 728 bytes in field_read_fields() (line 374 of /my_website/modules/field/field.crud.inc).
Notice: Undefined index: settings in text_field_schema() (line 17 of /my_website/modules/field/modules/text/text.install).
How to fix the notice?
The function unserialize() fails to convert a serialized value back into a PHP value because of an invalid length (or a length mismatch) in the stored representation of the data.
This means that a field record was not stored correctly in its field table.
The second notice tells us the type of the incriminated field : text_field_schema(), invoked via the hook_field_schema, exposes three field types : text, text_long, text_with_summary.
// line 392 of modules/field/field.crud.inc
$schema = (array) module_invoke($field['module'], 'field_schema', $field);
Just above, line 388, you got this :
module_invoke_all('field_read_field', $field);
By implementing this hook you should be able to point out which record is broken :
function yourmodule_field_read_field($field) {
if ($field['module'] === 'text' && !isset($field['settings'])) {
dpm($field);
}
}
Once identified, you will probably have to "repair" the field structure before saving it as usual via FieldAPI, e.g. :
$field += array(
'settings' => array(
'max_length' => $somelength
)
);
field_update_field($field);
The structure should be as defined in field_create_field().
[EDIT]
If you can't use field API, still you should be able to see which record is broken for that field.
Call field_read_field($field_name) and debug :
// line 370 of modules/field/field.crud.inc
$fields = array();
$results = $query->execute();
foreach ($results as $record) {
dpm($record); // check $record['data']
$field = unserialize($record['data']);
// ...
}
The broken record should be printed just before the first notice (if you display it).
Check the serialized value ($record['data']), and compare it with other records to see what's wrong. In the end you may have to update the field using SQL statements if you can't use field API.
I'd like to have the field name in addition to the error message.
I performed the following set of instructions to put all errors into an array :
$errors= array();
foreach ($newRdvForm->getErrors(true) as $key => $error) {
$errors[$key] = $error->getMessage();
}
So what can i to have the field name of each input ?
If there are other method, feel free to publish it
The FormInterface::getErrors() method returns a FormErrorIterator instance. The underlying FormError objects provide a getOrigin() method which returns the FormInterface the error relates to.
I have an old SS2.4 site which I have updated to SS3.1.13. The only part of the old site I can't get working is a search form that filters DataObjects. The old code is:
public function doCollectionSearch($data, $form)
{
$filters = array();
...
//setup some filters based on user selections
...
$where = implode(" AND ", $filters);
if(!isset($_REQUEST['start'])) $_REQUEST['start'] = 0;
$limit = $_REQUEST['start'].",50";
return $this->customise(array(
'Collections' => DataObject::get("Collection", $where, "Genus, Species ASC", null, $limit)
))->renderWith(array('Collection_results','Page'));
}
I have updated the last part to:
return $this->customise(array(
'Collections' => Collection::get()->where($where)->sort("Genus, Species ASC")->limit($limit)
))->renderWith(array('Collection_results','Page'));
But I get a "the method 'fortemplate' does not exist on 'CollectionPage_Controller'".
I know the $where is not right yet, but if I strip that out I still get an error..
I know I am missing something obvious...can anyone suggest a fix?
You'll get that error if your template accesses a method or database field that returns an object that can't be reduced to a string. This often happens when you have a related object (say a parent page) and you do something like the following:
<p>My parent is: $Parent</p>
Instead of
<p>My parent is: $Parent.Title</p>
The same thing existed in 2.4 so this doesn't totally explain your problem, but I'd look for something like the above scenario in your templates.
I am trying to modify a field collection in a node that already exists so I can change an image on the first element in an array of 3. The problem is, the hostEntity info is not set when I do a entity_load or entity_load_single so when I do a:
$field_collection_item->save(true); // with or without the true
// OR
$fc_wrapper->save(true); // with or without the true
I get the following error:
Exception: Unable to save a field collection item without a valid reference to a host entity. in FieldCollectionItemEntity->save()
When i print_r the field collection entity the hostEntity:protected fields are indeed empty. My field collection is setup as follows:
field_home_experts
Expert Image <--- Want to change this data only and keep the rest below
field_expert_image
Image
Expert Name
field_expert_name
Text
Expert Title
field_expert_title
Text
Here is the code I am trying to use to modify the existing nodes field collection:
$node = getNode(1352); // Get the node I want to modify
// There can be up to 3 experts, and I want to modify the image of the first expert
$updateItem = $node->field_home_experts[LANGUAGE_NONE][0];
if ($updateItem) { // Updating
// Grab the field collection that currently exists in the 0 spot
$fc_item = reset(entity_load('field_collection_item', array($updateItem)));
// Wrap the field collection entity in the field API wrapper
$fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc_item);
// Set the new image in place of the current
$fc_wrapper->field_expert_image->set((array)file_load(4316));
// Save the field collection
$fc_wrapper->save(true);
// Save the node with the new field collection (not sure this is needed)
node_save($node);
}
Any help would be greatly appreciated, I am still quite new to Drupal as a whole (end-user or developer)
Alright so I think I have figured this out, I wrote up a function that will set a field collection values:
// $node: (obj) node object returned from node_load()
// $collection: (string) can be found in drupal admin interface:
// structure > field collections > field name
// $fields: (array) see usage below
// $index: (int) the index to the element you wish to edit
function updateFieldCollection($node, $collection, $fields = Array(), $index = 0) {
if ($node && $collection && !empty($fields)) {
// Get the field collection ID
$eid = $node->{$collection}[LANGUAGE_NONE][$index]['value'];
// Load the field collection with the ID from above
$entity = entity_load_single('field_collection_item', array($eid));
// Wrap the loaded field collection which makes setting/getting much easier
$node_wrapper = entity_metadata_wrapper('field_collection_item', $entity);
// Loop through our fields and set the values
foreach ($fields as $field => $data) {
$node_wrapper->{$field}->set($data);
}
// Once we have added all the values we wish to change then we need to
// save. This will modify the node and does not require node_save() so
// at this point be sure it is all correct as this will save directly
// to a published node
$node_wrapper->save(true);
}
}
USAGE:
// id of the node you wish to modify
$node = node_load(123);
// Call our function with the node to modify, the field collection machine name
// and an array setup as collection_field_name => value_you_want_to_set
// collection_field_name can be found in the admin interface:
// structure > field collections > manage fields
updateFieldCollection(
$node,
'field_home_experts',
array (
'field_expert_image' => (array)file_load(582), // Loads up an existing image
'field_expert_name' => 'Some Guy',
'field_expert_title' => 'Some Title',
)
);
Hope this helps someone else as I spent a whole day trying to get this to work (hopefully I won't be a noob forever in Drupal7). There may be an issue getting formatted text to set() properly but I am not sure what that is at this time, so just keep that in mind (if you have a field that has a format of filtered_html for example, not sure that will set correctly without doing something else).
Good luck!
Jake
I was still getting the error, mentioned in the question, after using the above function.
This is what worked for me:
function updateFieldCollection($node, $collection, $fields = Array(), $index = 0) {
$eid = $node->{$collection}[LANGUAGE_NONE][$index]['value'];
$fc_item = entity_load('field_collection_item', array($eid));
foreach ($fields as $field => $data) {
$fc_item[$eid]->{$field}[LANGUAGE_NONE][0]['value'] = $data;
}
$fc_item[$eid]->save(TRUE);
}
I hope this helps someone as it took me quite some time to get this working.