field_to_name_array - Take second-level related data

Hi all,
here I am with a new question for which I cannot find suggestions.

I’m in a custom module; in editview.

I’m automatically populating some fields from the aos_products module when the user chooses a product from a related field:

editviewsdefs.php


............
array (
            'name' => 'codice_prodotto',
            'studio' => 'visible',
            'label' => 'LBL_CODICE_PRODOTTO',
            'displayParams' => 
            array (
              'field_to_name_array' => 
              array (
                'id' => 'aos_products_id_c',
                'name' => 'codice_prodotto',
                'description' => 'descrizione_c',
                'price' => 'prezzo_c',
              ),
            ),
          ),
......................

but how do I get the category related to that product?
In the product table I have id but the name is in another table…

Thank you so much.

I’m not sure, but I think this example does it by populating a separate field

https://stackoverflow.com/questions/41063014/populating-a-field-when-choosing-a-relate-field-suite-crm

If you can get it to work, please post your solution here. Thanks

In the end I decided to use bean (with logic_hook before_save_method) but I can’t get out.

In my custom mdule, I created from Studio the fields to populate which are:
description_c and price_c of AOS_products
categoria_c of AOS_produts_categories.

Now, how do I get the id of my relate field “codice_prodotto”?
And second question, how can I retrieve the name of its category?

I hope someone can help me.
I saw many examples around, I saw the guide but I can’t understand the usage

You have to advance in small parts. Start by getting the hook going.

In which module are you trying to add the hook? Is it running? Can you set a simple constant value to one pf those fields, as a test?

If you have code questions please post the exact code you’re using, and the exact file names and paths where you are making the changes.

Hi pgr, thanks for replying.
I’m adding a hook to a custom module created with Builder.

So, I created my logic_hook.php custom/modules/<my_module>/logic_hooks.php


<?php
$hook_version = 1;
$hook_array = Array();
$hook_array['before_save'] = Array();
$hook_array['before_save'][] = Array(
	1,              
	'autofill',       
	'custom/modules/<my_module>/logic_hooks_class.php',        
	'logic_hooks_class',              
	'before_save_method' 
);  ?>

Then, I saw that when you have a relate field, in vardes there is both a “name” field containing the value seen by the user and an “id_c” field which is what I have to retrieve to find other values associated with the products.

So I think my logic_hooks_class.php can be something like that:
(Note: my relate field is with the standard aos_products module)


<?php
	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
	class logic_hooks_class    
	{
		function before_save_method($bean, $event, $arguments)
		{
		
                    $idproductBeans = $this->bean->'aos_products_id_c'->getBeans();

......

If I have taken well the id of the product selected in the related field, how can I also take the description and copy it to the mydescription_c field of my custom module?

And the second question is: how can I also pull out the name of the category found in aos_produts_categorues? (and copy it to mycategory_c in my custom module)

don’t use apostrophes surrounding the field name.

Look online for examples of using “load_relationship”, that’s what you need to go get data from related records.

You need to know the exact internal name of your relationship. I am not sure how to find that out, but it should be somewhere in the files under “custom7modules/yourmodule”, probably in the vardefs.

I was suspecting it.
But I don’t really know where to find the name of the relationship with a relate field … I looked at the files and also on db but where does it write?

Hi pgr,
in the end I came to this code.

I believe that the way to call the relationship for the relate field (= name of the related module) is correct but but I’m not taking the values correctly and I’m not populating the field correctly…


<?php
	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
	
	class logic_hooks_class    
	{
		function before_save_method($bean, $event, $arguments)
		{
			
			if ($bean->load_relationship('aos_products')) {	
			
				$condizione -> $bean->load_relationship('aos_products');
				$product = $condizione->aos_products->getBeans();

				$product->name = $product ->descrizione_c;

				$bean->save();
			}
		
		}
	}

?>

please try to make me better understood :frowning:

First I would start by using a constant value just to test if the hook is running, and if it does its job:

$product->name = "hello world!";

Then I would be very careful about calling bean->save inside a before_save logic hook! Did you find examples online doing that? I am not sure, but I fear that It could generate an endless loop…

Finally - getbeans returns an array, you need to index the first item before getting the fields:


	$condizione -> $bean->load_relationship('aos_products');
	$product = reset($condizione->aos_products->getBeans());  // get only the first item

	$product->name = $product->descrizione_c;

Or you could use a “for each” loop to check the various items, of course.

Hi pgr,
I reflected on what you wrote.

Even though I’ve seen some that update before_save, an after_save update (which is safer) is fine for me.

I made some small progress but not enough.

I tried to use this code (I followed this example https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.1/Data_Framework/Models/SugarBean/):


function after_save_method ($bean, $event, $arguments)
		{
			//if(!$bean->name) {
				$module="clob_CLOB_condizioni";
				$bean = BeanFactory::newBean($module);

				$bean->name = 'Hello';
				$bean->save();

            //}                

		}

The page goes in error but in the db I see that the value is written in correspondence of some IDs (not only of the last one).

Furthermore, I need to do something more complex:

  • retrieve the product id in correspondence with the record ID just saved
  • retrieve its description, price and category (which are in aos_products and aos_products_category)
  • update myDesc, myPrice, myCat in the current module corresponding to the record just saved

But this is still far away, I still need to figure out how to update any field without making an issue.

Can you help me proceed step by step?

I’m so happy!
After so much effort I managed to make something work!

Now, I am able to get the id of the last inserted record and update the name field (without loop).

This is my code:



<?php
	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
	
	class logic_hooks_class    
	{
		function after_save_method ($bean, $event, $arguments)
		{
			if (!isset($bean->ignore_update_c) || $bean->ignore_update_c === false)
			{
				//if (!$bean->codice_prodotto)
				//{

					$record_id = $bean->id;
					
					$bean->ignore_update_c = true;
					$bean->name=$record_id;
					$bean->save();

				//}                
			}
		}
	}

?>

Please note that mine
if (! $ bean-> product_code)
it’s still wrong.
I would like to say “Run only if product_code is not empty”.

Now, by ID, I have to retrieve all the fields I need and complete what has been written before:

  • retrieve the product id in correspondence with the record ID just saved
  • retrieve its description, price and category (which are in aos_products and aos_products_category)
  • update myDesc, myPrice, myCat in the current module corresponding to the record just saved

Well, I’m trying to add a query but it doesn’t work


<?php
	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
	
	class logic_hooks_class    
	{
		function after_save_method ($bean, $event, $arguments)
		{
			if (!isset($bean->ignore_update_c) || $bean->ignore_update_c === false)
			{
				//if (!$bean->aos_products_id_c)
				//{

					$record_id = $bean->id;
					$product_id = $bean->aos_products_id_c;
					
					//prendo i dati dei prodotti
					$query = "SELECT pd.id, pd.descrizione, pd.price FROM aos_products pd LEFT JOIN aos_products_cstm pdc ON pd.id = pdc.id_c WHERE pd.id = '" . $record_id . "'";
					$res = $db->query($query, true);
					$row = $db->fetchByAssoc($res);
						$id = $row['id'];
						$descrizione = $row['descrizione'];
						$prezzo = $row['price'];
					
					$bean->ignore_update_c = true;
					//$bean->descrizione_c = $descrizione;

					$bean->save();
					
					
				//}                
			}
		}
	}

?>

Where am I doing wrong?

I am sorry. There are a lot of mistakes.

Let’s start from the beginning.

You want take data to the first module (???) from the second module (AOS_products).
You should have the keys of array ‘field_to_name_array’ , which are the names of fields of the second module and value of array ‘field_to_name_array’ which are the names of fields of the first module in file editviewsdefs.php . It will work only for fields of these 2 modules on Editview form.

If you want to use data from the third module, you should use logic hook ‘before_save’ (not after_save). Example:

 function before_save_method($bean, $event, $arguments){
        $second_module = new <name_of_second_module>();
        $second_module->retrieve($bean->aos_products_id_c);          // ‘aos_products_id_c’  fill in Editview form
        $third_module = new <name_of_third_module>();
        $third_module->retrieve($second_module-><name_of_id_field>);
        $bean->codice_prodotto = $third_module->name; 
    }

I don’t know all structure of your modules and fields. Check all the names. If you write configuration modules and fields I can write the correct hook.

Resolved! Isn’t this the right way to do this?

At the moment after_save it seems to me working well…

Here is my updated code:


<?php
	if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
	
	class logic_hooks_class    
	{
		function after_save_method ($bean, $event, $arguments)
		{
			if (!isset($bean->ignore_update_c) || $bean->ignore_update_c === false)
			{
				//if (!$bean->aos_products_id_c)
				//{
					$db = DBManagerFactory::getInstance();
					
					$record_id = $bean->id;
					$product_id = $bean->aos_products_id_c;
					$sconto = $bean->sconto;
					
					$query = "SELECT id, description, price FROM aos_products WHERE id = '" . $product_id . "'";
					$result = $db->query($query);  
					
					while( $row = $db->fetchByAssoc($result)){  
						
						$descrizione = $row['description'];
						
					}  
						
					$prezzo = 70; //to change with the value from the db
					
					$bean->ignore_update_c = true;
					$bean->descrizione_c = $descrizione;
					if ($sconto<>null || $sconto<>0)
					{
						$bean->prezzo_scontato_c = $prezzo - ($prezzo/100 * $sconto);
					}
					
					$bean->save();
					

				//}                
			}
		}
	}

?>
  1. If you use - ’ !isset($bean->ignore_update_c) || $bean->ignore_update_c === false ', it’s not a good decision.
  2. Why do you use query to DB? You can use object. It’s more easy.
  3. There is code for you:
function before_save_method($bean, $event, $arguments){
    $second_module = new AOS_PRODUCTS();
    $second_module->retrieve($bean->aos_products_id_c);
    $bean->descrizione_c = $second_module->description;
    $prezzo = 70;
    if ($bean->sconto<>null || $bean->sconto<>0){
            $bean->prezzo_scontato_c = $prezzo - ($prezzo/100 * $bean->sconto);
    }
}

Why?
I read in the guide that ignore_update_c serves to prevent loops but I have no experience to judge this method

I read documentation too. Method ‘before_save’ should be used when you want to change data of current object. When you use ‘before_save’ you don’t call save() because save() will be called automatically. Method ‘after_save’ should be used when you want to work with data of other objects related to current object. When you use ‘after_save’ you should call save() obligatory and switch on control of endless cycle as you planned to do.
In your situation ‘before_save’ will be called only one time, but ‘after_save’ will be called two times. You should remember that you use ‘ignore_update_c’ as temporary variable and never use it as really field in this object.

As far as I remember, method ‘after_save’ was implemented earlier in SugarCRM then ‘before_save’.

Thanks for the rich explanation, p.koretsky.
Even if my solution is working at the moment, I will also try following your suggestions.

Good luck. I am sure that everything will be fine. :slight_smile: