Laravel detectEnvironment - how to combine machine name and server variable? - php

In Laravel 4.2, I'm using App::detectEnvironment to change database according to machine name. I also now need to have it change environment according to an environment variable. I've tried to combine but it doesn't work at the moment and I'm not sure how to combine the two techniques.
Using machine name:
$env = $app->detectEnvironment(array(
'local' => array('.local', 'homestead'),
'staging' => array('ip-staging'),
'production' => array('ip-production')
)
);
Using a server environment variable:
$env = $app->detectEnvironment(function()
{
// Default to local if LARAVEL_ENV is not set
return getenv('LARAVEL_ENV') ?: 'local';
}
Non-working combined code looks like:
$env = $app->detectEnvironment(function()
{
// Default to machine name if LARAVEL_ENV is not set
return getenv('LARAVEL_ENV') ?: array(
'local' => array('.local', 'homestead'),
'staging' => array('ip-staging'),
'production' => array('ip-production')
);
});

Found the answer - thanks to #Marwelln's hint.
The $env variable needs to come from the detectEnvironment function for it to be recognised by Laravel.
if (getenv('LARAVEL_ENV'))
{
$env = $app->detectEnvironment(function()
{
return getenv('LARAVEL_ENV');
});
}
else
{
$env = $app->detectEnvironment(array(
// local development environments are set with machine host names
// developers find this out by typing 'hostname' at command line
'local' => array('*.local', 'homestead'),
'staging' => array('ip-staging'),
'production' => array('ip-production')
));
}

This should do it. It sets to environment to what you have in getenv('LARAVEL_ENV') if it's set, otherwise it uses the default $app->detectEnvironment method.
$env = getenv('LARAVEL_ENV') ?: $app->detectEnvironment(array(
'local' => array('.local', 'homestead'),
'staging' => array('ip-staging'),
'production' => array('ip-production')
));

Related

Escaping a PHP function as an Array value

I'm working on a Drupal 8 starter kit with Composer, similar to drupal-composer/drupal-project.
In my post-install script, I want to re-generate a settings.php file with my custom values.
I've seen that can be done with the drupal_rewrite_settings function.
For example, I'm rewriting the config_sync_directory value like that :
require_once $drupalRoot . '/core/includes/bootstrap.inc';
require_once $drupalRoot . '/core/includes/install.inc';
new Settings([]);
$settings['settings']['config_sync_directory'] = (object) [
'value' => '../config/sync',
'required' => TRUE,
];
drupal_rewrite_settings($settings, $drupalRoot . '/sites/default/settings.php');
Problem is I want my Drupal 8 project to have a Dotenv so the maintainers don't have to modify the settings.php but only a .env file in the root folder of the project. To make it work, my settings.php must look like this :
$databases['default']['default'] = [
'database' => getenv('MYSQL_DATABASE'),
'driver' => 'mysql',
'host' => getenv('MYSQL_HOSTNAME'),
'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
'password' => getenv('MYSQL_PASSWORD'),
'port' => '',
'prefix' => '',
'username' => getenv('MYSQL_USER'),
];
$settings['trusted_host_patterns'] = explode(',', '^'.getenv('SITE_URL').'$');
As you can see, the values are replaced by PHP functions, and I can't see a good way to print those values, to the point I'm not even sure that's possible.
So my question is : is it possible to escape a PHP function as an Array value when declaring this variable ?
Looks like it's not possible because of the way the Drupal function works.
Solution 1 by #misorude
Using the drupal_rewrite_settings function, we can add the value of settings as a String, like this :
$settings['settings']['trusted_host_patterns'] = (object) [
'value' => "FUNC[explode(',', '^'.getenv('SITE_URL').'$')]",
'required' => TRUE,
];
And after that, we can replace all occurrences of "FUNC[***]" by *** directly in the settings.php file.
Solution 2
Put all your settings in a separate file. Example here, a custom.settings.php file :
if (getenv('DEBUG') == 'true') {
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/dev.services.yml';
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
}
$databases['default']['default'] = [
'database' => getenv('MYSQL_DATABASE'),
'driver' => 'mysql',
'host' => getenv('MYSQL_HOSTNAME'),
'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
'password' => getenv('MYSQL_PASSWORD'),
'port' => '',
'prefix' => '',
'username' => getenv('MYSQL_USER'),
];
$settings['trusted_host_patterns'] = explode(',', '^'.getenv('SITE_URL').'$');
$settings['file_private_path'] = 'sites/default/files/private';
$settings['config_sync_directory'] = '../config/sync';
Then we can copy the default.settings.php and add our custom settings.
$fs = new Filesystem();
$settings_generated = $drupalRoot . '/sites/default/settings.php';
$settings_default = $drupalRoot . '/sites/default/default.settings.php';
$settings_custom = $drupalRoot . '/../includes/custom.settings.php';
$fs->remove($settings_generated);
$fs->dumpFile($settings_generated, file_get_contents($settings_default) . file_get_contents($settings_custom));
There's also a appendToFile method that seems way better than dumping a new file with dumpFile, but it was not working unfortunatly.

loading config class in start.php in Laravel

In start.php file in laravel4 ... have this code
$env = $app->detectEnvironment(function () {
$environmentList = array(
'staging' => Config::get('program.staging'),
'production' => Config::get('program.production'),
'development' => Config::get('program.development')
);
});
Fatal error: Class 'Config' not found in /var/www/vhosts/engine.domain.com/app/start.php on line 39
I was wondering how to load "Config" class before this ... in start file
What I was trying to do was loading different servers for staging and production for different partners based on url.
the way i was trying to do it created a paradox .. so I did this
$program = (object) include 'config/program.php';
$env = $app->detectEnvironment(function () use ($program){
$environmentList = array(
'staging' => array($program->staging),
'production' => array($program->production),
'development' => array($program->development)
);
});
just don't use the Config:: here ... store the values in a variable instead.

Laravel 4 Database configuration with $_ENV

I want to use Laravel Environment for my Database credential, I did this:
inside bootstrap\start.php :
$env = $app->detectEnvironment(array(
'local' => array('My_PC'),
'production' => array('server.example.com')
));
created .env.local.php on same directory where serve.php is, and inside this code:
return array(
'DATABASE_NAME' => 'laravel_db',
'DATABASE_USER' => 'root',
'DATABASE_PASSWORD' => '1234'
);
and inside app\config created a local\app.php file containing this code:
return array(
'debug' => true,
);
and inside the app\config\database.php for my secured mysql connection I did:
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => $_ENV['DATABASE_NAME'],
'username' => $_ENV['DATABASE_USER'],
'password' => $_ENV['DATABASE_PASSWORD'],
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
but I'm getting an error on the CLI:
{"error":{"type":"ErrorException","message":"Undefined index: DATABASE_NAME","file":"c:\\xampp\\htdocs\\Larave_project\\app\\config\\database.php","line":58}}
How to resolve this issue?
The hostname based env detection solution will only work on Unix type system.
It won't work on Windows.
In Laravel 4.2 you can detect environment this way:
$env = $app->detectEnvironment(function() {
if ($_SERVER['SERVER_NAME'] == "127.0.0.1") {
$domain = $_SERVER['HTTP_HOST'];
if (strpos($domain, 'localhost') !== FALSE || strpos($domain, "127.0.0.1") !== FALSE) {
die("Configure your local `hosts` file and go to address: http://{storeName}.local");
}
$len = strpos($domain, ".local");
if ($len !== FALSE) {
// will load .env.*.php
$len = strpos($domain, ".local");
$env = substr($domain, 0, $len);
return $env;
}
}
// will load .env.php
return 'production';
});
(this is bootstrap/start.php)
Then:
setup hosts file (in your operating system) to redirect mysuperstore.local to 127.0.0.1
go to URL like http://mysuperstore.local which loads .env.mysuperstore.php into $_ENV.
In configuration files (those placed in app/config/) refer to $_ENV. To see where $_ENV does come from take a look into documentation topic about "Protecting Sensitive Configuration".

Phpunit grabbing Doctrine2 configuration from unknown place

I am using ZF2 + Doctrine2 + PHPUNIT, when setting up Phpunit, it works fine for a basic test, however as soon as I try to run a test that invokes Doctrine2, I get:
PDOException: SQLSTATE[HY000] [1045] Access denied for user 'username'#'localhost' (using password: YES)
But, I have never specified "username" nor "localhost" nor any sort of password. In-fact, my application runs perfectly fine, and the configuration I have specifies completely different settings.
So where is PHPUnit getting those settings and how to fix it?
My global.php:
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
'params' => array(
'host' => '127.0.0.1',
'port' => '3306',
'user' => 'sbapp',
'password' => 'myp#ss',
'dbname' => 'root'
)
)
),
The Test:
class ApplicationControllerTest extends AbstractHttpControllerTestCase
{
protected $traceError = true;
public function setUp()
{
$this->setApplicationConfig(
include '../../../config/application.config.php'
);
parent::setUp();
}
public function testAuthActionCanBeAccessed()
{
$postData = new \stdClass();
$postData->username = "someAppUser";
$postData->password = "12345";
$postData = json_decode(json_encode($postData),true);
$this->dispatch('/auth', 'POST', $postData);
$response = $this->getResponse();
$this->assertResponseStatusCode(200);
$this->assertActionName('auth');
}
}
The relative paths used within the config on setUp when done incorrectly can seriously affect the loading of entities and so on. So I was chasing around the right path.. when calling phpunit from root..or from vendor..or from within the test folder, etc..
Solution:
Call it from project root, and leave the routes exactly as the main project are.

install kohana website on multiple servers

I have a Kohana 3.0.14 website that i want to put on multiple domains, having associated a virtual host each (different ips).
the difference between my websites is the configuration file and the boostrap file (where i set the language to be used).
All the sites are in production.
How can i 'breakup' the website, how can i include the files so that i would have all the kohana site in a single place, and the config and boostrap on every server, so that when i am fixing an error to be fixed on every site (every domain)?
thanks a lot!
You could do that by setting up an environment variable at the top of you index.php file. Then depending on this variable, you'll set the configuration variables, languages, etc. This is usually how I handle staging/live/local environments, and doing so allows you to keep all the code identical between the various installations.
For example, in index.php:
define("ENV", "staging")
Then in bootstrap.php:
$baseUrl = "http://defaultdomain.com/";
if (ENV == "staging") $baseUrl = "http://staging.somedomain.com/";
Kohana::init(array(
'base_url' => $baseUrl,
));
In database.php:
if (ENV == "live") {
$hostname = ...
$database = ...
$username = ...
$password = ...
} else if (ENV == "staging") {
$hostname = ...
$database = ...
$username = ...
$password = ...
}
return array
(
'default' => array
(
'type' => 'mysql',
'connection' => array(
'hostname' => $hostname,
'database' => $database,
'username' => $username,
'password' => $password,
'persistent' => FALSE,
),
'table_prefix' => '',
'charset' => 'utf8',
'caching' => FALSE,
'profiling' => TRUE,
)
If your hosting options are limited, your best bet is to choose the first primary domain and create an account using that. Then park more domains on top. Then simply get the URL to decide what language etc you want to use.

Categories