View Poll Results: Would you find related module search useful?

Voters
18. You may not vote on this poll
  • Yes

    18 100.00%
  • No

    0 0%
Page 1 of 3 123 LastLast
Results 1 to 10 of 26

Thread: Basic/Adv Search join/left join seaches

  1. #1
    kenneth.thorman is offline Sugar Community Member
    Join Date
    Oct 2007
    Posts
    191

    Default Basic/Adv Search join/left join seaches

    HOWTO HACK Sugar to easily allow cross module seaches.

    Please find the attaced SVN patch to 5.1.0b code for the file include/SearchForm/SearchForm2.php.

    This will allow you to change 2 files in a module to get rather advanced queries.

    The below sample is illustrating a consultant (person) that has many to many relations to role, department, group and finally division inderectly via department (division -> department -> consultant)


    vardefs.php
    for each related field you need you must define a new field of type non-db
    Code:
      // HACK Kenneth Thorman : To add support for the cross table queries across modules
      'role' => 
      array (
        'name' => 'role',
        'source'=>'non-db',
        'type' => 'relatedenum',
      ),  
      'department' => 
      array (
        'name' => 'department',
        'source'=>'non-db',
        'type' => 'relatedenum',
      ),  
      'division' => 
      array (
        'name' => 'division',
        'source'=>'non-db',
        'type' => 'relatedenum',
      ),  
      'group' => 
      array (
        'name' => 'group',
        'source'=>'non-db',
        'type' => 'relatedenum',
      ),  
      // HACK Kenneth Thorman : To add support for the cross table queries across modules

    searchdefs.php
    Code:
    	    // HACK Kenneth Thorman : To add support for the cross table queries across modules
            'role' => array(
                'name' => 'role', 
                'type' => 'enum', 
                'label' => 'LBL_ROLE', 
                'options' => '',                
                'options_sql' => 'select id as id, name as value from rm_role where deleted = 0',
                /**
                * join_sql:
                * Due to the whay the listview and the search view works together the different where clauses are imploded together forcing us to specify
                * this join as a subquery instead. NOTE that there is no ending parenthesis
                */
                'join_sql' => " base_consultant.id in (
                                    select base_consultant.id from base_consultant     
                                    inner join rm_role_base_consultant on base_consultant.id = rm_role_base_consultant.base_consultant_idb and rm_role_base_consultant.deleted = 0 
                                    inner join rm_role on rm_role_base_consultant.rm_role_ida = rm_role.id and rm_role.deleted = 0 
                                 ",
                'table_alias' => 'rm_role',
                'db_column' => 'id',       
            ),	  
            'department' => array (
                'name' => 'department',
                'type' => 'enum', 
                'label' => 'LBL_DEPARTMENT', 
                'options' => '',                
                'options_sql' => 'select id as id, name as value from base_department where deleted = 0',
                /**
                * join_sql:
                * Due to the whay the listview and the search view works together the different where clauses are imploded together forcing us to specify
                * this join as a subquery instead. NOTE that there is no ending parenthesis
                */
                'join_sql' => ' base_consultant.id in (
                                select base_consultant.id from base_consultant 
                                inner join base_departe_consultant on base_consultant.id = base_departe_consultant.base_consultant_idb and base_departe_consultant.deleted = 0 
                                inner join base_department on base_departe_consultant.base_department_ida = base_department.id and base_department.deleted = 0 ',
                'table_alias' => 'base_department',
                'db_column' => 'id',
            ),
            'group' => array (
                'name' => 'group',       
                'type' => 'enum', 
                'label' => 'LBL_GROUP', 
                'options' => '',                
                'options_sql' => 'select id as id, name as value from base_group where deleted = 0',
                /**
                * join_sql:
                * Due to the whay the listview and the search view works together the different where clauses are imploded together forcing us to specify
                * this join as a subquery instead. NOTE that there is no ending parenthesis
                */
                'join_sql' => ' base_consultant.id in (
                                select base_consultant.id from base_consultant 
                                inner join base_group_e_consultant on base_consultant.id = base_group_e_consultant.base_consultant_idb and base_group_e_consultant.deleted = 0 
                                inner join base_group on base_group_e_consultant.base_group_ida = base_group.id and base_group.deleted = 0 ',
                'table_alias' => 'base_group',
                'db_column' => 'id',       
            ),
            'division' => array (
                'name' => 'division',       
                'type' => 'enum', 
                'label' => 'LBL_DIVISION', 
                'options' => '',                
                'options_sql' => 'select id as id, name as value from base_division where deleted = 0',
                /**
                * join_sql:
                * Due to the whay the listview and the search view works together the different where clauses are imploded together forcing us to specify
                * this join as a subquery instead. NOTE that there is no ending parenthesis
                */
                'join_sql' => ' base_consultant.id in (
                                select base_consultant.id from base_consultant 
                                inner join base_departe_consultant as base_departe_consultant2 on base_departe_consultant2.base_consultant_idb = base_consultant.id and base_departe_consultant2.deleted = 0
                                inner join base_divisie_department as base_divisie_department2 on base_divisie_department2.base_department_idb = base_departe_consultant2.base_department_ida and base_divisie_department2.deleted = 0
                                inner join base_division on base_division.id = base_divisie_department2.base_division_ida and base_division.deleted = 0 ',
                'table_alias' => 'base_division',
                'db_column' => 'id',       
            ),
    	    // HACK Kenneth Thorman : To add support for the cross table queries across modules
    Attached Files Attached Files

  2. #2
    andy773 is offline Member
    Join Date
    Dec 2008
    Posts
    19

    Default Re: Basic/Adv Search join/left join seaches

    Hi Ken,

    Thanks for the post, I have tried but it works in half way.

    I mean, it can create a search enum list in the consultant module and show all the roles.

    However, when i select any role and then click search to get some consultants, it shows nothing.

    I have followed all the instruction in your post, and found that in the attached code, it seems the code begin with 'if ($type == 'relatedenum')' dosen't work.

    My sugarcrm version is 5.0.0.g. I am not sure if it is a problem?

    Can you give any hint? Thanks heaps.

  3. #3
    kenneth.thorman is offline Sugar Community Member
    Join Date
    Oct 2007
    Posts
    191

    Default Re: Basic/Adv Search join/left join seaches

    Hi Andy

    I do not have the 5.0.0f source available here so I cannot debug it. But I know that there were introduced alot of changes to core sugar going from 5.0 to 5.1. The most major being a complete rewrite of the relationships between modules. These changes involved SugarBean, Studio, ModuleBuilder, ModuleInstaller, ModuleLoader ...
    with significant changes being made also architectural So I do not think you can get the hack to work in 5.0, maybe it can be rewritten in some way but I am afraid I cannot give you any pointers here.

    Merry Christmas and good luck.
    Regards
    Kenneth Thorman

  4. #4
    andy773 is offline Member
    Join Date
    Dec 2008
    Posts
    19

    Default Re: Basic/Adv Search join/left join seaches

    Hi ken,

    Thank you for the reply. Actually, I create a new module like 'Company' and add a many to many relationship with accounts. I want to search search the company by account name which is similar as contacts in the basic searvh view.

    It seems this requirement is not supported in the latest 5.2.0 version too.

  5. #5
    kenneth.thorman is offline Sugar Community Member
    Join Date
    Oct 2007
    Posts
    191

    Default Re: Basic/Adv Search join/left join seaches

    Since there normally are rather many and major changes between the 5.x and 5.y version s this does not surprise me. Please test this on a 5.1.0.b release code, we are using it several places both in Basic Search/Adv Search and actually also in an extentions to dashlets that allows us to make adv. joins and search criteria.

    Regards
    Ken

  6. #6
    jaro1981 is offline Junior Member
    Join Date
    Feb 2009
    Posts
    2

    Default Re: Basic/Adv Search join/left join seaches

    hi ken,
    i found it very usefull thx!
    what i had to change due to version 2.5.0a is part in function generateSearchWhere()

    instead of

    Code:
    // If there is only a single element in the array the implode function does not suround the value with ''
    if (count($parms['value']) == 1) {
        $temp .= " in ('"  . implode("','",$parms['value']) . "')";
    }
    else {
        $temp .= ' in ('  . implode("','",$parms['value']) . ')';
    }
    i use only

    Code:
    // If there is only a single element in the array the implode function does not suround the value with ''
    $temp .= " in ('"  . implode("','",$parms['value']) . "')";
    and instead of

    Code:
    // Need to reset the db_field otherwise the other logic in SearchForm2 will generate SQL that is not valid
    unset($parms['db_field']);
    i use

    Code:
    // Need to reset the db_field otherwise the other logic in SearchForm2 will generate SQL that is not valid
    $parms['db_field'] = array();
    it works fine so far.
    can be it's possible to make this upgrade safe?
    anyways this helps a lot even non upgrade safe.

  7. #7
    kenneth.thorman is offline Sugar Community Member
    Join Date
    Oct 2007
    Posts
    191

    Default Re: Basic/Adv Search join/left join seaches

    I am happy that it was any use to use.

    Regards
    Kenneth Thorman

  8. #8
    SugarDev.net is offline Sugar Community Member
    Join Date
    Feb 2008
    Posts
    1,401

    Default Re: Basic/Adv Search join/left join seaches

    Bumping this up. There is a real need for searching in SubPanel items. (in many-to-many relations, and in one-to-many relations from the '1' side).

    A few notes:

    - When trying to implement this for a custom module that has a M:N relationship with Users, the fact that the assigned_user is displayed in ListView prevented your patch from working. To be clear: It's the same module, but the relationship is completely separate from the assigned_user
    - The 'table_alias' attribute in searchdefs.php suggests a MySQL alias, but this field needs to hold the name of the opposing module's table.

    In 5.2.0c

    Thank you very much for this .
    Developers go here
    Businesses go there (Dutch)

    Modules:
    SugarDev.net Developer Tools | Config | Dutch Language Pack
    "Nothing gets fixed unless there is a bug"

  9. #9
    kenneth.thorman is offline Sugar Community Member
    Join Date
    Oct 2007
    Posts
    191

    Default Re: Basic/Adv Search join/left join seaches

    Hi SugarDev.net

    I have run into the issue with the assigned_to field when using this advanced join functionality in the advanced dashlet framework I have built. I have posted the entire hack (which modifies 2 files or so + adds a few new ones) on the bug tracker as well but have not had any replies yet.

    I will post a few screen dumps of one of the dashlets in function (the framework works for charts dashlets as well)

    If there is is interest then lets bump the thread so Sugar looks into this.
    (Then I dont have to maintain the code anymore)

    Regards
    Kenneth Thorman

  10. #10
    kenneth.thorman is offline Sugar Community Member
    Join Date
    Oct 2007
    Posts
    191

    Default Re: Basic/Adv Search join/left join seaches

    As promised here are some screen shots

    The creation of a dashlet is almost the same as specifying the search parameters for the advanced search.
    There is a little bit more that need to be specified due to the display options.

    AppinuxDashlets\Dashlets\ProjectManagement\Project IssuesDashlet\ProjectIssuesDashlet.data.php
    Code:
    <?php
    if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    
    global $current_user;
    global $timedate;
    $dateformat = $timedate->get_date_format();
    
    /**
    * This are the filters that you want to display in the dashlet dialog these names
    * must match the corresponding field names in the vardefs.php file
    */
    $startDate = date($dateformat, time());
    $endDate = date($dateformat,strtotime("+1 months"));
    
    $dashletData['ProjectIssuesDashlet']['searchFields'] = array(
        'foundrelease'    => array('default' => ''),
        'status_filter'         => array('default' => ''),
        'priority_filter'         => array('default' => ''),
        'fixedrelease'         => array('default' => ''),
        'user' => array ('default' => '',),  
        'project' => array ('default' => '',),
    );
    
    /**
    * Allows you to affect how the sql is generated
    */
    $dashletData['ProjectIssuesDashlet']['sql_options'] = array(
        'custom_select' => ' ,users.user_name as user',
        'custom_from' => ' inner join users on users.id = pm_issue.assigned_user_id ',
        'distinct' => true,
    );
    
    /**
    * This are the different columns you can choose to display using the dashlet dialog
    * the names need to match either:
    * 
    * - a field name from the main modules vardefs.php
    * - or a field in our custom vardefs.php located in this directory
    */
    $dashletData['ProjectIssuesDashlet']['columns'] = array(
      'name' => 
      array (
        'width' => '40%',
        'label' => 'LBL_LIST_NAME',
        'link' => true,
        'default' => true,
        'name' => 'name',
      ),
      'foundrelease' => 
      array (
        'width' => '10%',
        'label' => 'LBL_FOUNDRELEASE',
        'default' => true,
        'name' => 'foundrelease',
      ),
      'type' => 
      array (
        'width' => '10%',
        'label' => 'LBL_TYPE',
        'sortable' => false,
        'default' => true,
        'name' => 'type',
      ),
      'status' => 
      array (
        'width' => '10%',
        'label' => 'LBL_STATUS',
        'sortable' => false,
        'default' => true,
        'name' => 'status',
      ),
      'user' => 
      array (
        'width' => '8%',
        'label' => 'LBL_LIST_ASSIGNED_USER',
        'name' => 'user',
        'default' => true,
      ),
      'author' => 
      array (
        'width' => '10%',
        'label' => 'LBL_AUTHOR',
        'default' => false,
        'name' => 'author',
      ),
      'priority' => 
      array (
        'width' => '10%',
        'label' => 'LBL_PRIORITY',
        'sortable' => false,
        'default' => false,
        'name' => 'priority',
      ),
      'effort' => 
      array (
        'width' => '10%',
        'label' => 'LBL_EFFORT',
        'default' => false,
        'name' => 'effort',
      ),
      'duration' => 
      array (
        'width' => '10%',
        'label' => 'LBL_DURATION',
        'default' => false,
        'name' => 'duration',
      ),
      'cost' => 
      array (
        'width' => '10%',
        'label' => 'LBL_COST',
        'currency_format' => true,
        'default' => false,
      ),
      'fixedrelease' => 
      array (
        'width' => '10%',
        'label' => 'LBL_FIXEDRELEASE',
        'default' => false,
        'name' => 'fixedrelease',
      ),
    );
    ?>
    AppinuxDashlets\Dashlets\ProjectManagement\Project IssuesDashlet\vardefs.php
    Code:
    <?php
    /** 
    * This is a dummy PHP class designed to hold the values selected base from the custom select instead of modifying the 
    * original vardef. 
    * 
    * Since the built in dashlet generator handles everything for us including the Configure screen we might as well 
    * try to code around the restrictions using this dummy class both for search filter widgets definitions as well as
    * other things 
    */
    $dictionary['ProjectIssues'] = array(
        'table'=>'pm_issue',     // main module table
    	'fields'=>array (
            /**
            * Each of the fields defined here are used to decide how sugar shows them in the GUI
            * 1. either in the display mode of the dashlet  -   this is only for fields that is not part of the main module's vardef
            * 2. or how a field/filter should look in configure mode. 
            * 
            * Leave the table clause to the same as you base table for the query.
            */
    		'name' => 
    		array (
    			'vname' => 'LBL_LIST_NAME',
    			'name' => 'name',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'foundrelease' => 
    		array (
    			'vname' => 'LBL_FOUNDRELEASE',
    			'name' => 'foundrelease',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'type' => 
    		array (
    			'vname' => 'LBL_TYPE',
    			'name' => 'type',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'status' => 
    		array (
    			'vname' => 'LBL_STATUS',
    			'name' => 'status',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'status_filter' => 
    		array (
    			'vname' => 'LBL_STATUS',
    			'name' => 'status_filter',
    			'type' => 'dashletenum',
    			'source' => 'non-db',
                'options' => $GLOBALS['app_list_strings']['pm_issueStatus_list'],
                'options_sql' => '',
                'remove_blank' => false,    
                'join_sql' => '',
                'table_alias' => 'pm_issue',
                'db_column' => 'status',       
    		),
    		'author' => 
    		array (
    			'vname' => 'LBL_AUTHOR',
    			'name' => 'author',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'priority' => 
    		array (
    			'vname' => 'LBL_PRIORITY',
    			'name' => 'priority',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'priority_filter' => 
    		array (
    			'vname' => 'LBL_PRIORITY',
    			'name' => 'priority_filter',
    			'type' => 'dashletenum',
    			'source' => 'non-db',
                'options' => $GLOBALS['app_list_strings']['pm_issuePriority_list'],
                'options_sql' => '',
                'remove_blank' => false,    
                'join_sql' => '',
                'table_alias' => 'pm_issue',
                'db_column' => 'priority',       
    		),
    		'effort' => 
    		array (
    			'vname' => 'LBL_EFFORT',
    			'name' => 'effort',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'duration' => 
    		array (
    			'vname' => 'LBL_DURATION',
    			'name' => 'duration',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'cost' => 
    		array (
    			'name' => 'cost',
    			'vname' => 'LBL_COST',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'fixedrelease' => 
    		array (
    			'vname' => 'LBL_FIXEDRELEASE',
    			'name' => 'fixedrelease',
    			'type' => 'varchar',
    			'source' => 'db',
    		),
    		'fixedrelease_filter' => 
    		array (
    			'vname' => 'LBL_FIXEDRELEASE',
    			'name' => 'fixedrelease',
    			'type' => 'varchar',
    			'source' => 'non-db',
                'options' => '',
                'options_sql' => '',
                'remove_blank' => false,    
                'join_sql' => '',
                'table_alias' => 'pm_issue',
                'db_column' => 'fixedrelease',       
    		),
            'project' => array (
                'name' => 'project',
                'vname' => 'LBL_PROJECT',
                'type' => 'dashletenum',    
                'source' => 'non-db',       
                'options' => '',                
                'options_sql' => 'select id as id, name as value from pm_project where deleted = 0',
                'remove_blank' => false,    
                'join_sql' => ' inner join pm_project_pm_product_c on pm_project_pm_product_c.pm_project_pm_product_idb = pm_product.id and pm_project_pm_product_c.deleted = 0
    							inner join pm_project on pm_project.id = pm_project_pm_product_c.pm_project_pm_project_ida and pm_project.deleted = 0 ',
                'table_alias' => 'pm_project',
                'db_column' => 'id',       
            ),
            'user' => array (
                'name' => 'user',       
                'vname' => 'LBL_LIST_ASSIGNED_USER',
                'type' => 'dashletenum',
                'source' => 'non-db',
                'options' => '',                
                'options_sql' => 'select id as id, user_name as value from users where deleted = 0',
                'remove_blank' => false,
                'join_sql' => '',
                'table_alias' => 'users',
                'db_column' => 'id',       
            ),
    ),
    	'relationships'=>array (
    ),
    	'optimistic_lock'=>true,
    );
    require_once('include/SugarObjects/VardefManager.php');
    
    /**
    * Sugar defines some stardard DTO classes that contains certain properties that can hold data.
    * Since all modules builder generated module inherit from these this is a fast shortcut rather than 
    * explicitly defining them all here. Unless for some reason you want to override any of the settings,
    * then you have to define it here as well.
    */
    VardefManager::createVardef('ProjectIssues','ProjectIssues', array('basic','assignable'));
    This is pretty much the code needed and most of it is copy paste from the different involved modules vardefs.php and most of the solumns can be generated directly using the ;B built in dashlet generator.

    Regards
    Kenneth Thorman
    Attached Images Attached Images     

Page 1 of 3 123 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Enhanced Search Plugin
    By kenshiro in forum Downloads
    Replies: 71
    Last Post: 2010-08-24, 02:45 PM
  2. Many to many search join in advanced search
    By kenneth.thorman in forum Developer Help
    Replies: 6
    Last Post: 2009-12-26, 10:34 PM
  3. Join another table in the index search
    By ukeller50 in forum Developer Help
    Replies: 0
    Last Post: 2008-10-15, 01:50 PM
  4. Replies: 2
    Last Post: 2008-08-23, 08:49 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •