Larahook: Hooks for Laravel
In SaaS or similar applications, there often comes a point when you want to start adding custom or tweaked functionality for clients without the codebase itself diverging. One of the most common solutions to this is to use hooks.
Hooks effectively allow you to make certain parts of your applications functionality open to modification by another part. My own usage of this for instance is allowing a single white label configuration file to adjust (in some cases quite deeply) how the larger application works. WordPress is probably the most well known for using this approach in order to allow its plugins and themes to easily interact with WordPress’s functionalty, without needing to make any changes WordPress’s own code.
To support this functionally in a Laravel application, for the last few years I have been using the wonderful esemve/Hook library by Bence Kádár. Unfortunately the library now appears to be mostly inactive – most critically lacking support for Laravel 8 (as well as PHP8 itself in some areas).
As such, with an growing requirement for additional functionality and updates, I decided to take the plunge and create a new maintained fork of the library.
Although for simple use cases coinvestor/larahook
can be used as a drop in replacement for the original esemve/hook
, I utilised the opportunity of it being a clean break to make some more involved changes to the libraries functionality.
The most important changes are listed below.
Laravel 8 and PHP 8 compatibility plus auto-discovery support.
The library has been updated to work with the latest version of Laraval, as well as to make use of the newer package auto-discovery features meaning you will no longer need to update your app.php directly.
Retired the initial content parameter, and replaced it with $useCallbackAsFirstListener.
In the original version of the library, you needed to specify both a call-back (to run when the hook was not being listened to) as well as optionally a default $output
value to be passed in as the 4th parameter to the get hook method. This lead to some confusing code where a hook would need to invoke the original call-back directly to get a default value (where output was null), but if a second hook had run previously, may instead include data in the $output the hook would need to be aware of.
To simplify this I changed the 4th parameter on get
to instead be a Boolean called $useCallbackAsFirstListener
, as such by setting this as true, the hooks default callback will always run and pass its value in as the $output
value for every subsequent listener. As such listener logic can be simplified to always expect to be working with the value of output. For now this option is left as false, as in the case where the default hook is taking an action (say sending an email) this behaviour would not be desired, and so for safety must be specifically enabled.
Listeners at the same hook at the same priority will no longer overwrite each other.
Unlike the original version of the library, lara-hook will allow multiple hooks to be registered on the same event at the same priority level. In the case this happens the hook listeners will be run in the order they are registered.
If you are making use of the original functionality where hooks at the same priority overwrite each other, code changes will be needed.
Support for falsely return values.
In our application there were a number of cases where we’d wanted a hook listener to return a falsey value back to an underlying function. This was previously not possible, as a hook returning false would trigger an abort – causing the hook to return the default value (rather than the falsey value itself).
This is no longer the case in larahook, meaning the Hook:stop();
method will now have to be used directly where a hook does need to abort, as 0/false/nulls will simply be returned from the hook like any other value.
New Methods: getListeners, removeListener and removeListeners.
Listeners can now be unregistered, both individually as well as all listeners for a specific hook.
Additionally a full list of listeners on a hook can be returned using the getListeners
method.
Test and bugfixes.
In addition to the functionality changes, I also spent some time adding unit tests and basic CI for the library. As is always the case when adding tests I managed to find and fix a number of minor bugs and edge cases across the library.
If you’d like to swap over to the new library, please have a look at our repo at https://github.com/CoInvestor/larahook/
PHP Secret Santa
After a few years of neglect I decided it was about time I gave my ageing PHP Secret Santa App a bit of an update.
The original, having been the result of a spur of the moment, hacked together reaction to the idea of running a CS Secret Santa between my friends (way back when in my second year of UNI), was as you may have guessed a pretty crappy implementation. The code was awful and the word awful just doesn’t capture just how bad the UI really was. Despite this, I’ve still somehow ended up running the script almost every time Christmas rolls come around.
My newer version of the script functions, effectively, the same as my original. Rather than taking the more common approach of putting the names in to two arrays, shuffling one, then joining em back together until no one ends up with themselves, I decided to stick with my original “names in a hat” style algorithm. Mostly just for nostalgia value. The implementation effectively mirrors its real world equivalent, with each user taking their turn to grab a value from the “hat” (array of users who need gifts buying from them) and putting it back and taking another if they happen to get themselves. This continues until every user has someone to buy for. The one flaw with this plan is that when the final person comes to pick, if it so happens that the only person left in the “hat” is themselves, there a little stuck. My solution to this problem was essentially just to make them swap with another user. Which so far has worked pretty well 🙂
Once everyone has been assigned someone to buy for, the next step is just email everyone telling them who they have. It may not be the shortest, simplest or most straight forward solution, but I quite like it either way.
The next step of the Rebuild was to try and create a “slightly” nicer looking UI, although due to my terrible design skills I’m not sure how successful this was, but on the bright side, I found an excuse to make a JavaScript Add User button.
As normal the code can be found on my github or you can use the live version here: http://userbag.co.uk/labs/santa/
Please feel free to ask questions, point out bugs/flaws or even just use the script for your own Secret Santa’s.
Read and write to SharePoint lists using PHP
Its been a while since I last blogged so I thought I may as well post an update. The main thing I plan to present is my, hopefully useful, PHP SharePoint API Class.
The aim of the class is essentially to make interacting with the SharePoint Lists API a whole lot more straight forward and allow PHP developers to talk with the Lists API without having to get there hands dirty with SOAP.
As with most stuff I create, its free under MIT licence and is being maintained on my Github account. At current the tool is fairly basic, although if I end up working on a SharePoint based project again I may take the opportunity to expand it further. If anyone spots any bugs or wants to add some features feel free to send em my way or just fork the github repo. Currently the SharePointAPI code is only capable of interacting with an existing SharePoint list and does not support creating new ones programmatically at this time.
You can grab the full source from: https://github.com/thybag/PHP-SharePoint-Lists-API
Setting up the PHP SharePointAPI Object
Using the SharePointAPI to read a SharePoint list is pretty straight forward. The first step is to create a new instance of the SharePointAPI object which requires a username and password (which it will authenticate with in order to interact with the lists) as well as the path to a local copy of the SharePoint Lists WSDL file.
You can normally grab the WSDL from: sharepoint.url/subsite/_vti_bin/Lists.asmx?WSDL
$sp = new SharePointAPI('<username>','<password>','<path_to_WSDL>');
Reading from a Sharepoint List
Once the SharePointAPI Object has been created, you can read from a list simply by calling:
$sp->read('<list_name>');
More advanced filtering is also possible, for example if you wanted to filter on surname = Smith and only return 5 results you would call:
$sp->read('<list_name>', 5, array('surname'=>'Smith'));
You can filter on multiple parameters simply by adding extra values to the filter array. (currently only AND ing is possible)
All results are returned as associative arrays, calling print_r on the results of a $sp->read(‘<list>’); is probably the best way to understand exactly what data is being returned.
Writing to a SharePoint List
Writing to a SharePoint list (or inserting a new list item) is equally straight forward. The data to be inserted is simply provided as an associative array to the function. For example to add someone called bob to a list you may use:
$sp->write('<list_name>', array('forename'=>'Bob','surname'=>'Brown','pet' =>'cat'));
Editing a SharePoint List Item
To edit an existing SharePoint item the syntax is fairly similar to the above examples. The primary difference being that the ID of the record you wish to edit is also required. Assuming the ID for Bob’s record was 20, you could change his pet to dog with the following code:
$sp->update('<list_name>','20', array('pet'=>'dog'));
Deleting a SharePoint List Item
Deleting a SharePoint list item also requires the ID of the record you wish to remove.
$sp->delete('<list_name>','<ID>');
Thanks for reading 🙂
P.S. I’m now only one week away from starting my new job on the Kent Web Development team. Woo 😀