Introducing PHP API Client v2

A new version of the PHP client is coming. This will be the base for a new version of other client within the next few months.

If you ever found yourself thinking “I wish I could do this with the client”, please email me (julien.bourdeau@algolia.com) or open an issue on GitHub.

~~The current alpha version is available on github, on the 2.0 branch: https://github.com/algolia/algoliasearch-client-php/tree/2.0~~ Merged on master branch.

Why

All the Algolia clients were designed years ago, we think rewriting them from scratch will help improve the developer experience for every user and make them more maintainable.

More maintainable means faster feature development and less bugs, so in the end, it all comes down to improving the developer experience for the entire Algolia community.

Requirements

Backward compatibility

We believe it’s sometimes necessary to break backward compatibility, however we want to keep it as minimal as possible, upgrading to the new major version has to be very smooth.

Similar public API

For that reason, most of the public API is kept as-is or has very slightly changed. The library still relies on 2 main classes to access most of the API: Client and Index.

Even if we considered doing something more eloquent or even build some sort of query language, we are convinced that this will add a lot of complexity, make upgrade really hard and bring very little value in the end. Simplicity for the win.

PHP 5.3+ supported

This new version support the exact same PHP version range as before: 5.3+. We chose to do it to simplify upgrade as much as possible. Even if it made my life more difficult, I believe it will make everybody else’s easier.

New backward compatibility promise

  • All API clients follow SemVer.
  • Backward compatibility is guaranteed on all classes and interface except of the Internal folder
  • New exceptions can be added at any time but they will necessarily extend AlgoliaException class.
  • Configuration entry can be added in minor versions.
  • The structure of the API response can have new field added independently of this library.

Conventions

A good library should be obvious to use.

  • Method signatures have an argument for all required parameters and then one array of requestOptions which can contain about anything

  • Required arguments take precedence over the requestOptions array.

    In the following example, some query will override better query.

    $index->search('some query', ['query' => 'better query']);
    
  • Verbs:

    • save means add or replace existing ← /!\
    • partialUpdate means updates only the given fields
    • clear means delete all
    • delete means delete
    • replaceAll means remove all existing and save what is passed

* There is no phpdoc in the code for public API method, because it’s usually outdated and clutters the code. Instead, refers to the doc on algolia.com (to be published along with the final version). If the method is internal, doc can be added if necessary.
There are now some PHPDoc and we’ll add as much as possible. I’m still not a fan, but other people might want it.

What’s new

The transport layer

This new version allows developers to change the transport layer easily. If your PHP version is recent enough, all HTTP calls are done by the Guzzle library. The lib also follow the PSR7 standard.

If you have an old version, use the embedded http layer.

In order to implement your own, implement the HttpClientIntercace, which define only one request method.

RequestOptions as a first-class citizen

Timeouts and parameters all managed by requestOptions

RequestOptionsFactory is responsible for splitting the given array into 4 sections: headers, query params (url), post content and timeouts.

Timeouts are the transport layer’s responsibility but in order to change them easily per query, they were added to the RequestOptions.

Some params like forwardToReplicas or createIfNotExists should always be passed in the query params, while other parameters like cursor (in browse) should be passed in body, RequestOptions will take care of that.

RequestOptions schema

NOTE: Passing an array makes the library much easier to use but if you need total control, you can pass a RequestOption object instead.

Debug Mode

The client now integrates a debug mode, which allow you to print some information by default (typically, the request being sent).

You can enable/disable it via a static call. This way, as opposed to a env variable, you can enable it only in certain conditions.

By default, the handle() method will check if the dump function is defined (in Symfony or Laravel for instance), otherwise fallback on var_dump. You can override this behavior (to write to the logs for instance) via the setHandler() method.

In the final release, debug mode became a logger

A logger can be set, so it logs events like the rest of your application. By default, there is a debug logger that will dump or var_dump the logs.

Algolia\AlgoliaSearch\Logger\DebugLogger::enable();
Algolia\AlgoliaSearch\Logger\DebugLogger::disable();

Canary Release

The library ships with a CanaryClient class which extends Client. The point would be to add methods in beta in this class so you can start using them if necessary. Once they’re considered stable, they’ll be moved to the Client class.

The idea is that features here don’t have to follow the normal release cycle. A feature in canary could be in beta while 6 minor versions are deployed.

Features in canary could change or be removed.

THIS FEATURE DIDN’T MAKE IT IN THE FINAL RELEASE

New methods

reindex

Ever wanted to reindex your data without down time? You had to create a temporary index, add synonyms, rules and settings, index data and rename your index.

Now you can use $index->replaceObjects($objects) which will take care of everything for your.

WaitFor

Operations on keys or userIds don’t return a taskID. To ensure the task is completed, new methods were added to simulate the behavior.

Currently, only $client->waitForKeyAdded($key) is implemented, others are coming.

In the final release we came up with a much better solution, every write operations return an object (array accessible) with a wait method. This way you can do:

$response = $client->addApiKey(['search'])->wait();
dump($response['key']);

The doctor tool

Having an issue? :pill: Run ./vendor/bin/algolia-doctor to get a full configuration check and provide helpful message to improve your setup.

You can find the check in the bin/ directory. What other check would you like to see?

Exceptions

A bunch of new Exceptions have been introduced. The main reason is to help the developer debugging but also catch them in production.

  • MissingObjectId if you tried to add object without objectID
  • BadRequestException if your request cannot work
  • NotFoundException if the API returned a 404 (extends BadRequestException)
  • RetriableException if something went wrong and query again
  • UnreachableException - hu ho

Could be added if necessary:

  • QuotaExceededException if you reached your plan limits
  • ACLExceptions if you’re using an key that cannot perform this action

Upgrade

Please follow the upgrade guide in docs/UPGRADE-from-v1-to-v2.md.md.

This doc will be updated during the beta and will be complete before the final release.

Tests

There are 3 types of tests.

Type Description
Public API tests Check the library has correct method names and arguments (using reflexion)
Integration tests Call Algolia API to ensure method behave the way they should
Unit tests Some part of the code is absolutely critical and must be Unit tested, the RequestOptionsFactory for instance.

Integration tests use a SyncClient and SyncIndex which automatically wait for all taskID, making tests easier to read and more stable.

Call for feedback

If you are already an Algolia user or if you plan to be, please share any feedback you may have via:

In general, I’d like to hear:

  • What you would like to see added
  • How long was it to upgrade
  • If it’s clear enough
  • What feature you’d like to see added
  • How well (or not) it integrates in your stack

Question

Should we consider client, index and such as final or let developers extend them?

Do you see any missing feature?

Edited for final release

2 Likes

Hi,

I don’t support the decision to support PHP5.3+
Any modern libraries drop support for PHP5.3 ages ago.

Minimum requirement should be 7.1+. http://php.net/supported-versions.php

Anyone who is forced to stick with their <PHP7.1 should be using the 1.x version.

I hope you’ll change your mind about this, or this decision will haunt you while maintaining the 2.x branch.

1 Like

I would definitely love to drop PHP 5.x entirely but we still have a significant amount of users using it. At least, I’m hoping we can go up to 5.4 soon. this is not available in closure and traits don’t exist yet in 5.3, which is what I missed the most.

The reason I’d rather avoid 2 versions of the package is for our integration. For example, a lot of users using old version of PHP are running Magento or WordPress and keeping these plugins working with both 1.x and 2.x api clients will be very complicated.

Basically, I think it will be easier to maintain 1 lib with very old PHP version than 2 libraries.

I recently added the PHP version in the UserAgent to get a better picture, until then, we only had this data with the Magento and WordPress integrations.

Thanks a lot for taking the time to share your feedback :pray:

2 Likes

I’m glad you’re thinking of the users here. Printkick are on a Magento build and don’t have any intention to upgrade - it’d be pretty bad to lose Algolia functionality simply because you’re not supporting older versions of PHP.

1 Like

Thanks @aman! I understand that upgrading PHP version can be risky but moving to PHP7 should be a significant improvement from a performance perspective.

I’m just gonna drop this link : PHP Versions Stats - 2018.1 Edition | Jordi's Ramblings

As you can see, php 7 is kinda the most used version (around 80%ish ?). PHP 5.3 is dead and has been that way for at least the last 5 years or so, if not more. The same goes for your “hope to get on 5.4 minimum”…

Basically, this is a footgun.

BTW, Magento stopped supporting PHP5 over a year ago (https://github.com/magento/magento2/commit/0364bf93b363fe7923b2fa95ab61f3b715828565) and it was 5.6… And wordpress being wordpress, that’s another matter altogether. But at least they’re recommending 7.2…

WordPress and Magento1 are still important to us. I wish everybody using PHP would update to PHP7, it would benefit them a lot as well as the community.

Note that these Magento1 and WordPress don’t use composer so they’re not included in Jordi’s stats.

This is very tough decision to make but today, I think it’s better to trade off some PHP features to make it available for all users. Maintaing 2 version of the lib (hence to version of Magento1 and WP extension) would be the worth case scenario.

I had a very different opinion when I was working at PrestaShop, because maintaining an old PHP version for an entire ecommerce CMS was a very different tradeoff. For an Algolia API client, I think it’s manageable to keep the compat’.

I appreciate you taking the time to share your feedback :raised_hands:

1 Like

I edited the first post to take into consideration everything that has changed between the beta and the final.