I'm trying to create a node (B type) & assign it to a A type node's CCK nodereference field using node_save() method.
$node_type_A = node_load($some_nid);
$node_type_A->field_type_B_node_ref[]['nid'] = $node_type_B_nid;
$node_type_A = node_submit($node_type_A);
node_save($node_type_A);
As the result, a new B type node will be created, but no reference will be assigned to the A type node. any help would be appreciated.
GApple is right, the format is correct, but there are couple of things that you might want to care about.
Delta Value
First you need to know the delta value of the latest node reference attached to $node_type_A, the delta is actually a partial index, when combined with vid field of the $node_type_A, they become the index for node reference table in the database. In other words, its a count for $node_type_B which are referenced in $node_type_A, ok?
GApple is right again, you have to exactly say where to add the new reference. When you got that delta value you can exactly say where to append (delta+1) the new reference. Here it is:
function get_current_delta($node_vid){
return db_result(db_query("SELECT delta FROM {content_field_type_A_node_ref}
WHERE vid = '%d'
ORDER BY delta DESC
LIMIT 1", $node_vid));
}
Adding the new reference
We got delta! so we can attach the new $node_type_B node to our $node_type_A node:
// Loading type_A node.
$node_type_A = node_load($some_nid);
// Getting current delta value.
$current_delta = get_current_delta($node_type_A->vid);
// "Appending" a node reference based on delta.
$node_type_A->field_type_B_node_ref += array($current_delta + 1 => array('nid' => $node_type_B_nid));
Resaving the updated node
Optionally call node_submit() to populate some essential fields in the node object and save it by utilizing node_save(). After all, you need to call content_insert() to make the node completely saved asidelong with its CCK fields:
// Resaving the updated node.
$node_type_A = node_submit($node_type_A);
node_save($node_type_A);
content_insert($node_type_A);
Flushing the content cache
Probably the most important part, this was killin' me for couple of days. CCK has a cache table in the database called cache_content (take a look at its structure), after resaving the updated node, you will notice that nothing has changed in the $node_type_A theme output even though that the tables are updated. We have to remove a record from that content cache table, this will force Drupal to show the latest snapshot of the data. You can define the following as a function:
db_query("DELETE FROM {cache_content} WHERE cid = '%s'", 'content:' . $node_type_A->nid . ':' . $node_type_A->vid);
Hope it helps ;)
I just checked one of my own modules that does something similar for the object format, and $node_type_A->field_type_B_node_ref[]['nid'] should be correct.
One thing to check for is that when you load the node, CCK may pre-populate the node reference array with an empty value. If you have configured the field to only allow one value, by using the array append operator (field_type_B_node_ref[]) it will create a second entry that will be ignored (field_type_B_node_ref[1]), instead of overwriting the existing value (field_type_B_node_ref[0]). Try explicitly specifying the array key if possible.
Great post, but one correction: don't flush cache entries by manually querying the DB. In the event someone is using memcache or any other external cache it's going to fail.
cache_clear_all() is your friend for clearing.
Suggested code, direct from the CCK module:
cache_clear_all('content:'. $node_type_A->nid .':'. $node_type_A->vid, content_cache_tablename());
I show CCK storing node references as $node->field_node_reference[0]['items'][0]['nid'], not $node->field_node_reference[0]['nid']. Have you tried mimicking that?
"Flushing the content cache" This works for me, especially if you get a data from node_load()
Related
That's a simple question.
I'm building a PHP Excel from scratch and is a very useful package.
I need to catch the active cell or row to know which cells to modify and customize, I checked all methods in the package and I didn't found something that helped me.
I'm inserting some data like this:
$sheet->appendRow(array(
$variable->value1,
$variable->value2,
$variable->value3,
));
And then I want to customize some things(This example I'm changing the background color), something like:
//The XXX is the last active row that I append some value before
$sheet->cells('XXXX',function ($cells){
$cells->setBackground('#34EC34');
});
There's some way to do find out the active cell or row to put in place of the 'XXX'? I found some question on Stack that someone was accessing by the variable $row, but I didn't found how to access....
go to class name "LaravelExcelWorksheet" in vendor/maatwebsite/excel/src/Maatwebsite/Excel/Classes/LaravelExcelWorksheet.php
Try to change method modifier of getStartRow from protected to public
You can use it with $sheet->getStartRow(), that's show you active row
Kaew's answer works, but to do this without modifying then LaravelExcel source, you can just use the method that getStartRow() uses internally - getHighestRow() - and add to the returned value if needed.
Here is the Laravel Excel 2.1 source for the getStartRow() method.
Have such structure:
Node
-> Filed "field_server_supported_hardware" (Fieldcollection)
-> Field "field_hardware_items" (Node reference width checkboxlist)
I want to add one more item in "field_hardware_items" (check one more item in ckeckboxlist).
Here's my code, it doesn't throws errors, but I can't save changes:
$node_wrap = entity_metadata_wrapper('node', $node_id); // our node wrapper
$node_wrap->field_server_supported_hardware[$key_item]->field_hardware_items->offsetSet($new_key, $new_node_item_to_attach); // setting new item
___save_debug($node_wrap->field_server_supported_hardware[$key_item]->field_hardware_items->value()); // if I log "field_hardware_items", it includes new item, and includes it in correct structure.
$node_wrap->save(TRUE); // trying to save node
Then I open the node I saved in admins panel, but checkbox of node with id=$new_node_item_to_attach isn't checked.
Give $node_wrap->revision->set(TRUE) a try before saving it
Apparently the save() function don't take into account the flag to create a new revision on a node on update, so it may be why you don't see the change.
Nestable tree structure handle with left and right value
I already done the functionality of add parent node, child node and delete node.
But How to save tree value after moving nodes drag and drop with the nestable.js
Lest see my output what I want to do....
i want to manage with data-left, data-right values
And my database structure is
Please help in this how to manage drag and drop functionality.
I tried to comment this, but the website tells me I need 50 Reputation in order to do so, so this may or may not answer your question, I'd have to wait until I got home when I could fiddle with something similar in database / Javascript structure.
I'm fairly familiar with left/right_id tables and such. The first place I saw them was in phpBB3.0 and I spent a whole lot of time reading up on them.
One thing you could do to help you expedite your queries is to add a parent_id column, this way you can immediately get ALL the child notes without having to use "left_id > 1 AND right_id < 8" in your SQL statements.
Now, for your javascript question, how I will try to go about this when I get home is to declare an array of id keys => child values. So, in the screenshot example you've given above you could hopefully get to something like this
array(
2 => array(
5 => array(
3
),
6
),
3 => array(
8
),
4
)
In order to get this you'd have to loop through the DOM for each member of the list, using their id's and the array.push function to add values as necessary.
I'll try and help more once I can get to my house where I have a PHP server setup, but this should give you an Idea of how to get it started.
Are you using any Javascript framework (such as MooTools, jQuery)?
Edit:
So, I've worked on it for quite some time and I've got a general thing working. Below is the code directly responsible for looping through the DOM tree and assigning left/right_id values. It should be fairly easy to edit it for your liking.
I have a preference for MooTools, so I wrote this using the mootools library (it offers some Element features that are quite nice and in fact gave me a multi-level drag and sort tool to test this with). If you prefer to use another library, it should be fairly easy to switch the code to work for it, but I do not use jQuery so I am unfortunately not helpful in that regard
Link to download all files involved: Here
function calculate_ids(el,left_id, parent_id){
var el = $(el);
//makes the element a MooTools Element
var left_id = left_id || 1;
//If left_id is given, we are using this function recursively
var parent = parent_id || 0;
//Gives us a quick method in order to figure out what level we are currently on
var id_array = {};
/*ID array object will look like
{
1:{
'left_id':1,
'right_id':2,
'parent':0
},
2:{
'left_id':3,
'right_id':6,
parent_id:0
},
3:{
'left_id':4,
'right_id':5
},
etc.
}
*/
var els = el.getChildren('li');
//Get the immediate children
els.each(function(child){
var id = child.get('id');
//The ID
var descendants = child.getElements('li');
//Gets ALL most descendent children that match the format, these are ordered the way they are in the DOM
var right_id = left_id + descendants.length * 2 + 1
id_array[id] = {
'left_id':left_id,
'right_id':right_id,
'parent':parent
};
if(descendants.length > 0){
//There are child elements to this thing, recursion!
id_array = Object.merge(id_array, calculate_ids( child.children[0], left_id + 1, id) );
}
left_id = right_id + 1;
//Increment the left_id counter
});
return id_array;
}
Known Issues
The example code I posted doesn't correctly calculate the left/right ids after they've been calculated a first time or moved up/down a level if they were calculated previously. I'm guessing this has something to do with how the multi-level sort class moves the items around. This code is meant to serve as a starting point. I'm really busy (unfortunately), so I may or may not be able to fix this issue in the future, but either way this code should serve as a great starting point.
I have created a custom module and am using hook_block to programmatically create some blocks.
My question is how can I access field values including CCK fields for the current node within my module?
I basically want to get a value from a CCK field and use the value when building my block for that page.
Getting at the current node is an awkward pain in the posterior. Standard practice is to do something like this:
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == '') {
$node = node_load(arg(1));
// Collect output.
}
arg() pulls elements out of the Drupal path. Since all nodes (regardless of what a path alias might show you) appears at node/#, by checking for 'node' and that the second element is a number, you are fairly well guaranteed to have your hands on a node. Checking the third path element allows you to avoid processing on the node edit form and other pages that hang off a specific node.
CCK Values are loaded into the node, and usually look something like this:
// Text field. Structure also works for number fields.
$text = $node->field_my_text_field[0]['value']
// Node Reference field.
$nref = $node->field_my_nref_field[0]['nid']
// User Reference field.
$uref = $node->field_my_uref_field[0]['uid']
The "0" array element specifies the delta of the field. Any given field can actually process multiple values, and the array structure in CCK assumes this possibility even if you restrict the field to a single value.
In Drupal 6 there is a built-in Drupal function to get the node object.
if ($node = menu_get_object()) {
…
}
Read more here http://api.drupal.org/api/function/menu_get_item/6.
I have Drupal 5 View (must be "Views 1" so), which contains Event_StartTime field, which shows up normally for the fields that have a real date inside. But I also have a number of records with Event_StartTime field value like Dec 31 1969 - 8:00pm which looks bad in view and I need to replace them with some custom label, like "No Date Available".
Can I somehow inject this condition (if value = x show value y) into view?
Even when I print in "No Date Available" into SQL, the view will show empty field.
To sum up, the general problem is that View fields are kind of limiting, and sometimes you just need to replace some field value, but it's either "date or nothing" or "node-reference id or nothing".
P.S. The situation might be a bit complicated because I use "Bonus: Views Export" module which makes my view return CSV data.
I'm not really familiar with Views1 anymore, but I think you have at least two options:
At the theming level - you could override the field template and put a check for the particular date value in there, replacing it when found. Of course this check would depend on the formatting of the dates, so if you ever change that, you'd need to adjust the check as well.
At the view generation level - you could execute the view 'manually' from code and inspect the views object right after instantiation and/or after execution, but before rendering (See her for an example of manipulationg the view object in Views2). You could manipulate the result property after execution, but before rendering, or you might be able to put a pre-render callback in there right after instantiation (but I'm not sure if this is already possible in Views1).
Building off of Henrik's comment, theming seems to me to be the best place to do this. You would need to add a function to your template.php file to override that specific view. See the Views 1 theming documentation. Based on this documentation, you create a function with the name of your view of the form
function THEMENAME_view_view_VIEWNAME($view, $type, $nodes, $level = NULL, $args = NULL)
to theme the whole view. $nodes is an array of partially-loaded node objects that are included in your view. You can load each node and check the values of the Event_StartTime field with something like this:
foreach ($nodes as $id => $node) {
$temp_node = node_load($node->nid);
//now check value of Event_StartTime assuming that is what you named the field
if ($temp_node->Event_StartTime === 'Dec 31 1969 - 8:00pm') {
$temp_node->Event_StartTime = 'No Date Available';
}
//output the fields of your view . . .
}
I only showed how to check the value of the Event\_StartTime field, and I am not sure what the actual value is. Dec 31 1969 is before the dates returned by the time() function, so if this does not work you might want to check if Event_StartTime === '', which may be true if the event field is just left empty. You will still have to theme the rest of your fields and output them as HTML, which might be too much of a pain just to change the output of one field. You can also override the output of individual fields. I have not done this so I couldn't walk you through it, but the link I gave above has some documentation on overriding field theming functions.