One Way To Index ElasticSearch In Sugar 7

Edit (8/20/14): As Cédric Mourizard mentioned in the comments, if you have access to CLI you can simply run the following command to trigger an indexing of ElasticSearch. The method explained in this article is geared toward triggering an indexing via the API in scenarios where you may not have access to the CLI.

$ php silentFTSIndex.php

Like many, I’m comfortable with the ETL tools that I have been using in Sugar for years now. While many ETL tools support Sugar’s SOAP API (and a couple support the new REST API), I often prefer working directly with the database as it’s a much quicker way to move large amounts of data due to bypassing business logic such as workflow rules and logic hooks.

Things changed in 7. With ElasticSearch now being a requirement of Sugar, doing database work can have some undesired effects in regards to search and activity stream functionality. They simply do not work if data has been imported directly to the database.

One way I have found to update ElasticSearch after doing an import directly to the database is to interact with the bean within Sugar or using the API.

I think it’s safe to assume that our goal as Sugar developers is to automate tedious tasks so that users (and us developers) can work more efficiently. Indexing ElasticSearch is certainly one of those tasks.

That said, I find writing a script using the Sugar 7 Rest Client to be a quick and easy way to index ElasticSearch after performing Sugar 7 database work.

Here is a quick example of using the Sugar 7 Rest Client to do just that.

Have a better idea? Please let me know in the comments below!

Sugar 7 API Wrapper Class Updates

Previously, the wrapper class was… well… just that, a class. Working with custom endpoints was awkward and felt hacky. The more I dived in to Sugar 7 customization the more I realized I needed something more flexible and future proof.

That something is, at the time of this writing, the latest push to github.

Now the wrapper class is now a facade to a more powerful rest client. The reason for going this route was to keep the class intuitive but also allow a developer more flexibility. Prior to this latest push to github, in order to support a new endpoint a new method in the wrapper class had to be coded. Now, with a simplified rest client and improved facade you can easily work with custom endpoints and endpoints that have not been defined in the wrapper class.

Does this mean new features? Of course!

There have been 4 new methods added to the wrapper class. Those 4 methods allow you to interact with any endpoint that is not covered by the wrapper class. This includes both custom and stock endpoints.

Examples of these endpoints are:

<?php
$sugar = new \Spinegar\Sugar7Wrapper\Rest();

$sugar->setUrl('https://sugar/rest/v10/')
    ->setUsername('restUser')
    ->setPassword('password')
    ->connect();
    
/* Get Endpoint*/
$arguments = array();
$result = $sugar->getEndpoint('MyCompany/MyAddon/MyGetEndpoint', $arguments);

/* Post Endpoint*/
$arguments = array();
$result = $sugar->postEndpoint('MyCompany/MyAddon/MyPostEndpoint', $arguments);

/* Put Endpoint*/
$arguments = array();
$result = $sugar->putEndpoint('MyCompany/MyAddon/MyPutEndpoint', $arguments);

/* Delete Endpoint*/
$arguments = array();
$result = $sugar->deleteEndpoint('MyCompany/MyAddon/MyCustomDeleteEndpoint', $arguments);

Nifty, right? Enjoy!

Install Elasticsearch On CentOS 6.5

Introduction

While setting up a new instance of SugarCRM 7.1 I reached a point in which Elasticsearch is required to continue. This is a very welcomed surprise! For those of you not familiar with full text search in SugarCRM, it offers the following benefits.

  • Full text search on keywords or partial words
  • Quick View previews search results with the search string highlighted
  • Prioritized results are shown first for the module from which the search is performed, followed by results from other modules
  • Wildcard searches
  • Include a field name in searches to filter results by matches to that field only
  • Show All link displays the full search results from each module in separate panels

Installation

While Googling I noticed a common theme of making installation way more difficult than it needed to be. Many tutorials have you install Elasticsearch, install a service wrapper, move files and directories here and there, etc. Overkill.

Installing it is pretty simple using the provided RPM from the Elasticsearch website.

cd ~
sudo yum update
sudo yum install java-1.7.0-openjdk -y

wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.10.noarch.rpm

rpm -Uvh elasticsearch-0.90.10.noarch.rpm 

chkconfig elasticsearch on

If you are installing for SugarCRM (which is a majority of the traffic generated to this post), I recommend adding the following to the configuration file located at /etc/elasticsearch/elasticsearch.yml

Testing

Testing to make sure it works is pretty straight forward. Using curl we will make sure the service is running on the standard port of 9200.

curl http://localhost:9200

The results returned should resemble something along the following lines.

{
  "ok" : true,
  "status" : 200,
  "name" : "Vagabond",
  "version" : {
    "number" : "0.90.8",
    "build_hash" : "909b037218cf880e8772b066a764f179f2d5e719",
    "build_timestamp" : "2013-12-18T16:08:16Z",
    "build_snapshot" : false,
    "lucene_version" : "4.6"
  },
  "tagline" : "You Know, for Search"
}

Full Text Search Examples

See the following links for more information on how to use Elasticsearch as a whole and some more specific SugarCRM examples.

http://joelabrahamsson.com/elasticsearch-101/

http://developer.sugarcrm.com/2012/07/06/full-text-search-tricks/

Optimize All Tables In a MySQL Database

In a previous post I covered converting all of your MySQL MyISAM tables to InnoDB. Lets take that a step further and optimize all of the tables in the DB.

First, create a query to generate all of the needed SQL statements to optimize each table in the DB.

The output generates an optimization query for each table.

Copy and paste these results and run the queries. After some time all of the tables in the DB will be optimized.

 

Convert All MyISAM Tables To InnoDB

Today I took on the task of converting our SugarCRM MySQL MyISAM tables to InnoDB. Currently we have roughly 200 tables in the SugarCRM DB. Its a time consuming processes to convert each table one at a time. Luckily, using some SQL scripting you can make this much less painful.

Start by running the following query to build a list of SQL statements that will handle converting each table.

The output generates a query for each table to be converted to InnoDB.

Copy and paste these results and run the queries. After some time (in my case about 20 minutes) all of the tables in the DB will be converted to InnoDB.

Sending Emails Using Push Queues With Confide

Using push queues to send emails offers significant benefits to your application. It boosts application performance which in turn improves the user experience which in one way or another generally leads to a more successful application.

Confide, being built specifically for Laravel 4, has its own mail method that handles translation among other things. This mail method is used for common user account emails such as account confirmation, password resets, etc. With that in mind, to use push queues with with Confide you will need to override the sendEmail() method.

To override the Confide sendEmail() method open up User.php that you created (or edited) when installing Confide and add the following code.

After saving this file, your application will now use a push queue to send user account emails.

Securing Laravel Push Queues

Push queues are the all the hype at the moment. However, I have not seen much discussion around securing them. Thats likely do the the simplicity of securing the receiving route, but either way…lets cover it.

There are two basic ways to secure the receiving route.

  • SSL – Use a security certificate to secure the connection.
  • Token and Route Filter – Build a route filter that requires a valid token.

Route Filter & Route Example

Configure the subscriber URL on iron.io to look something like the following. In this example the URL query string is set to the value of the iron.io token in app/config/queue.php.

Role Specific Drop Downs in SugarCRM

Today I ran in to a scenario where I needed the status field for projects to hide a value for everyone except two specific roles. I did some googling and found a post which seemed to theoretically accomplish what I was looking for. However, in practice it didn’t. That said, I won’t be covering what didn’t work as nobody really cares.

Now down to business. The first thing we need to do is edit the vardefs of the drop down to use a custom function that will handle the logic of determining if the specified value is available for selection.

Next, create the file and function to handle the logic.

Finally, run Quick Repair and Rebuild. The drop down is now hiding the “Pending Input” option for everyone except users in the Developer and Marketing roles.

A Small But Troubling Trend With Laravel Packages

Edit: I have updated the “Correct Service Provider” with code provided by William Cahill-Manley in his comments. Thanks for the contribution William!

Watching Laravel 4 grow has been spectacular. Its great to see so many libraries building service providers and facades for Laravel to make them feel more native to the framework. That said, I have noticed small but troubling trend with some packages available for Laravel.

The Problem

The problem lies in how configuration is handled for the package. Configuration should not be done within the service provider. This concept is not unique to Laravel. However, for this post I will be discussing Laravel packages specifically. Below is simple example of one such package.

At a glance, this file doesn’t appear to require configuration. If you look deeper (or refer to the documentation) you will find the developer can change the geocoding provider and adapter used for geocoding services. The ability to pick which geocoding provider and adapter to use is tremendous in allowing developers to build applications to do exactly what they want. The problem lies in the implementation of such configuration.

As you can see above, to use a different geocoding provider and/or adapter the developer must adjust the service provider to instantiate an alternate geocoding provider and/or adapter. Let’s say the package receives an update and the developer pulls down that update via composer. What happens to the “configuration”? It gets wiped out. Now the application is broken and the developer must update the service provider again. Wash. Rinse. Repeat.

The Solution

To solve this issue the package should (and now does) implement a publishable configuration file. The configuration file allows the developer to specify which geocoding provider and adapter to use for geocoding services.

So what do the new service provider and configuration look like? Take a look.

<?php
 
return array(
    'provider' => 'Geocoder\Provider\FreeGeoIpProvider',
    'adapter' => 'Geocoder\HttpAdapter\CurlHttpAdapter'
);
<?php

/**
 * This file is part of the GeocoderLaravel library.
 *
 * (c) Antoine Corcy <contact@sbin.dk>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Toin0u\Geocoder;

use Geocoder\Geocoder;
use Illuminate\Support\ServiceProvider;

/**
 * Geocoder service provider
 *
 * @author Antoine Corcy <contact@sbin.dk>
 */
class GeocoderServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;

    /**
     * Bootstrap the application events.
     *
     * @return void
     */
    public function boot()
    {
        $this->package('toin0u/geocoder-laravel');
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->registerAdapter();
        $this->registerProvider();
        $this->registerGeocoder();        
    }

    public function registerAdapter() {
        $this->app->singleton( 'geocoder.adapter',
            $this->app['config']->get('geocoder-laravel::adapter', 'Geocoder\HttpAdapter\CurlHttpAdapter')
        );
    }
    public function registerProvider() {
         $this->app->singleton( 'geocoder.provider',
            $this->app['config']->get('geocoder-laravel::provider', 'Geocoder\Provider\FreeGeoIpProvider')
        );
    }
    public function registerGeocoder() {
        $this->app['geocoder'] = $this->app->share(function($app) {
            $geocoder = new Geocoder;
            $geocoder->registerProvider($app['geocoder.provider']);

            return $geocoder;
        });
    }

    
    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return array('geocoder', 'geocoder.adapter', 'geocoder.provider');
    }
}

Now you may ask, “How do you configure this package?”

Simple. Run the following command after installing the package via composer.

$ php artisan config:publish toin0u/geocoder-laravel

After the configuration has been published the developer can edit it to use the geocoding provider and adapter of their choice. The published configuration file will allow the developer to update via composer without worrying about breaking their application (from a configuration stand point at least).

Summary

Configurable packages are a great thing. That said, let’s wear our “best practice hats” and make sure we keep the configuration out of Composers reach.

Introduction to the Sugar 7 API Wrapper Class

In a previous post I showed you how to use Guzzle to interact with the new SugarCRM v10 API. Today, I would like to introduce you to an even easier way to utilize the new API, the SugarCRM REST API Wrapper Class.

Installation and Instantiation

Installation of this package is handled with Composer. Start by updating composer.json with the following information.

Next, install the package via Composer.

With the SugarCRM REST API Wrapper installed and auto loaded, we can now instantiate the class and authenticate against our SugarCRM instance.

 

Common Usage Examples

1. Searching for an account by Name.

2. Alternatively, we can retrieve an account by ID.

3. Retrieving a list of cases associated to an account.

4. Create a case and relate the case to an account.

5. Listing notes associated to a case.

6. Listing documents associated to the account. (Compare to using Guzzle without the wrapper class)

 

Summary

There you have it. Using this new wrapper class is very simple and involves much less code than using cURL or even Guzzle to interact with the new API. That said, the wrapper class requires Guzzle and will install it via composer for you.

Are there any other examples you would like to see? If so, please comment and I’ll update this post accordingly.