Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Monday, January 26, 2015

7 CRM Options Compatible with Drupal

1 comment
I love Drupal and end up undertaking most of my programming projects with it. I have been using it for so long that I find it far easier to push out projects with Drupal than with anything else, despite it’s infamous learning curve.
Whether you want to call Drupal a CMS (Content Management System), a CMF (Content Management Framework) or a CMSomething, the ‘C’ always stands for Content. Content is where Drupal shines and is what it’s designed for.
drupal8wide
When an organisation is at a stage and mindset that they also want to manage their contacts and interactions effectively they will often need tools designed specifically for that function. These are generally referred to as a CRM, which stands for Client Relationship Manager or Constituent Relationship Manager, depending on the sector (For-Profit or Not-for-Profit respectively). CRMs are big business, with many free and paid options available, all with their own advantages and disadvantages.
Often these interactions that people have with your organisation will include things such as registering for an event, making a donation, becoming a member, expressing interest in a product or receiving a newsletter. This all sounds quite simple, but often representing a business rule in the digital realm is very difficult as everyone thinks ‘their way’ is ‘the only way’ and that surely every off-the-shelf system should represent them out of the box.
What has a CRM got to do with Drupal? Nothing directly, but indirectly if you’re looking to streamline your business operations and automate the ways people can interact with you, your CRM will need to work well with your website.
If you are reading this, I will assume your website is likely built in Drupal and, unsurprisingly, Drupal continues its talents of playing well with others into the domain of CRMs.
In this article, we will look at several of the big players in the CRM space that work well with Drupal, how they integrate or how developers can get them to integrate.

Roll it yourself

Whilst I mentioned above that Drupal is aimed at Content, Drupal has always excelled at relationships between content, or in newer parlance, ‘Entity References’. Theoretically you could create content types for contacts (or the User entity) and content types for the interactions they may have with you alongside other modules such as Event and Commerce. Then create a bunch of Views and you effectively have a ‘CRM’. In some simpler cases this may be enough and you have complete control of the processes you want to represent. This could end up consuming a lot of Developer time and using a tool designed specifically for the job may be a better solution.

RedHen

The team at ThinkShout effectively followed the advice above and created a collection of modules that will provide you with a lot of Drupal-Native CRM functionality. It takes the Drupal Commerce approach and instead of providing you functionality our of the box, rather provides you with a toolkit for creating that functionality. This does mean you may still need to undertake a lot of extra work yourself but you are adding no new systems into your technology stack and the problems that can entail. The other downside of RedHen is that it isn’t updated that regularly (in comparison with other options on this list), its release cycle is based more upon when ThinkShout have client requirements or run a code sprint.
If you want to customize RedHen then you can create your own sets of modules and theme overrides, it’s Drupal!

CiviCRM

Often when searching for CRM options for Drupal, people come across CiviCRM and it initially appears as a Drupal module. I have undertaken a lot of work with CiviCRM (and contribute to the project) and the fact that it masquerades as a Drupal module is often a massive point of confusion. It’s best thought of what it actually is, an external service that happens to integrate quite well with Drupal and almost look like it’s a part of it. CiviCRM is a custom PHP application that also integrates with Joomla! and WordPress and is primarily aimed at not-for-profits but can be customized to work with commercial organisations. Out of the box CiviCRM comes with a LOT of features and is thus quite a weighty program, as an open-source project it can sometimes be a bit rough around the edges and inconsistent, but development has increased and matured a lot in the past year.
CiviCRM integrates directly with Drupal in many places, some better than others, and these include:
  • A direct (optional) relationship between a Drupal user and a contact record as well as synchronization between Drupal roles and CiviCRM groups and memberships.
  • Views for constructing listings of CiviCRM entities.
  • Rules and triggers
  • Webform for replacing CiviCRM’s inbuilt forms.
  • Commerce and Ubercart
  • Organic Groups
  • Theming (sort of). You can use the Drupal theme to override CiviCRM CSS but CiviCRM does use its own templating engine (currently smarty but likely switching to twig).
  • Another option is to set aside the Drupal/CiviCRM modules and utilise CiviCRM in a ‘headless’ approach, utilizing it’s API and REST interfaces.
CiviCRM offers a plethora of its own inbuilt customization options that I won’t go into, which, being PHP, will be reasonably familiar to many of you. You can also utilize direct CiviCRM to Drupal customization through creating your own Drupal module. In the module you can access CiviCRM hooks and API functions which offers an endless level of options to suit a plethora of client needs.

Salesforce

Salesforce is the main player for commercial sales focused companies and is reasonably entrenched in many business workflows. It is a large application with its own long established ecosystem and extension marketplace. It is expensive, proprietary and written in its own programming language, ‘Apex’. Development moves fast and it is a reasonably stable system.
Salesforce is a cloud based CRM, so integration happens via a REST interface. Fortunately as Salesforce is so popular in the types of environments that Drupal is also popular, there are a few prebuilt options. Bear in mind that your license may limit the options available to you:
  • The SalesForce Suite is a module with a long history and it starts you on your integration journey. It will handle authentication, mapping Drupal entities to SalesForce fields, pushing and pulling data between Drupal and SalesForce and a legacy module to connect with SalesForce’s older SOAP API.
  • There is some basic Webform integration via a module with seemingly stalled development.
  • Springboard is a commercial Drupal distribution from Jackson River that bundles Drupal and SalesForce together into an offering specifically for not-for-profits. It’s a little unclear what it offers above just doing integration yourself, but it includes support. There are also a couple of other agencies that offer Drupal / SalesForce integration services.
Theoretically, once you have SalesForce entries represented as Drupal entities you can utilize the plethora of customization options that Drupal offers such as views, rules and module hooks. If you want to enhance SalesForce functionality then it could potentially be accomplished through Drupal and pushed to SalesForce, but chances are you will need to learn SalesForce itself at some point.

Sugar CRM

Sugar is another long established player and comes in community (open source PHP) and commercial editions. It is aimed at commercial sales focused organisations and much like SalesForce, development moves quickly and Sugar CRM also has its own marketplace for extensions.
OSSCube created a Drupal module and accompanying SugarCRM project to allow for some direct integration. I haven’t personally used them and find the documentation somewhat hard to understand. However, it claims to offer:
  • Field mapping between Drupal and Sugar entities
  • Data syncing between the two systems
  • Webform integration to create Sugar entities
Again, you also have the option of utilizing Sugar’s SOAP and REST APIs to create Drupal entities and continue from there. Sugar also offers LDAP, so there is the potential to create a single sign on between the two systems.

Other Options

I have grouped together several other options here. All the CRMs vary wildly, but their integration options are mostly the same so I didn’t want to just repeat those options over and over again. I have attempted to undertake Drupal integration work with some of them in the past and often struggled to accomplish anything. A lot of this is due to the proprietary nature of these systems, finding information on their API and developer options is a challenging endeavor unless you pay some money.

Microsoft Dynamics and BlackBaud

It is worth including Dynamics and Blackbaud as they are big players in the CRM space. Both offer their own options for a CMS (and other systems), so are often reluctant to offer integration options outside of their ecosystem.

Nation Builder and Salsa

These are both CRMs of a sort that are aimed more at the newer wave of engagement focused organisations. They are not just about tracking contributions and interactions, but also encouraging interactions.
Salsa has some integration modules for Drupal 6, so if you’re feeling generous you may want to update them. Otherwise it’s a process of communicating via the Salsa API and fortunately there is a Drupal module under development to get you started.
NationBuilder have gone out of their way to not create any direct CMS integrations, citing that their inbuilt CMS is a far better option instead. However, they do have an API that can be used with the options noted below.

How to integrate with Drupal?

Here are some potential options, but your mileage may vary:
  • Utilize the CRM’s API (if it exists in your version / license) to pull entities into Drupal and then proceed in a similar vein to the SalesForce options via Services or a custom module.
  • Using the Migrate module and optionally the MSSQL Server PHP extension for any .NET based systems to directly query the CRM database and import into Drupal entities. Again, your license and setup may or may not allow this.
  • There is a Sandbox module for Dynamics integration, last time I tried, it didn’t work anymore, but you may feel like updating it.

Conclusion

This is by no means a comprehensive list of CRMs or the possible options to integrate them with Drupal. I have mainly focused on the ones I have experience with and can’t possibly keep up with all the new options that are constantly emerging. I also have far more experience working with not-for-profits, so my solutions are somewhat skewed to that sector. What are some of the systems you have tried to connect with Drupal? Did you succeed? Have you had to overcome any hurdles? Let us know!
Read More

An Introduction to Asset Handling in WordPress

Leave a Comment
As a WordPress theme or plugin developer, there will come a time during your development process that you will need to include third party scripts or stylesheets in your plugin or theme. Sure, simply linking the assets in the header or footer would definitely work, but adhering to standard practice using the provided WordPress API will ensure that your theme or plugin will play nice with other plugins in the WordPress ecosystem.
If you want to provide maximum compatibility with other plugins and themes available, asset handling in WordPress is definitely a skill you should master.
This article is targeted to the beginner WordPress developer, with the assumption that you have a working knowledge of how WordPress action and filter hooks work.
WordPress Asset Handling

The Basics

WordPress has provided a few basic functions to help the developer correctly load custom assets of their theme or plugin. The four main functions that you will use frequently are wp_register_script,wp_enqueue_scriptwp_register_style and wp_enqueue_style.
Let’s go through these four major functions one by one.

wp_register_script( $handle, $src, $deps, $ver, $in_footer );

I’m just going to go ahead and paste the description provided in the codex for this function.
Registers a script file in WordPress to be linked to a page later, which safely handles the script dependencies.
Only $handle and $src arguments are required, while the latter three is optional.
$handle is the name of the script and should be unique. This is the most important part when enqueuing your script as the $handle will be the identifier of which script is to be loaded.
$src is the URL to the script. You can get the proper URL using provided built in functions such asplugin_url()get_template_directory_uri() and get_stylesheet_uri(). For a remote URL, protocol-agnostic URL such as //ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js can be used.
$deps should be an array of scripts’ handle of which your script depends on. By defining them here, WordPress will load those dependencies first before loading your custom scripts.
$ver is simply your script’s version, and it will be appended as a query string in your src parameter ofscript tag.
$in_footer is a Boolean flag that will tell WordPress whether to load your script in head section of document, or in the footer instead. Make sure that the theme properly includes wp_head() andwp_footer() correctly for this to work.

wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );

This function is similar to wp_register_script with the exception that only $handle parameter is required. If you have already registered your scripts prior to execution using wp_register_script, you can directly enqueue them using wp_enqueue_script('your-registered-handle').
This is the actual function that will link your script to the generated page, so this function needs to be used in conjunction to wp_register_script.

wp_register_style( $handle, $src, $deps, $ver, $media );

This is the counterpart function for wp_register_script, only that this function will handle all your stylesheet registration. Let’s go through each of the arguments for this function.
$handle is the unique identifier to your stylesheet, similar to the one for your wp_register_script andwp_enqueue_script. This is a required parameter and your handle should be unique to your WordPress installation.
$src will be the URL to your CSS file. Again, you can either link it to the local file in your theme or plugin, and it also works with a remote URL.
$deps will handle all your CSS’s dependency, which should be defined as an array of the styles handles.
$ver is optional parameter where you can define your CSS version, and it will be appended to the URL as the query string as well.
$media is the CSS media types of your CSS. The complete list of acceptable value can be found on this page.

wp_enqueue_style( $handle, $src, $deps, $ver, $media );

This function will link your CSS to the generated page, similar to how wp_enqueue_script works. So basically, you can either enqueue your previously registered CSS, or you can enqueue the CSS on the go by defining the $src parameter as well.

When Do We Enqueue Them?

There are three proper hooks recommended to enqueue your scripts and stylesheets.
Use wp_enqueue_scripts action hook whenever you want to enqueue your script to the front end of your site. Don’t be confused with the name, as the same hook can be used to enqueue your style as well.
How about the admin page? Well, you can hook your enqueue function on the admin_enqueue_scripts and all your scripts and styles will be loaded on the administrative side of things correctly. To load your scripts and styles specifically on the login page, login_enqueue_scripts action hook is provided.

Enqueue Versus Register

At a glance, it seems redundant to register your scripts and stylesheets first, before enqueuing them. So why do we need to use wp_register_script and wp_register_style in the first place, when in reality we can directly just use wp_enqueue_script and wp_enqueue_style instead? Well, technically, you don’t need to.
But if you want to dynamically load your scripts and stylesheets based on various conditions, you better register them first so you can enqueue them anytime you want at any point of execution without repeating yourself.
Let’s look at this simple example:
wp_register_script( 'my-custom-js', ... );
 wp_register_script( 'my-second-js', ... );

 if ( is_page( 32 ) ) {
  wp_enqueue_script('my-custom-js');
 }

 if ( $var ) {
  wp_enqueue_script('my-second-js');
 }
Based on this snippet, you can see that we first register two custom scripts, my-custom-js and my-second-js. Based on several conditions, in this case, when the page loaded is of ID 32, or $var is set to true, we can dynamically enqueue them.
Registering them first is also useful whenever you want to rely on the same script on a different part of the website. As pointed out earlier, there are two different hooks that need to be used in order to load your scripts and stylesheets on front end facing side and administrative side. So by registering them first, you would just need to register them once, and enqueue them in both related hooks.

What’s Already Included?

Many developers resort to including a third party library of their own, which then leads to big plugin or theme sizes and the potential for incompatibilities. WordPress includes some useful JavaScript libraries of its own, so why not utilize that instead?
An exhaustive list of what’s already included with its respective handle is listed on this page under Handles and Their Script Paths Registered by WordPress section. This list may get outdated, so if you want to peek directly at the source, take a look at wp-includes/script-loader.php source code, specifically inside thewp_default_scripts function.
You can find a lot of useful libraries that can be reused without the need of shipping it inclusively with your plugin or theme.

Additional Functionalities

Besides the four main functions to register and enqueue your scripts and styles, WordPress also provides a handful of functions that can help with regards to managing your plugin or theme assets. Let’s take a look at some of them.

Making Your PHP Variables Available on the Client Side with wp_localize_script

Although this function is primarily used to provide proper localized translation of strings (thus the name) to your client side code, it can be used virtually to make any data that you have on the server side available on the client side as well.
wp_localize_script( $handle, $name, $data );
As the above code suggests, this function will accept three required parameters. $handle refers to the handle of the script you are attaching the data for. It is important to note that the script must be either registered or enqueued first to make sure wp_localize_script works correctly.
$name is the variable name that will be available on the client side, and will contain all your specified$data that you defined in an array.
Here’s a simple snippet to explain what this function does:
wp_register_script( 'my-custom-js', ... );

 $args = array(
    'foo' => 'bar'
   );

 wp_localize_script( 'my-custom-js', 'my_var', $args );
 wp_enqueue_script( 'my-custom-js' );
When the my-custom-js is enqueued, WordPress will handle the given data to make it available on the client side code. Since the $args will be JSON-encoded and assigned to the variable called my_var, you can always access the value back in your script like you normally do on any JavaScript object.
<script>
 console.log( my_var.foo ); // print out "bar" in console
</script>

Enqueuing All Related Scripts for WordPress Media Library with wp_enqueue_media

If you want to use the native WordPress media uploader in your plugin or theme, you will need to enqueue all the related assets required before you can access all the available related APIs. To make things easier, WordPress provides a helper function that will help you enqueue all the related scripts, styles and templates related to the Media API.
wp_enqueue_media( $args );
The only parameter is $args, which is optional, and can be used if you want to enqueue all related assets associated with a specific post. I won’t delve too much into how to use the available API to implement the native media uploader in your plugin or theme since it deserves an article on its own, but here’s a little snippet to get you started.
wp_enqueue_media();       // basic usage, enqueue all related scripts, styles and templates
wp_enqueue_media( array( 'post' => 32 ) );  // enqueue all related assets for post with ID of 32

Adding Metadata to Stylesheet with wp_style_add_data

This function works only for the stylesheet, and is particularly useful when you want to add metadata such as conditional comments, RTL support and an alternate title to your custom stylesheet.
wp_style_add_data( $handle, $key, $value );
All three parameters are required. Let’s go through each of them to see what they represent.
$handle is the specific stylesheet handle that we want to add our metadata to.
$key is the data point. There are five accepted values which are conditionalrtlsuffixaltand title
$value is the data string in conjunction to the previously specified $key.
Here’s a example snippet on how we can take advantage of this function to load our stylesheet specific to Internet Explorer only.
wp_enqueue_style( 'custom-ie-style', get_template_directory_uri() . '/css/ie.css' );
wp_style_add_data( 'custom-ie-style', 'conditional', 'IE' );
That’s it! Once your stylesheet is linked to the generated page, this is what is actually printed on the headpart of the document.
<!--[if IE]>
  <link rel="stylesheet" id="custom-ie-style-css" href="http://www.example.com/wp-content/themes/example/css/ie.css" type="text/css" media="all">
<![endif]-->

Automatically Cache Busting Using filemtime

This is not actually WordPress specific, but I kept finding myself using this code time and again in my client projects. What it actually does is take advantage of the version argument in the wp_enqueue_script and related functions as a cache busting method by checking the file last modified time. Obviously, this only works for the local file, since we are using filemtime PHP function to detect the last modified timestamp of that file.
Here’s how we define the version argument, in example of wp_enqueue_script function:
wp_enqueue_script( 'my-custom-js', get_template_directory_uri() . '/js/custom.js', array(), get_template_directory() . 'js/custom.js' );
Note that filemtime requires the path of your file, not the URL, thus in above snippet, we are usingget_template_directory function instead to get the path to our theme directory.
From now onwards, any modifications to the file will result in different version value, and our query string will get updated accordingly.

Conclusion

As a responsible WordPress developer, it’s vital that you to apply best practices to your development process, and that includes learning how to properly load assets in your custom plugin or theme. This will ensure your plugin or theme is compatible with other plugins or themes, as well as reducing conflicts and bugs as WordPress evolves.
Read More

Thursday, January 22, 2015

Starting a New PHP Package The Right Way

Leave a Comment
Back when we covered Diffbot, the visual AI-enhanced machine-learning crawler, we also mentioned they have libraries for a wide array of programming languages, but those are often less than cutting edge – with so many to keep an eye on, there’s bound to be a few bad apples that slip through the cracks. One such apple is their PHP library, and we’ll be building an alternative in this series, in an effort to do it better.
Note that this tutorial will focus on writing a good package – the code we write will be real and production-ready, but you shouldn’t focus too much on Diffbot itself. Diffbot’s API is simple enough and Guzzle’s interface is smooth enough to just consume it outright without the need for a PHP library anyway. Rather, pay attention to the approaches we use to develop a high quality PHP package, so you can reuse them in your own project. Diffbot was selected as the subject of the package because I’d like to demonstrate best practices on a real world example, rather than yet another “Acme” package.

Good Package Design

In recent years, good standards for PHP package design have popped up, in no small part due to Composer,PackagistThe League and, most recently, The Checklist. Putting all these in a practical list we can follow here, but avoiding any tight coupling with The League (since our package won’t be submitted there – it’s specifically made for a third party API provider and as such very limited in context), the rules we’ll follow are:
  1. include a license
  2. be open source (well, duh!)
  3. exclude development stuff from dist
  4. use PSR-4 autoloading
  5. be hosted on Packagist for Composer installation
  6. be framework agnostic
  7. use PSR-2 coding standard
  8. have in depth code comments
  9. use semantic versioning
  10. use CI and Unit Tests
For a more detailed reading of these and more rules, see here.

Getting Started

Naturally, we’ll be using our trusty Homestead Improved box again, as it’s the quickest way to get started developing on a unified environment. For your reference, I chose the following vhosts, and will be using them throughout the rest of this tutorial:
1
2
3
4
5
sites:
    - map: test.app
      to: /home/vagrant/Code/diffbot_lib
    - map: test2.app
      to: /home/vagrant/Code/diffbot_test
OK, after getting into the VM, let’s start hacking away.
To hit the ground running, we’ll use the League Skeleton, which is a template package with League rules embedded, allowing for a head start. I’ve made my own fork with a better .gitignore and some minor tweaks if you’d like to use that – if not, just use theirs, the difference is truly trivial.
1
git clone https://github.com/Swader/php_package_skeleton diffbot_lib
We edit the composer.json file and end up with something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
    "name": "swader/diffbot_client",
    "description": "A PHP wrapper for using Diffbot's API",
    "keywords": [
        "diffbot", "api", "wrapper", "client"
    ],
    "license": "MIT",
    "authors": [
        {
            "name": "Bruno Skvorc",
            "email": "bruno@skvorc.me",
            "homepage": "http://bitfalls.com",
            "role": "Developer"
        }
    ],
    "require": {
        "php" : ">=5.5.0"
    },
    "require-dev": {
        "phpunit/phpunit" : "4.*"
    },
    "autoload": {
        "psr-4": {
            "Swader\\Diffbot\\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Swader\\Diffbot\\Test\\": "tests"
        }
    },
    "extra": {
        "branch-alias": {
            "dev-master": "1.0-dev"
        }
    }
}
We set some common meta data, define the requirements, and set up PSR-4 autoloading. This, along with the fact that we’re using the League Skeleton, takes care of points 1-6 on our to-do list from above. While we’re here, we can also add Guzzle to our requirements, as it’s the HTTP client library we’ll be using to make all calls to Diffbot API points.
1
2
3
4
"require": {
    "php" : ">=5.5.0",
    "guzzlehttp/guzzle": "~5.0"
},
After running composer install, which will pull in all the dependencies, including PHPUnit we’ll need for testing, we can check if everything is working by changing the contents of src/SkeletonClass.php to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
namespace Swader\Diffbot;
class SkeletonClass
{
    /**
     * Create a new Skeleton Instance
     */
    public function __construct()
    {
    }
    /**
     * Friendly welcome
     *
     * @param string $phrase Phrase to return
     *
     * @return string Returns the phrase passed in
     */
    public function echoPhrase($phrase)
    {
        return $phrase;
    }
}
and creating an index.php file in the root of the project:
1
2
3
4
5
6
7
<?php
require_once "vendor/autoload.php";
$class = new \Swader\Diffbot\SkeletonClass();
echo $class->echoPhrase("It's working");
Visiting test.app:8000 in the browser should now yield the “It’s working” message.
Don’t worry about not having a public directory or anything of the sort – this is not important when building a package. When building a library, all the focus should be on the package, and only on the package – no need to deal with frameworks or MVC. We’ll use the index.php file for testing some stuff out from time to time, but mostly, we’ll be using PHPUnit to develop our library. For now, let’s add index.php to.gitignore to make sure we don’t accidentally send it upstream.

PSR-2

To keep in sync with modern standards, we’d do best to implement PSR-2 from the get-go. I use PhpStorm, so this is dead easy to do. You can either choose the built-in PSR1/PSR2 standards, like so, or you can install and activate CodeSniffer and use it as a PhpStorm inspection, like so. I opted for the former, because remote execution of PHPCS via PhpStorm is not yet supported (and a Vagrant VM is, for all intents and purposes, remote), but if you’d like to help out with adding this feature to PhpStorm, please vote here.
You can still require CodeSniffer in your project as usual via Composer and run it from the VM’s command line, though:
You can also opt to only install PHP on your host machine (as opposed to additional nonsense that comes with a standard XAMPP/WAMP installation), download CodeSniffer there, and use it like that. You’d use your host machine only for code inspection, while developing and running your package logic from the VM. It’s a bit awkward, but helps when using IDEs like PhpStorm, at least until the aforementioned issue is implemented.
If you’re not using PhpStorm, look for alternatives on how to accomplish this, but make sure you do – we need PSR2.

Planning

With our bootstrapping out of the way, we can start developing. Let’s think about everything we need.

Entry point

No matter what the use case for Diffbot’s API, a user will want to create an instance of the API client – there’s nothing you can do with Diffbot other than query the pre-made APIs. Each API use also needs a developer token which is to be passed in the request as a query param, in the form of ?token=xxxxxx. My reasoning is as follows: a single developer will usually be using a single token, so aside from allowing developers to create new API client instances and passing in a token (say, in the constructor), we should also have a way of defining a global token to be used in all future instantiations. In other words, we want both of these approaches to be valid:
1
2
3
4
5
6
7
8
9
10
$token = xxxx;
// approach 1
$api1 = new Diffbot($token);
$api2 = new Diffbot($token);
// approach 2
Diffbot::setToken($token);
$api1 = new Diffbot();
$api2 = new Diffbot();
The former approach helps when you’re creating a single API client instance, or you’re using several tokens (maybe you have one for Crawlbot, and one for regular APIs). The latter approach works well when you’ve defined many API endpoints for your application to consume and will be needing several, but don’t want to re-inject the token every time.
With that in mind, let’s go ahead and make our package’s first class. Create the file src/Diffbot.php.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
namespace Swader\Diffbot;
use Swader\Diffbot\Exceptions\DiffbotException;
/**
 * Class Diffbot
 *
 * The main class for API consumption
 *
 * @package Swader\Diffbot
 */
class Diffbot
{
    /** @var string The API access token */
    private static $token = null;
    /** @var string The instance token, settable once per new instance */
    private $instanceToken;
    /**
     * @param string|null $token The API access token, as obtained on diffbot.com/dev
     * @throws DiffbotException When no token is provided
     */
    public function __construct($token = null)
    {
        if ($token === null) {
            if (self::$token === null) {
                $msg = 'No token provided, and none is globally set. ';
                $msg .= 'Use Diffbot::setToken, or instantiate the Diffbot class with a $token parameter.';
                throw new DiffbotException($msg);
            }
        } else {
            self::validateToken($token);
            $this->instanceToken = $token;
        }
    }
    /**
     * Sets the token for all future new instances
     * @param $token string The API access token, as obtained on diffbot.com/dev
     * @return void
     */
    public static function setToken($token)
    {
        self::validateToken($token);
        self::$token = $token;
    }
    private static function validateToken($token)
    {
        if (!is_string($token)) {
            throw new \InvalidArgumentException('Token is not a string.');
        }
        if (strlen($token) < 4) {
            throw new \InvalidArgumentException('Token "' . $token . '" is too short, and thus invalid.');
        }
        return true;
    }
}
The method also references a DiffbotException, so real quick, just make the filesrc/exceptions/DiffbotException.php with the contents:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
namespace Swader\Diffbot\Exceptions;
/**
 * Class DiffbotException
 * @package Swader\Diffbot\Exceptions
 */
class DiffbotException extends \Exception
{
}
Let’s quickly explain the Diffbot class.
The token static property will serve as the default which Diffbot will use if no token is provided in the constructor while building a new instance. In that case, it gets copied into the instanceToken property which is bound to instances.
The constructor checks if a token was passed. If it wasn’t, it uses the predefined default token, or throws a DiffbotException if none was set – that’s what our Exception code above was for. If the token is OK, it gets set as the token of the instance. On the other hand, if the token was passed in, then that one gets copied intoinstanceToken. Note that in both cases, the token must be validated with the validateToken static method. This private method for now simply checks if the token is a string of a length of more than three characters – if not, it throws an invalid argument exception.
Finally, there’s the setToken static method, which lets us set the aforementioned global token. Naturally, this one needs to get validated, too.
Seeing as a Diffbot token is bound to its set of APIs, being able to change a token on an already existing instance of Diffbot would be crazy. As such, I’ve opted to allow the setting of a token only on instantiation, or globally for all future instances of Diffbot. Of course, if the token gets set globally, an instance can still override this setting. Also, the global token is mutable, because we want to be able to change the spawning condition of future instances, and changing it when instances already exist doesn’t affect them in any way.
Notice also how everything is documented with docblocks – not overdocumented, but just enough to make it easy to understand for everyone else coming in.

Conclusion

In this part, we got started with PHP package development by setting up a skeleton project with some basic functionality, and by configuring our environment. You can download the end result of part 1 here. In part 2, we’ll start writing some tests and some actual functionality, and we’ll get started with proper test driven development. Before we move on, are there any questions or comments regarding the current process? Leave them below!
Read More