Restructoring Where to run Laravel Scheduler from.
In Laravel there is a great scheduler built in.
You need to run a OS based job that calls a console action every minute
This works great, and various functions allow you to run your scheduled actions at pretty much any interval you want.
I currently use scheduler to
- Check for bookings every minute during the day
- Check for bookings every 10 minutes at night.
- Clear up cache directories once a day
- Prune models every day.
- Send out student emails at a specific time daily.
However I find that putting information into the schedule method of the console Kernal to be not the best place to put this info. For one thing when searching I type ‘schedule’ but that wont find my file so it seems like the wrong place.
instead what I do is create a Scheduler class and place it in the Consol directory with a single method
public function schedule (Schedule $schedule)
inside this I can reference the $schedule object and call all my schedules
public static function run(Schedule $schedule) { >User::LoginSystemUser(); Self::CheckInternetBookings($schedule); $schedule->call(new RemoveSpacesFromNames)->name('Remove Space from front of names’)->everyThirtyMinutes(); $schedule->call(new UpdateNullAccommodation)->name('Update Accommodation 1900 to null’) ->everyThirtyMinutes(); …. }
and I just need to this in the kernel
protected function schedule(Schedule $schedule) { Scheduler::run($schedule); }
I find that this is a much better layout. Hope this is helpful
Facades or Helpers?
In Laravel code we often use helpers and facades interchangably and many of the facades that are used most in Laravel are also available as Facades
eg.
view('order.show');
view::make('order.show');
This is so prevalent, that I thought that helpers were part of Facades so when I went to create my own facade I couldnt understand why the helper function didnt work.
Slowly it dawned on me this was not the case and what I really needed was a facade and a helper function.
I found this very helpful article on Laravel news
https://laravel-news.com/creating-helpers
This explains very simply what helper functions are, where and how your crate them and how you autoload them.
Now I have a facade and a helper function and I’m happy.
Further integration with Laravel
A few weeks ago I wrote a short blog post outlining some of the early success and challenges I had had integrating Laravel with a large legacy application. It is not possible to start again from scratch, so I am using Laravel to provide the application development process with a modern platform while continuing to allow the legacy code to run unhindered.
Since then i have continued to integrate the code and have come upon and successfully solved several integration issues.
- Laravel must be loaded in a function.
- Laravel Takes over all Error Processing
- Sometimes you think Laravel is causing a bug but its not.
- Sometimes you can use both
Integration
At the begining I was unsure exactly how integrated I would make the Laravel Code and the Legacy Non Laravel Code. I began by only loading the Laravel Codebase when I needed it, but quickly realise that having laravel functions available provided a huge advantage to the legacy codebase, so now I just load laravel in the config load file for the legacy codebase, ensuring I have access to all functions at all times.
Together but seperate.
One obvious area for seperation is in views. My legacy code base uses smarty, which I have always liked, and have been using since V1. If laravel had an option to use Smarty I would have continued with it, but thats not possible, so I use Blade with my new Laravel code.
This was a simple decision. Old code would continue to use Smarty, new code would use Blade.
Then…
Then I decided to provide information about a new feature (Subscriptions) to an old feature (Booking) so I pulled in the new Subscription Eloquent model into my view_booking page and passed it to a new Smarty template to use as a partial in the main Smarty Template? But why write a new template in Smarty, if I’m slowly going to be moving to Blade? So instead I called
$SubscriptionsHTML = View::make(‘bcs.booking.tab_subscriptions’,['Subscriptions’ => $Subscriptions]);
This runs my new Blade Partial through the blade engine and returns my HTML which I can pass to Smarty as part of its content.
This may seem like I’m mixing up lots of things and heading for making myself very confused, however I see it differntly. i have decided to embrace (Laravel)[https://laravel.com/] and use it moving forward. The more I integrate it with the old codebase the more I will be willing to write ALL new code in any part of the codebase using the Laravel Framework.
I have been amazed at how well I have been able to integrate an existing project with Laravel.
(Attempting to ) Integrating Laravel into a Legacy Codebase
We have a reasonably large codebase for a PHP application that provides the main business functions here at the cookery school. It was written orginally in 2004 when I thankfully decided to see what would happen if I turned our main business app into a web app written in PHP (rather than clasic ASP) instead of another Delphi desktop app which was what I was planning.
The usability and speed that I got up and running using PHP 4 was wonderful but it is very legacy.
- Very very few objects
- All functions to capture logic
- Each page has its own php page.
- All pages pull in all code (pretty much).
- Very little file structure, all files in a two directories. pages and includes
- No Namespaces
Recently I have been learning an ready about Laravel. This has been on everyone else’s radar for a long time and came on mine about 4 years ago when I was introduced to Lumen by a colleague. Having spent lockdown going through the excellent Laracasts introduction to Laravel 7 I felt like it was time to use Laravel a bit more.
Sure I can use it for any new api’s or apps, but what about leaveraging some of the benefits for our main application. Well its worth a try.
This blog post (possibly posts) tells my story of how I got (or did not get) a legacy codebase working in tandam with Laravel and modern PHP 7.
Working in Parallel
First things first: get a Laravel App and my primary core application both running on the same domain. As I have mentioned before I use the wonderful CaddyServer to host our sites. I set up a new site and pointed it to a directory on my server.
I created a new Laravel app in the directory and pointed caddy to its ‘public’ directory
Laravel
\App
\Public
\resources
Next I cloned my entire core application into the public directory (making sure not to overwrite the index.php file here).
How to get it working?
Just like this, Laravel works no problem, you can set a route and as long as the route directory doesnt really exist in my main application, I can get access to a controller and view a new laravel app. I can also access my legacy application on a standard url since the files all exist in the public directory.
However I dont want to rewrite my entire application straight away, so I do want to be able to call functions in my legacy application from Laravel.
First off I tried simply calling the function from the controller.php after include the appropriate files. This inevitably led to an error that the function was not found. This of course was due to there being no namespaces in my legacy code.
The Reason for Namespaces
I immediately got an error saying that
Logger can not be redeclared
My code declared a logger function which unfortunately is pretty common and laravel declares a logger also. Without namespaces I was stuck since PHP didn’t know which logger I wanted. I had come upon the fundamental reason for declaring namespaces in the first place.
So I added a namespace at the beginning of the file that contained my function.
Namespace BCS
Then I got a different error. Now I need to use Namespaces everywhere.
My code calls PDO but does not call \PDO
So I change the few instances where I find
PDO::FETCH_ASSOC
to
\PDO::FETCH_ASSOC
Then next I get error for functions that my legacy function calls. So I add namespace BCS to those files also.
and it all starts working (for that one function).
Ok. So far so good.
Next I got back and try to view my legacy application.
Its all broken!
By putting a few namespace BCS in my legacy code, I had broken the app. Namespaces seem to be an all or nothing. My entire legacy app needed to be in a namespace or none of it.
With a quick find and replace on the two primary folders in my application, I inserted the line
namespace BCS
at the begining of each and ever file and although there are still a few errors, which I am workgin through, I now have my legacy app up and running again on the BCS namespace and I can call functions if required from my new Laravel app.
I’ll see if I do finally hit a wall I can’t get past or if I can slowly convert my old legacy app into a laravel app, one page at a time.
Next up - Calling Laravel Controllers from my Legacy App!!
Using Laravel Classes in the Legacy Application.
Now that I have the two applications working seperately withing the same file structure and my new Laravel code can call functions in my Legacy application I had a lot of what I need.
This will allow me to create new section of the application and create them in Laravel, calling into the old legacy app when required to provide some logic I do not with to duplicate.
What about the modifications to the legacy appliation though?
I am hoping that using laravel will give me access to all the great features and conventions that Laravel provides. This I can do with new code, but what if I want to add code to an existing feature that cant easily be moved out into the new section?
Calling Laravel Objects from Legacy Code
Wouldnt it be cool if I could declare a Eloquent Class in Laravel and then create an instance of that class in my Legacy Application? That way I could really share code.
Starting Laravel
The entire Laravel Application is run from a single file public/index.php, which despite a lot of comments is only actually about 5 lines of code
define(‘LARAVEL_START’, microtime(true));
require __DIR__.’/../vendor/autoload.php’;
$app = require_once __DIR__.’/../bootstrap/app.php’;
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
I tried simply including this file. It should load Laravel and allow me to create a new instance of my object right? Well yes, but it just routes to the home page of laravel, which isnt useful.
I took a look at the code in index.php and decided that I probably needed it all except for the last two lines.
$response->send();
$kernel->terminate($request, $response);
I created a new file called loadlaravel.php and put the contents of index.php into it but commented out the last two lines.
BINGO - It Works.
So now I have a new laravel app that can call functions on my legacy application, and a legacy application that can use laravel classes.
Now to write the code and see where I go.
Very few things are truly boolean
When writing code and particuarily business applications, there are certain things that are true or false, or seem to have only 2 possible values
Examples
- Does a customer want
- Accommodation
- No Accommodation
Leaving aside any discussion of non-binary assignment of gender these two options leave out a very important third option.
The customer has not chosen ?
Anytime you are choosing a boolean value for something in code or in the database, think. Can this value really be only true or false? Are we sure there is a not a ‘Has not choosen’? value?
If so don’t make the field boolean, make it something else.
€1000 a year for Open Source
Ballymaloe Cookery School like EVERY SINGLE BUSINESS on the planet relies on a huge amount of open source software to run. We use Caddy Web Server to run our internal line of business websites all served over https with LetsEncrypt TLS Certs. Our main customer facing site runs on Drupal and mariadb.
That is not to mention that most of the routers on our network run some form of linux.
The world today only runs because of Open Source Software, and businesses such as ours can only do what we do because of open source software.
Giving Back
Ballymaloe Cookery School is pledging to give a minimum of €1000 a year to support open source projects. I will update this post as we decide which projects to support. This is something we encourage all businesses large and small to do.
If you are hesitant to spend this money just imagine what it might cost if you had to run your website on a proprietary server or buy a licence for your database or create your own CMS from scratch.
Simplifying Code Review with Github and Caddy
I’ve been involved in the Caddy webserver project for a while now and use it as the main webserver for all our internal admin applications.
It is super simple to use, very easy to configure, a breath of fresh air after years of wrestling with apache, ohh and it (makes setting up a https site)[https://caddyserver.com/docs/automatic-https] so (trivial)[https://caddyserver.com/docs/automatic-https] you forget that was even a thing.
It comes with lots of great modules for doing lots of cool stuff such as browsing folders, using markdown, automagic https, fastcgi, proxy etc, but also has a whole host of 3rd party plugins that can be build right into the executable via the build server at caddyserver.com. One of those is a really great plugin called git by Abiola. This plugin will pull your repo from a github (or other) repository and respond to any commit git hooks, to make sure your site is kept up to date with any changes.
I had ignored it for a long time thinking it wouldnt work with private repos on github, but now that Windows git / github integration is better and https rather than ssh is the standard way to push changes to github on windows, it all seems to work brilliantly.
We are only a two man team and recently we started using github private repos to code review pull requests. This is fine for the codereview part but its always a bit of a pain to test out the changes on the branch prior to merging.
This is where caddy and git plugin come along.
update your caddy file with the new branch and restart.
githubbranch.example.com {
root c:\\www\\mysite\\gitbranch
git {
repo https://github.com/tobya/privaterepo
hook /webhooks/xxcaddygithook secretpassword
branch issue27
}
}
Now this will pull down the new branch and we can try it out there and then.
Open Whatsapp via url
We send out an email after someone has been on a cookery course with us asking for feedback. We also ask them if they would like to send us a photo via email, text or whatsapp so we can recognise them when they come back.
I wanted to make the suggestion to send us a whatsapp a link so as to make it as easy as possible for someone to send me a photo straight from the email. I found lots of examples about how to open whatsapp from a link and lookup an id, but I wanted them to send it direct to my phone and my number is probably not in their phone. This simple snippet does it.
whatsapp://send?text=Here+is+my+photo&phone=353871111111
use this as the href in an anchor tag and it will open whatsapp with the text, ready to send to my number.
Keep cURL secure.
Recently I had a familiar error in a php script I was writing using the Dropbox api.
cURL error 60: SSL certificate problem: unable to get local issuer certificate
I’ve seen this error or similar before and I sighed. Basically this means that while my code is trying to connect to a https secured site, it is unable to verify that the Certificat Authority (CA) that issued the cert is valid, this is all about the trust for certs.
If you search for this issue online you will find many many results on Stackoverflow.com and other sites telling you to simply put -k or (more succinctly!) –insecure for your curl options to tell curl to simply assume that the cert if valid. For those of us (myself included) who don’t really understand encryption, the idea of our communications still being encrypted but not verified, seems to be harmless, its the encryption we want, so what’s the harm.
Its really not!
The more –insecure parameters out there peppering scripts the easier it is for someone to impersonate dropbox.com and have great fun with all my and your files.
The Solution
Before abandoning all hope, I thought I’d do a search for a solution and found a really simple one courtisy of a Sven0188 on Laracasts.
https://laracasts.com/discuss/channels/general-discussion/curl-error-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate/replies/37017
The solution is to download the CA list from the curl website. Download the file and save it somewhere useful, then tell php about it by modifying this line in your php.ini file
[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo = C:\PATH\TO\YOUR\cacert.pem
restart your webserver or php process, and VIOLA your problem is solved and your secure.
everythinghttps