Using PHP LinkedIn SDK to fetch Company and Profile Information via API

LinkedIn has an API that makes it possible to:

  1. Fetch Profile Information like name, email, and updates
  2. Fetch Company Information like name, email and updates
  3. Post to a Profile
  4. Post to a Company
  5. And more

There’s little written about a PHP implementation for the LinkedIn API. We’ll try to give the best articles and SDKs for PHP to kickstart your LinkedIn API implementation.

One important note: LinkedIn needs an access token that you’ll receive via OAuth2. It needs to be refreshed every 60 days. And this tutorial is (of course) on your own risk.

Create an app: Client ID and Secret

In order to start, you’ll need to create an app in LinkedIn Developers. You can do that here: https://www.linkedin.com/developers/apps . Make sure that you’re entering the redirect URL’s from where you’re starting the OAuth2 process, else the app won’t work.

Then you’ll receive a Client ID and Secret. Save those two.

Install the LinkedIn SDK

Install the LinkedIn SDK, we’re using this one: https://github.com/zoonman/linkedin-api-php-client. You can install it via Composer:

composer require zoonman/linkedin-api-php-client

After that, it’s installed. Then, you can use the example script here: https://github.com/zoonman/linkedin-api-php-client/blob/master/examples/index.php. You don’t need getenv, you can change these values to your client id and secret values:

$client = new Client(
    'YOUR_CLIENT_ID',
    'YOUR_CLIENT_SECRET'
);

The demo script also posts some things to your LinkedIn profile page + company page, so make sure to comment that out, so that it doesn’t happen. Then you can sign in and do your first OAuth request.

If everything works, you’ll get some profile + company info. Check your LinkedIn profile + company profile to make sure that nothing has been shared.

Saving the token

You can save the token somewhere (safely stored). And call it again. You can then modify the demo script that it initializes with the token:

// add Composer autoloader
include_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';

// import client class
use LinkedIn\Client;
use LinkedIn\Scope;
use LinkedIn\AccessToken;

// instantiate the Linkedin client

$client = new Client(
    'YOUR_CLIENT_ID',
    'YOUR_CLIENT_SECRET'
);

// load token from the file
$token = 'YOUR_TOKEN';
$expires = 'EXPIRY';
// instantiate access token object from stored data
$accessToken = new AccessToken($token, $expires);

// set token for client
$client->setAccessToken($accessToken);

if (!empty($token))
{
	// Do the client magic here!
}

You can put this information in a separate file as well and run it. Then you’re good to go!

Relevant resources

  1. https://medium.com/@ellesmuse/how-to-get-a-linkedin-access-token-a53f9b62f0ce
  2. https://www.linkedin.com/developers/
  3. https://github.com/zoonman/linkedin-api-php-client

Good luck. Got any tips? Leave a comment below.

Laravel 5: simple multi-tenant/multi-site model setup (many-to-many relation covered as well)

Laravel multi site multi tenant navigation bar illusatrationLaravel 5 is a brand new version of the popular framework. Unfortunately, there are no good multi-tenant setups for Laravel 5 yet. That’s why I’d decided to create my own simple version as well, based on Eloquent Global Scopes.

In my case I wanted a sites table, with categories that have a many to many relationship. So like:

sites
id | name

categories
id | name

site_category
id | site_id | category_id

So this table structure is a many to many relation. With this setup you can create a multi-site setup with different categories. Site A has categories 1 and 2, Site B has category 3 etc. It’s defined in the model as follows:

App\Site.php

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Site extends Model {

    protected $fillable = ['name', 'domain'];

    public function categories()
    {
        return $this->belongsToMany('App\Category', 'site_category');
    }
}

And the category like:

App\Category.php

<?php namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Traits\TenantableTrait;

class Category extends Model {
	use TenantableTrait;

	/**
	 * The fillables
	 * @var array
	 */
	protected $fillable = ['name', 'description'];

	/**
	 * A category has many sites
	 */
	public function sites()
    {
        return $this->belongsToMany('App\Site', 'site_category');
    }

Notice that this category has the trait TenantableTrait assigned. That is like:

App\Traits\TenantableTrait.php

<?php namespace App\Traits;

use App\TenantScope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;

trait TenantableTrait {

    /**
     * Boot the tenantable trait for the model
     *
     * @return void
     */
    public static function bootTenantableTrait()
    {
        static::addGlobalScope(new TenantScope);
    }

}

And finally, don’t forget the global Eloquent scope:

App\TenantScope.php

&lt;?php namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ScopeInterface;
use Session;

class TenantScope implements ScopeInterface
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        if (Session::has('siteId'))
        {
            $siteId = session('siteId');
          
            $builder->whereHas('sites', function($query) use($siteId)
            {
                $query->where('sites.id', $siteId);
            });
        }
    }

    /**
     * Remove the scope from the given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function remove(Builder $builder, Model $model)
    {
        
        dd('remove called');
    }
}

Now, if you set the site id by session (e.g.) in a controller with:

Session::set('siteId', 1)

A all categories that have a site_category link with site_id=1 will be called. As you see, the remove method still has to be specified, so if you’d like to finish up this script, leave it in the comments.

You can repeat this with site_products or probably even site_category_product (with some finetuning, if that works, let me know below 🙂 ).

Magento A/B testing or Multivariate testing – Php script

Split test A/B PHP Script

Magento is quite limited in tools like conversion optimalisation like A/B testing or multivariate testing. That is why I created a very simple php script that you can put directly into a phtml file. It’s a bit hacky, that it’s not via the core, but it works though and is fast. This script has its limitation, see the note on the bottom.

If you want to variate the text of a button on the product page and go to a file like /app/design/frontend/default/default/catalog/product/view.phtml and insert this into the header (in the php-code):

srand((double)microtime()*1000000);

$var = array();
$var[1]['name'] = 'direct';
$var[1]['value'] = 'Buy direct';
$var[2]['name'] = 'purchase';
$var[2]['value'] = 'Purchase product';
$var[3]['name'] = 'invest';
$var[3]['value'] = 'Invest in product';

$choice = cookieCheck($var);

function cookieCheck($var)
{
	$cookie = Mage::getSingleton('core/cookie');
	$cookievalue = $cookie->get('variation_test');
	if (isset($cookievalue) && ($cookievalue > 0))
	{
		$choice = $cookievalue;
	}
	else
	{
		$choice = rand(1,count($var));
		$cookie->set('variation_test', $choice ,time()+30*86400,'/');
	}
	return $choice;
}

Then create a piece of text like a link or a button. That is where the variation takes place:

<a class="varbutton" href="&lt;? echo $this-&gt;getUrl('bedankt'); ?&gt;">&lt;? echo $var[$choice]['value']; ?&gt;</a>

If you want to track the variable in Google Analytics, you can edit the template file /app/design/frontend/default/default/googleanalytics/ga.phtml , so it gets like:

 srand((double)microtime()*1000000);

$var = array();
$var[1]['name'] = 'direct';
$var[1]['value'] = 'Buy direct';
$var[2]['name'] = 'purchase';
$var[2]['value'] = 'Purchase product';
$var[3]['name'] = 'invest';
$var[3]['value'] = 'Invest in product';

$choice = cookieCheck();

function cookieCheck()
{
	$cookie = Mage::getSingleton('core/cookie');
	$cookievalue = $cookie->get('variation_test');
	if (isset($cookievalue) && ($cookievalue > 0))
	{
		$choice = $cookievalue;
	}
	else
	{
		$choice = rand(1,count($var));
		$cookie->set('variation_test', $choice ,time()+30*86400,'/');
	}
	return $choice;
}
 
 
?>
<?php if (!Mage::helper('core/cookie')->isUserNotAllowSaveCookie()): ?>
<?php $accountId = Mage::getStoreConfig(Mage_GoogleAnalytics_Helper_Data::XML_PATH_ACCOUNT) ?>
<!-- BEGIN GOOGLE ANALYTICS CODEs -->
<script type="text/javascript">
//<![CDATA[
    var _gaq = _gaq || [];
    _gaq.push(["_setCustomVar", 1, "variation_test", "<?php echo $choice; ?>"]);
    <?php echo $this->_getPageTrackingCode($accountId) ?>
    <?php echo $this->_getOrdersTrackingCode() ?>

    (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();

//]]>
</script>
<!-- END GOOGLE ANALYTICS CODE -->
<?php endif; ?>

Note: This script could not work properly if you’re using Full Page Cache. Also it could not work with the page block html cache. So, work in progress …

jQuery Address and History Forms – Remembering form choices in hash / browserstate (updated version)

For jQuery hash support I like the jQuery Address plugin: http://www.asual.com/jquery/address/ . Especially, if you want to make a form or product filter, you can use this variant: http://www.asual.com/jquery/address/samples/form/ .

Though, it doesn’t support checkboxes in the form of arrays like check[]=1&check[]=2 , etc. I updated the plugin with some other libraries and code and now it works.

You can download it here.