Code. Life.

Laravel PHP development on the iPad Pro

L

As I said in a separate post, I am a Laravel developer amongst other things and recently, I bought a 12” iPad Pro from Apple. I do a lot of writing and I also consume a lot of media on YouTube and Netflix. I also enjoy sketching and prototyping every once in a while. So the iPad Pro was a no-brainer. I was scared of the limitations of iOS though but bought it anyway. Days later, iPadOS was announced — never been happier about a purchase.

Laravel development on the iPad Pro iPadOS
12” iPad Pro

However, as a developer at heart, there was one thing I wanted to be able to do the most on my iPad: programming. I checked out many tools but most of them required me to SSH to some server and edit from there. No. I wanted something that could run offline and be able to preview without the need for a stable internet connection. Enter DraftCode.

With DraftCode, I had the ability to run PHP applications offline. Although the editor itself is less than impressive, with no support for auto complete and basic editor features, DraftCode’s ability to run PHP offline was what I needed. Paired with my other development tools, it seemed like I could finally play around with projects without having to whip out my MacBook.

Laravel / web development with with iPad Pro
My web development tools on my iPad Pro

Some other tools I use are:

The problem

The problem with DraftCode became apparent when I wanted to start building apps. You see DraftCode does not have a CLI and cannot run composer commands. This means you can only run the installation on a PC, commit the vendor directory, and then import everything into DraftCode. This was a pain. I did not want to have to pick up my laptop every time I wanted to start a new project.

This problem was why I built Cmpsr. This is not a full product by any means and it is not to be treated as such, at least not yet.

How does it work

Cmpsr works by allowing you provide a composer.json file and it then returns the bundled vendor directory. Using the bundled helper makes it as easy as just running a PHP script and it will generate the ZIP and unzip to the vendor directory. If you want to add new packages, just update the cmpsr.json or composer.json file and resend your request.

Running PHP & Laravel on Your iPad

You should be able to complete all these steps from your iPad Pro running iPadOS. Download the latest version of Laravel from the repository using Safari.

Download Laravel to your iPad

Next open DraftCode and import the Laravel framework into the editor. This will be a ZIP so just unzip the project using the unzip tool that comes with DraftCode. When you have done this, you should now have a familiar Laravel installation on your DraftCode.

Next, go to the cmpsr repository and download the cmpsr.php file (or just create a new file in DraftCode and paste the contents into it). The file should look something like this:

<?php

/**
 * Cmpsr
 *
 * This package was writted mostly because developing on an iPad is very limited
 * and DraftCode, although has offline running capability, did not have support for
 * Composer. This package will thus use the cmpsr.co API to generate the composer
 * packages outside and then return the ZIP as a package. It is by no means perfect
 * and I will be updating it as time goes.
 *
 * @author   Neo Ighodaro <neo@creativitykills.co>
 * @package  Cmpsr
 * @version  1.0
 * @license  MIT
 */

defined('CMPSR_BASE_URL') or define('CMPSR_BASE_URL', 'https://cmpsr.co');

/**
 * @return void
 */
function cmpsr_install(): void
{
    $composerFile = file_exists(__DIR__ . '/cmpsr.json')
        ? __DIR__ . '/cmpsr.json'
        : __DIR__ . '/composer.json';

    if (!file_exists($composerFile)) {
        throw new Exception('Could not locate a "cmpsr.json" or "composer.json" file.');
    }

    $contents = file_get_contents($composerFile);
    $data = ['data' => _cmpsr_json_recode($contents)];

    $response = json_decode(_cmpsr_send_request($data), true);

    if (!$response['status'] ?? false) {
        throw new Exception('An error occurred. Err: ' . $response['error'] ?? 'unknown');
    }

    $filename = basename($response['url']);

    echo "Downloading ZIP file from {$response['url']}..." . PHP_EOL;

    _cmpsr_download_file($response['url'], $filename);

    if (!file_exists($filename)) {
        echo "Error downloading ZIP file..." . PHP_EOL;
    }

    echo "Download complete. Unzipping..." . PHP_EOL;

    $zip = new ZipArchive;

    if ($zip->open($filename)) {
        $res = $zip->extractTo(__DIR__);
        $zip->close();
    }

    echo ((isset($res) && $res) ? 'Unzipped successfully!' : 'Failed to unzip') . PHP_EOL;

    unlink($filename);

    echo "Complete.";
}


/**
 * @return void
 */
function cmpsr_fetch(string $hash): void
{
    // Try to fetch
    // If fails then try to install
}


/**
 * @return string
 */
function _cmpsr_json_recode(string $contents): string
{
    return json_encode(json_decode($contents));
}

/**
 * @param  array $data
 * @return string|null
 */
function _cmpsr_send_request(array $data): string
{
    $curl = curl_init();

    curl_setopt_array($curl, array(
        CURLOPT_URL => CMPSR_BASE_URL . "/install",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 300,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "POST",
        CURLOPT_POSTFIELDS => json_encode($data),
        CURLOPT_HTTPHEADER => array(
            "Accept: application/json",
            "Content-Type: application/json",
        ),
    ));

    $response = curl_exec($curl);
    $err = curl_error($curl);

    curl_close($curl);

    return empty($err) ? $response : json_encode(['status' => false, 'error' => $err]);
}

/**
 * @param  string $url
 * @param  string $path
 * @return void
 */
function _cmpsr_download_file($url, $path): void
{
    $newfilename = $path;

    if ($file = fopen($url, "rb")) {
        $newfile = fopen($newfilename, "wb");

        if ($newfile) {
            while (!feof($file)) {
                fwrite($newfile, fread($file, 1024 * 8), 1024 * 8);
            }
        }
    }

    if ($file) {
        fclose($file);
    }

    if ($newfile ?? false) {
        fclose($newfile);
    }
}

cmpsr_install();

This is just a sample way to fetch the packages but you can and should build one yourself.

Next, it is recommended to duplicate your composer.json file to cmpsr.json so that cmpsr can use this file. The gotcha is that you will need to update both files whenever you want to update the requirements. Finally, you need to make sure the json file does not contain any of the keys in the known limitations section of the readme.

Now run the cmpsr.php file inside DraftCode. It will take a while to generate the vendor directories and you will see absolutely no output till it’s completed so have some patience. When it’s done, you should now have the vendor directory as expected.

Composer install on the iPad Pro

Making some other things work

If you are just building a regular PHP package or application, this might be good enough and you can just run the PHP file you want to run, however, if you are building a Laravel application you need to update something to make it (somewhat) work with routes.

Open the index.php file in the public directory and update the code as seen below:

if ($_GET['route'] ?? false) {
	$_SERVER['REQUEST_URI'] = $_GET['route'];
}

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

Great now you can launch the index file and when you want to visit a route, you have to append the route query parameter. A minor annoyance but it’s tolerable.

Oh, you also need to create the usual .env file and add the application key to the file. Now you’re good to go.

Laravel running on the iPad Pro
Laravel running on the iPad Pro / iPadOS

From here I think you got it. You can also add Working Copy for some git integration. If you play your cards right, you can probably have the code on git and then build on your MacBook when you are on there and also build on your iPad when you don’t have your MacBook with you. Wins!

Gotcha!

For now, Cmpsr is free and open-source but this may change in the future, if you wish to contribute, let me know. Also it is hosted on a relatively low-powered server so it might make more sense to host it on your own server.

If you have tried it and it works for you let me know. If you run into problems also let me know. There may be more limitations that I may have missed. If you have other tips, you can also share them in the comments section below.

Comment

Leave a Reply

Code. Life.