From artisan to artisan command

Have you tried to execute an artisan command from the handle of another artisan command?

Yeah, all fine you could say, but, no, there is a hidden mess buried deep into the bootstrapping mechanism of Laravel, an insect maybe that some people may call a feature.

If you run a command for a specific environment (e.g. –env=production) and that command executes another artisan command but for a different environment by specifying it on the command line arguments (e.g. –env=testing) guess what? the nested call will not see the change! This is kinda terrible because although you define a specific environment on the nested call, it will be ignored and it will be executed on the parent environment and probably affect a different database than the one defined on the code.

So what can we do? Simple: load the desired .env file manually and instead of Artisan::call use a Symfony process.

Here is a draft example:

Load the env file manually:

$basepath = app()->basePath();

$dotenv = Dotenv::createArrayBacked($basepath, ".env.testing");
$values = $dotenv->load();

The configuration has not changed yet:

$cmd = ["php", "artisan", "db:migrate", "--env=testing"];

$process = new Process($cmd, null, $values);

$process->setTimeout(null)->setTty(true)->mustRun(function ($type, $buffer) {
    echo $buffer;
});

See:

https://stackoverflow.com/questions/64577028/calling-artisan-commands-from-other-artisan-commands-using-different-env

Create database schema via DB Facade

Kinda tricky, but laravel tries to select (use) the database schema when trying to connect to the database and not when executing the queries. So if you try to connect in order to create the schema you will get an error that the schema does not exist. (doh). Which is kinda of a paradox.

So the trick here is to set the database to the configuration to null. Then laravel will not execute any use statement and you will be able to create the schema. You have to restore it though else the following commands will fail.

Here is a solution that does not depend on the database technology:

$connectionName = config('database.default');
$database = config("database.connections.{$connectionName}.database");

config(["database.connections.{$connectionName}.database" => null]);
DB::purge();

DB::statement("create database bloo");

config(["database.connections.{$connectionName}.database" => $database]);
DB::purge();

To find the connection and the database you may also use the ConnectionResolverInterface and do something like this:

 public function handle(ConnectionResolverInterface $connections) {      
  $connection = $connections->connection($this->input->getOption('database'));
  $connectionName = $connection->getName();
  $database = $connection->getDatabaseName();
}

For more, see:

https://github.com/laravel/framework/issues/19412

Snap to orthogonal shifted Grid

Given a orthogonal d-dimensional grid: Grid(t, δ) where:

  • d the size of the grid (distance between intersections (same to all dimensions)
  • t the shift of the grid (t is a vector)

A vector v can be snapped to the grid as follows:

Since for each xi of v:

kδ + ti <= xi <= (k+1)δ+ti

Solving by x gives:

xi = floor((xi-ti)/δ + 1/2)*δ + ti

Docker links

Documentation:

Per framework:

https://dev.to/martinpham/symfony-5-development-with-docker-4hj8

Useful articles:

Deployment:

Examples of composition:

Examples of docker file:

Common mistakes:

Personal portal to the Internet