Accessing array values of a field collection in a node with Drupal? - arrays

Please bare with a very recent user of Drupal.
I want to create an array out of all examples of the string "url" on a Drupal site.
I've used the method "field_get_items" previously to do something very similar, but I am now trying to access a field collection that is many levels deep into the node's array and I'm not sure that method would work.
$website_urls = array();
$faculty_members = field_get_items('node', $node, 'field_faculty_member');
for ($i = 0; $i < count($faculty_members); $i++) {
$value = field_view_value('node', $node, 'field_faculty_member', $faculty_members[$i]);
$field_collection = $value['entity']['field_collection_item'][key($value['entity']['field_collection_item'])];
$website_urls[] = render($field_collection['field_link']['#items'][0]['url']);
}
An example of one url's location is...
['field_faculty_program'][0]['entity']['field_collection_item'][1842]['field_faculty_member'][0]['entity']['field_collection_item'][1843]['field_link']['#items'][0]['url']
..and another...
['field_faculty_program'][4]['entity']['field_collection_item'][1854]['field_faculty_member'][0]['entity']['field_collection_item'][1855]['field_link']['#items'][0]['url']
What is the method I should be using to collect al of the 'url' strings for placement in an array?

You can actually still use the field_get_items() function but eventually pass it 'field_collection_item' instead for the node type.
Something like this should work:
if ($items = field_get_items('node', $node, 'field_faculty_member')) {
//loop through to get the ids so we can take
//advantage of field_collection_item_load_multiple for
//greater efficiency
$field_collection_item_ids = array();
foreach ($items as $item) {
$field_collection_item_ids[] = $item['value'];
}
if ($field_collection_items = field_collection_item_load_multiple($field_collection_item_ids)) {
foreach ($field_collection_items as $subitem) {
//now we load the items within the field collection
if ($items = field_get_items('field_collection_item', $subitem, 'field_faculty_member')) {
//And you can then repeat to go deeper and deeper
//e.g. a field collection item within a field collection
//for instance to get the urls within your faculty members
//item. Best to break this into functions or a class
//to keep your code readable and not have so many nested
//if statements and for loops
}
}
}
}
Hope that helps!
Scott

Related

Drupal - get the field of view

Hello!
I am trying to get the fields of views
There is a code:
$variables = module_invoke('views', 'block_view', 'news-block');
print render($variables['content']);
to display unit software.
Whether it is possible to obtain the field at such a conclusion. Rather get views across the fields from variable $variables
Advance all grateful
Sorry for my English.
You can use views_get_view_result function:
$view = views_get_view_result($name, $display_id); // returns an array conatining the result of the view
print_r($view);
If you prefer to get whole node objects, you can use node_load function with nids of each row:
$view = views_get_view_result($name, $display_id); // returns an array conatining the result of the view
$nodes = array(); // create an empty array to push each node objects
foreach ($view as $row) {
$node = node_load($row->nid); // get the node object by nid
$nodes[] = $node; // push node to $nodes array
}
print_r($nodes);
Also see: https://drupal.stackexchange.com/questions/32825/get-a-views-result-using-php-code-and-iterate-the-proper-way

CakePhp foreach saving only last value in array

I have a problem, right now Im using this foreach loop on CakePhp on which I want to add all the values which are still not on the table for the respecting user. To give a little more context, the user has a menu. And the admin can select which one to add for the user to use. On the next code I receive a array with the menus which will be added as so:
//This is what comes on the ['UserMenuAccessibility'] array:
Array ( [menu_accessibility_id2] => 2 [menu_accessibility_id3] => 3 [menu_accessibility_id4] => 4 [menu_accessibility_id5] => 5 [menu_accessibility_id8] => 8 )
I get the ids of the menus which want to be added to the table for the user to use. And I use the next code to add the menus to the table if they are not there still:
//I check if the array has something cause it can come with no ids.
if (!(isset($this->request->data['UserMenuAccessibility']))) {
$this->request->data['UserMenuAccessibility'] = array();
}
$UserMenuAccessibility = $this->request->data['UserMenuAccessibility'];
foreach ($UserMenuAccessibility as $key => $value) {
$conditions = array(
'UserMenuAccessibility.menu_accessibility_id' => $value,
'UserMenuAccessibility.users_id' => $id
);
if ($this->User->UserMenuAccessibility->hasAny($conditions)) {
} else {
$valuemenu['UserMenuAccessibility']['users_id'] = $id;
$valuemenu['UserMenuAccessibility']['menu_accessibility_id'] = $value;
if ($this->User->UserMenuAccessibility->save($valuemenu)) {
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
For some reason the array is only saving the last new id which is not on the table and not the rest. For example if I have menu 1 and 2 and add 3 and 4 only 4 gets added to the table. For some reason I cant add all the missing menu ids to the table. Any ideas why this is happening?
Thanks for the help on advance.
It looks like your code will save each item, but each call to save() is overwriting the last entry added as $this->User->UserMenuAccessibility->id is set after the first save and will be used for subsequent saves. Try calling $this->User->UserMenuAccessibility->create() before each save to ensure that the model data is reset and ready to accept new data:-
$valuemenu['UserMenuAccessibility']['users_id'] = $id;
$valuemenu['UserMenuAccessibility']['menu_accessibility_id'] = $value;
$this->User->UserMenuAccessibility->create();
if ($this->User->UserMenuAccessibility->save($valuemenu)) {
}
In cakephp 2.0 $this->Model->create() create work fine. But if you are using cakephp version 3 or greater then 3. Then follow the below code
$saveData['itemId'] = 1;
$saveData['qty'] = 2;
$saveData['type'] = '0';
$saveData['status'] = 'active';
$saveData = $this->Model->newEntity($saveData);
$this->Model->save($materialmismatch);
In normal case we use patchEntity
$this->Model->patchEntity($saveData, $this->request->data);
It will only save last values of array so you have to use newEntity() with data
In cakephp3, patchEntity() is normally used. However, when using it for inserting-new/updating entries in a foreach loop, I too saw that it only saves the last element of the array.
What worked for me was using patchEntities(), which as explained in the patchEntity() doc, is used for patching multiple entities at once.
So simplifying and going by the original code sample to handle multiple entities, it could be:
$userMenuAccessibilityObject = TableRegistry::get('UserMenuAccessibility');
foreach ($UserMenuAccessibility as $key => $value) {
$userMenuAccessibility = $userMenuAccessibilityObject->get($value);//get original individual entity if exists
$userMenuAccessibilities[] = $userMenuAccessibility;
$dataToPatch = [
'menu_accessibility_id' => $value,
'users_id' => $id
]//store corresponding entity data in array for patching after foreach
$userMenuAccessibilitiesData[] = $dataToPatch;
}
$userMenuAccessibilities = $userMenuAccessibilityObject->patchEntities($userMenuAccessibilities, $userMenuAccessibilities);
if ($userMenuAccessibilityObject->saveMany($requisitions)) {
} else {
$this->Session->setFlash(__('The users could not be saved. Please, try again.'));
}
Note: I haven't made it handle if entity doesn't exist, create a new one and resume. That can be done with a simple if condition.

Better way to access Laravel array inputs?

Currently I have an array sort. Sort has only one key / value. The keys and values are always different. This array always has just 1 key/value pair. How do I access both elements dynamically in laravel?
I have already solved this but think it is extremely inefficient.
my current solution
I made a function orderQuery() to return the key name.
function orderQuery() {
foreach (Input::get('sort') as $key => $value) {
return $key; // there is only 1 item in the array but this looks like bad practice
}
}
Then I call it like this to respond to my request
->orderBy(orderQuery(), Input::get('sort.'.orderQuery()))
Is there a better way to do this?
You can use key()
$key = key(Input::get('sort'));
If you want to be save reset the pointer first:
$sort = Input::get('sort');
reset($sort);
$key = key($sort);

cakephp - using create() not working as expected

I have a product controller and when I'm saving a new product I want to save some records to another related controller to make a record of what categories the product is associated with.
My code I'm using is:
$this->Product->create();
if ($this->Product->save($this->request->data)) {
$newProductId = $this->Product->getInsertID();
//associate products with categories
foreach($categoriesToSave as $key=>$value) {
$saveArray['CategoriesProduct'] = array('category_id'=>$value, 'product_id'=>$newProductId);
$this->Product->CategoriesProduct->create();
$this->Product->CategoriesProduct->save($saveArray);
$this->Product->CategoriesProduct->clear();
}
}
For some reason though, even if $categoriesToSave has 10 items in it, only the very last one is being saved. So it's obviuosly creating only the one new CategoriesProduct item and saving each record over the top of the last instead of create()-ing a new one.
Can anyone explain what I'm doing wrong and how I can make this work?
The way I would do it would be like this:
//Add a counter
$c = 0
foreach($categoriesToSave as $key=>$value) {
$saveArray[$c]['CategoriesProduct']['category_id'] = $value;
$saveArray[$c]['CategoriesProduct']['product_id'] = $newProductId;
$c++;
}
$this->Product->CategoriesProduct->saveMany($saveArray);
I don't think that is the only way to do it but that should work just fine.
Good luck!

Define and access virtual properties in cakePHP - where and how?

In an application a lecture hasMany slides and a slide belongsTo a lecture. When the index function of lecture is called we would like to add a column which displays the amount off slides belonging to a certain lecture.
I tried to define this as as a $virtualFields in the lecture model like this:
public $virtualFields = array(
'slides_amount' => 'SELECT COUNT(*) AS `count` FROM `eflux`.`slides` AS `Slide` LEFT JOIN `eflux`.`lectures`
AS `Lecture` ON (`Slide`.`lecture_id` = `Lecture`.`id`)
WHERE lecture_id = \''.$id.'\'')';
The problem is that I am not able to access the current $id of the object and therefore MySQL returns an error.
My next try was to use the controller for this:
$lectures = $this->Lecture->findByCourseId($course_id);
for ($i = 0; $i < count($lectures); $i++) {
$slide_amount = $this->Lecture->Slide->find('count', array('conditions' => 'lecture_id = \' '.$id.'\''));
$slide_amounts[$i] = $slide_amount;
}
I was also not able to access the id of the current $lecture-object to determin the amount of slides belonging to that lecture.
Finally I did it in the view:
for ($i = 0; $i < count($slides_helper); $i++) {
if ($slides_helper[$i]['slides']['lecture_id'] == $lecture['Lecture']['id']) {
echo $slides_helper[$i][0]['count'];
}
}?>
Only here I could acces the id of the current object or the $lectures array. But I feel that the view is not the place to handle this.
What is best practice to achieve this goal?
in your controller, you can try:
$lectures = $this->Lecture->find('all', array('conditions'=>array('Lecture.course_id'=>$course_id)));
foreach ($lectures as &$lecture){
$lecture['Lecture']['slide_count'] = count($lecture['Slide']);
}
$this->set('lectures', $lectures);
and then access the count in your view with
foreach ($lectures as $lecture){
echo $lecture['Lecture']['slide_count'];
}
The code might not be exact... you can help us give more accurate code by pasting the results of the following code:
Place this in your controller:
$lectures = $this->Lecture->find('all', array('conditions'=>array('Lecture.course_id'=>$course_id)));
pr($lectures);
EDIT FOR PAGINATION:
Something like this might work for your pagination
$this->paginate['conditions'] = array('Lecture.course_id'=>$course_id);
$this->paginate['limit'] = '10';
$lectures = $this->paginate('Lecture');
//PERFORM THE LOOP TO ADD SLIDE COUNT
$this->set('lectures', $lectures);

Resources