Logic hook not working in a Custom Module

Hello everyone!

I have coded logic hooks for the Project module and everything was okay, but when I tried to replicate it for a custom module I haven’t managed to get it running. In fact I had to remove the logic hook files because it kept doing weird things, like not being able to add a relationship.

I tried to place the files in the /custom/modules/[Module] folder but I read in the documentation that it would be better to place the files in the Extension folder and then do a rebuild so that it generates another logic hook file, this time in /custom/modules/[Module] folder.

So I placed these files in the /custom/Extension/plata_Plataformas/Ext/LogicHooks/ folder:

logic_hooks.php


<?php
// Do not store anything in this file that is not part of the array or the hook version.  This file will	
// be automatically rebuilt in the future. 
 $hook_version = 1; 
$hook_array = Array(); 
// position, file, function 
$hook_array['after_relationship_add'] = Array(); 
$hook_array['after_relationship_add'][] = Array(1, 'addRelationship', 'custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships.php','logic_hook_after_relationships', 'fillRelationships'); 
$hook_array['after_relationship_delete'] = Array(); 
$hook_array['after_relationship_delete'][] = Array(2, 'deleteRelationship', 'custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships.php','logic_hook_after_relationships', 'fillRelationships'); 

?>

logic_hook_after_relationships.php


<?php

    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   
    class logic_hook_after_relationships
    {
        function fillRelationships(&$focus, $event, $arguments) {
            
            $empresasAdheridas = $this->rellenaEntidad($focus->get_linked_beans('accounts','Accounts',array()));

            $focus->empresas_c = $empresasAdheridas;
            
            $focus->save(true);
        }
        
        function rellenaEntidad($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $str .=  ", " . $bean->name;
            }
            $str = substr($str, 2);
            return $str;
        }
        
        function rellenaAmbitos($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $str .= ", " . $bean->ambito;
            }
            $str = substr($str, 2);
            return $str;
        }
    }

?>

And it generated this file in /custom/module/plata_Plataformas/Ext/LogicHooks/
logichooks.ext.php


<?php 
 //WARNING: The contents of this file are auto-generated


// Do not store anything in this file that is not part of the array or the hook version.  This file will	
// be automatically rebuilt in the future. 
 $hook_version = 1; 
$hook_array = Array(); 
// position, file, function 
$hook_array['after_relationship_add'] = Array(); 
$hook_array['after_relationship_add'][] = Array(1, 'addRelationship', 'custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships.php','logic_hook_after_relationships', 'fillRelationships'); 
$hook_array['after_relationship_delete'] = Array(); 
$hook_array['after_relationship_delete'][] = Array(2, 'deleteRelationship', 'custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships.php','logic_hook_after_relationships', 'fillRelationships'); 




    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   
    class logic_hook_after_relationships
    {
        function fillRelationships(&$focus, $event, $arguments) {
            
            $empresasAdheridas = $this->rellenaEntidad($focus->get_linked_beans('accounts','Accounts',array()));

            $focus->empresas_c = $empresasAdheridas;
            
            $focus->save(true);
        }
        
        function rellenaEntidad($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $str .=  ", " . $bean->name;
            }
            $str = substr($str, 2);
            return $str;
        }
        
        function rellenaAmbitos($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $str .= ", " . $bean->ambito;
            }
            $str = substr($str, 2);
            return $str;
        }
    }


?>

I think everything is okay, but if I add a relationship it doesn’t even show in the panel. And of course if I set a breakpoint in the function that gets called with the logic hook, it doesn’t stop, so the error is before the call… (How adding a logic hook can generate an error BEFORE the logic hook gets executed???)

This is the log error:

Any ideas?

Thanks!

1 Like

I’m not sure, but this is what it looks like… your PHP is loading the class twice, so it gives an error about redeclaration. Maybe you have too many files lying around and you need to check which of them are getting picked up.

This explains why the error is before the call, the classes get loaded with requires first, only then are they called.

Check out this blog post and refine your filter until you can see exactly which files are being loaded. If two of those files contain the same class, you found your problem.

Also consider the possibility that simply the name logic_hook_after_relationships is already used by someone else. Try calling it la_mia_logic_hook_after_relationships_no_la_tuya or something, to see if the error goes away…

Generally the bean functions allows to put 3 parameters which are $bean, $event, $arguments
but why you have another one and omitted $bean?
function fillRelationships(&$focus, $event, $arguments) {

I just changed the names, in any case I had it duplicated and still the same.

I have attached the log that I see after trying to fire the logic hook.

I don’t see that it’s loading two different classes…

What do you have in your filter?

auditctl -l 

Because your original error was

PHP Fatal error: Cannot redeclare class logic_hook_after_relationships in /media/sf_GES_Alliance/gesalliance-suite/custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships.php on line 5

… and I don’t see any file with that name there.

2 Likes

I have this in my filter:

[quote]LIST_RULES: exit,always dir=/media/sf_GES_Alliance/gesalliance-suite/custom/modules/plata_Plataformas/Ext/LogicHooks syscall=all
LIST_RULES: exit,always dir=/media/sf_GES_Alliance/gesalliance-suite/custom/modules/plata_Plataformas/Ext/LogicHooks perm=rwa
LIST_RULES: exit,always dir=/media/sf_GES_Alliance/gesalliance-suite/custom/Extension/modules/plata_Plataformas/Ext/LogicHooks perm=rwa
[/quote]

I do have the file /media/sf_GES_Alliance/gesalliance-suite/custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships.php.

I am declaring two different logic hooks pointing to the same class… I removed one so that the class is only called from one logic hook. The problem is still the same.

I changed the name, just in case, and the problem is still there:

In the audit log only appears:

I think it’s because it reads the file autogenerated by SuiteCRM after doing the rebuild. (Could it be that this autogenerated file and the one that I placed in the /Extension have the same class name??)

If you’re looking for additional files that it tries to load (but that you are not aware of), it’s better to make wider filters, to catch a lot.

For example, everything under custom/, or everything under /custom/Extension/modules

and then use grep to narrow it down, to remove lines you can see obviously have nothing to do with your problem.

And for a completely different approach that just occurred to me:
https://stackoverflow.com/questions/5854057/get-file-where-class-has-been-declared-required-from

1 Like

I finally made it work:
removed the files, rebuild, created the files again from scratch (with new names) and rebuild and it worked.

The logic hook code was copy-paste of one of other module. But the custom module didn’t work like the other one. Instead I had to query again the database in order to achieve what I wanted:


function fillRelationships(&$focus, $event, $arguments) {

            $empresasAdheridas = $this->rellenaEntidad($focus->plata_plataformas_accounts_1->rows);
            if ($empresasAdheridas == false){
                $focus->empresas_adheridas_c = "";
            } else {
                $focus->empresas_adheridas_c = $empresasAdheridas;            
            }
            
            $focus->save(true);
        }

function getNombreEmpresaAdheridaPorId($id) {
            $empresa = new Account();
            $empresa->retrieve($id);
            return $empresa->name;
        }

function rellenaEntidad($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $nombre = $this->getNombreEmpresaAdheridaPorId($bean['id']);
                $str .=  ", " . $nombre;
            }
            $str = substr($str, 2);
            return $str;
        }

I had to create another function to retrieve the Accounts, because I couldn’t find them while debugging anywhere.

Thank you!

Great to hear that!

For future reference, in case anybody comes here looking for similar answers, can you please tell us the details of your solution (where exactly you placed these files, and how you named them)?

Ok, I tried to remember every step:

[li]First I placed the two files that I posted before in the Extension folder:
[/li]

\custom\Extension\modules\plata_Plataformas\Ext\LogicHooks\

logic_hooks.php


<?php
// Do not store anything in this file that is not part of the array or the hook version.  This file will	
// be automatically rebuilt in the future. 
 $hook_version = 1; 
$hook_array = Array(); 
// position, file, function 
$hook_array['after_relationship_add'] = Array(); 
$hook_array['after_relationship_add'][] = Array(1, 'addRelationship', 'custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships_plataformas.php','logic_hook_after_relationships_plataformas', 'fillRelationships'); 
$hook_array['after_relationship_delete'] = Array(); 
$hook_array['after_relationship_delete'][] = Array(2, 'deleteRelationship', 'custom/Extension/modules/plata_Plataformas/Ext/LogicHooks/logic_hook_after_relationships_plataformas.php','logic_hook_after_relationships_plataformas', 'fillRelationships'); 

?>

logic_hook_after_relationships_plataformas.php


<?php

    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   
     class logic_hook_after_relationships_plataformas
    {
        function fillRelationships(&$focus, $event, $arguments) {

            $empresasAdheridas = $this->rellenaEntidad($focus->plata_plataformas_accounts_1->rows);
            if ($empresasAdheridas == false){
                $focus->empresas_adheridas_c = "";
            } else {
                $focus->empresas_adheridas_c = $empresasAdheridas;            
            }
            
            $focus->save(true);
        }
        
        function getNombreEmpresaAdheridaPorId($id) {
            $empresa = new Account();
            $empresa->retrieve($id);
            return $empresa->name;
        }
        function rellenaEntidad($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $nombre = $this->getNombreEmpresaAdheridaPorId($bean['id']);
                $str .=  ", " . $nombre;
            }
            $str = substr($str, 2);
            return $str;
        }
        
        function rellenaAmbitos($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $str .= ", " . $bean->ambito;
            }
            $str = substr($str, 2);
            return $str;
        }
    }


?>

[li]Then I rebuilt it and it generated the file: \custom\modules\plata_Plataformas\Ext\LogicHooks\logichooks.ext.php
[/li]
[li]I deleted the files in the Extension folder.
[/li]
I now have only one file:

\custom\modules\plata_Plataformas\Ext\LogicHooks\logichooks.ext.php


<?php 
 //WARNING: The contents of this file are auto-generated


// Do not store anything in this file that is not part of the array or the hook version.  This file will	
// be automatically rebuilt in the future. 
 $hook_version = 1; 
$hook_array = Array(); 
// position, file, function 
$hook_array['after_relationship_add'] = Array(); 
$hook_array['after_relationship_add'][] = Array(1, 'addRelationship', 'custom/modules/plata_Plataformas/Ext/LogicHooks/logichooks.ext.php','logic_hook_after_relationships_plataformas', 'fillRelationships'); 
$hook_array['after_relationship_delete'] = Array(); 
$hook_array['after_relationship_delete'][] = Array(2, 'deleteRelationship', 'custom/modules/plata_Plataformas/Ext/LogicHooks/logichooks.ext.php','logic_hook_after_relationships_plataformas', 'fillRelationships'); 




    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   
    class logic_hook_after_relationships_plataformas
    {
        function fillRelationships(&$focus, $event, $arguments) {

            $empresasAdheridas = $this->rellenaEntidad($focus->plata_plataformas_accounts_1->rows);
            if ($empresasAdheridas == false){
                $focus->empresas_adheridas_c = "";
            } else {
                $focus->empresas_adheridas_c = $empresasAdheridas;            
            }
            
            $focus->save(true);
        }
        
        function getNombreEmpresaAdheridaPorId($id) {
            $empresa = new Account();
            $empresa->retrieve($id);
            return $empresa->name;
        }
        function rellenaEntidad($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $nombre = $this->getNombreEmpresaAdheridaPorId($bean['id']);
                $str .=  ", " . $nombre;
            }
            $str = substr($str, 2);
            return $str;
        }
        
        function rellenaAmbitos($arrayEmpresas) {
            $str = "";
            foreach ($arrayEmpresas as $bean) {
                $str .= ", " . $bean->ambito;
            }
            $str = substr($str, 2);
            return $str;
        }
    }


?>

NOTE: I haven’t done a rebuild after this. Keep the two first files just in case it messes up after a rebuild.

Ok, thanks a lot! Normally you don’t have to remove the original files. And that way you can rebuild as often as you need.

I not sure if this is correct but the way I’ve seen logic hooks created is this:

Put your logic hook definition files (NOT the files that contain your logic, the one with before_save, after_save etc) in the custom/Extension/modules//Ext/LogicHooks folder - name them whatever you want
Those files should have an entry in them pointing to where your files that contain your CLASS and FUNCTION declarations are, generally in your custom/modules/ folder, or a sub folder of same e.g. logichook_functions in your code the following line

$hook_array[‘after_relationship_add’][] = Array(1, ‘addRelationship’, ‘custom/modules/plata_Plataformas/Ext/LogicHooks/logichooks.ext.php’,‘logic_hook_after_relationships_plataformas’, ‘fillRelationships’);

This entry:
‘custom/modules/plata_Plataformas/Ext/LogicHooks/logichooks.ext.php’

is pointing to where your logic/code is located.

Make sure your logic hook definition files have the correct path, class and functions in them - the line above

I’m not sure if the class/functions SHOULDN’T be part of the logichooks.ext.php file but I’ve never seen logic hooks defined this way

When you do an Admin/QRR the logichook definition files in custom/Extension/modules/<modulename/Ext/LogicHooks are compiled to create the custom/modules//Ext/LogicHooks/logichooks.ext.php file (in your case it’s compiling your code into that file as well)

Each line in that file points to logic hook LOGIC files where the class/function is defined. When the logic hook fires it loads your logic file and parses your code

I suppose it shouldn’t matter how you create them if they work, but as mentioned I’ve never seen the logic combined with the definitions as you have with the logichooks.ext.php file