PHP the right way to use constants with composer - php

I have a PHP library on packagist.org, which uses some constants, changing from project to project.
I'm trying to use constants like that:
Constants stores in conf.php in composer libriary
After composer init username/mylib command, I making a copy from /vendor/username/mylib/conf.php to local /conf.php and use it for current project config
for project1, in /conf.php
define("HOST", "host1.com");
project2, in /conf.php
define("HOST", "host2.com");
But it looks like a wrong way.
What is right way to use constants with composer libraries ?

I prefer to do this a slightly different way
in my libabry i would have
/vendor/vendorname/pkg/config/system.php
/vendor/vendorname/pkg/config/local.sample.php
and provide instructions to copy
/vendor/vendorname/pkg/config/local.sample.php
to
/config/local.php
then in my code I would have something like
$sysconffile = static::$vendorbasedir . '/config/system.php';
if (file_exists($sysconffile)) {
$sysconf = require $sysconffile;
} else {
throw new \RuntimeException('Sys Conf Missing!');
}
$localconf = [];
$localconfile = static::$appbasedir . '/config/local.php';
if (file_exists($localconfile)) {
$localconf = require $localconfile;
}
UPDATE:
I also prefer static classes with data over defines, as a define is very loose in documentation, type hinting and over-writable ..
So once i have both config's, I usually do
static::$config = array_replace_recursive($sysconf, $localconf);

Related

PHP getenv always returns false

The getenv() always returns false. I am using Symfony dotenv library and loading my variables from a .env file in the root of my project.
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\Dotenv\Exception\PathException;
if (!getenv('APP_ENV')) {
try {
(new Dotenv())->load(__DIR__ . '/../.env');
} catch (PathException $ex) {
echo $ex->getMessage();
exit(1);
}
}
var_dump(getenv('APP_ENV')); // bool(false)
But when I dump the super global I can see my variables
var_dump($_ENV); // array:1["APP_ENV" => "dev"]
So what am I missing?
I m not using symfony but i've encountered the some problem
i am using the vlucas library this is my first code that caused the problem
define('BASE_PATH',realpath(__DIR__.'/../../'));
require_once __DIR__.'/../../vendor/autoload.php';
$dotEnv = Dotenv\Dotenv::createImmutable(BASE_PATH);
$dotEnv->load();
$appName=$_ENV['APP_NAME'];
$appName2=getenv('APP_NAME');
var_dump($appName) // return "This is my website";
var_dump($appName2) // return false;
i didn't knwo the problem at first but it seems that it was because putenv() and getenv()
are not thread safe
so i changed it to this code
define('BASE_PATH',realpath(__DIR__.'/../../'));
require_once __DIR__.'/../../vendor/autoload.php';
$dotEnv = Dotenv\Dotenv::createUnsafeImmutable(BASE_PATH);// <======== :) look here
$dotEnv->load();
$appName=$_ENV['APP_NAME'];
$appName2=getenv('APP_NAME');
var_dump($appName) // return "This is my website";
var_dump($appName2) // return "This is my website";
i hope this resolves your issue
For Symfony 5.x+, in public/index.php
replace
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
with
(new Dotenv())->usePutenv()->bootEnv(dirname(__DIR__).'/.env');
This worked for me.
By default, Symfony doesn't use putenv() (I think it's for security reasons, don't remember exactly) so you are not able to use directly getenv() if you are using Symfony's "fake" environment variables.
The best solution in my opinion is to use dependency injection instead. You can access env vars in your Symfony configuration. For example with a yaml configuration file:
framework:
secret: '%env(APP_SECRET)%'
If you want to be able to use getenv() anyway, that I don't recommand for multiple reasons, you can do this :
Before Symfony 5.1 : In your config/bootstrap.php file -> new Dotenv(true)
Symfony 5.1 and later : public/index.php, add the following before Dotenv instantation-> Dotenv::usePutenv();
EDIT :
Using the putenv PHP function is not thread safe, that's why this setting defaults to false.
Didn't notice in the first place your using the Dotenv component as a standalone library, so you can ignore my advice concerning the dependency injection.
The reason is that using getenv() and putenv() is strongly discouraged due to the fact that these functions are not thread safe, however it is still possible to instruct PHP dotenv to use these functions. Instead of calling Dotenv::createImmutable, one can call Dotenv::createUnsafeImmutable, which will add the PutenvAdapter behind the scenes. Your environment variables will now be available using the getenv method, as well as the super-globals:
$s3_bucket = getenv('S3_BUCKET');
$s3_bucket = $_ENV['S3_BUCKET'];
$s3_bucket = $_SERVER['S3_BUCKET'];

How to properly add Red Bean PHP into my project

I'm not very experienced with php projects structure, I found this awesome and simple tutorial: https://arjunphp.com/creating-restful-api-slim-framework/ how to create simple slim rest app.
This is actually PHP SLIM's official project structure, my question is what is best and proper way to add and use RedBean php ORM, I dont want on every route to include something like this
use \RedBeanPHP\R as R;
R::setup( 'mysql:host=localhost;dbname=mydatabase', 'myusername', 'mypassword)
and then
$book = R::load( 'book', $id );
And then use ReadBean for my db stuff. Im wondering how to include RedBeans into project and then just use it where i need it. This is my project structure https://github.com/iarjunphp/creating-restful-api-slim-framework3.
Note: i added red beans via composer like its described here https://github.com/gabordemooij/redbean
You can put the code for setting up your libraries in any file that is going to be included on each request, so assuming you're using slim/slim-skeleton, src/dependencies.php is probably the place you want to add these two lines:
use \RedBeanPHP\R as R;
R::setup( 'mysql:host=localhost;dbname=njux_db', 'root', '');
Then you can use ReadBeans in your route callbacks but you also need to add the use \RedBeanPHP\R as R; statement to your src/routes.php as well (or any file that is going to use this class)
If you use a MVC framework (which I recommend) like codeigniter it's pretty easy.
You only have to copy your rb.php to the application/third_party folder.
Then create a file called application/libraries/rb.php containing a code like this one.
<?php
class Rb {
function __construct() {
include(APPPATH.'/config/database.php');
include(APPPATH.'/third_party/rb.php');
$host = $db[$active_group]['hostname'];
$user = $db[$active_group]['username'];
$pass = $db[$active_group]['password'];
$db = $db[$active_group]['database'];
R::setup("mysql:host=$host;dbname=$db", $user, $pass);
}
}
?>
...and vĂ´ila. RedBean will read your database configuration from CodeIgniter's standard file application/config/database.php and you will be able to use any R:: command from anywhere in your code. No includes, not additional code required :-)

Drupal 7 xautoload composer

So I have the Paypal REST API installed ( https://github.com/paypal/rest-api-sdk-php ) with Composer in my_drupal_module/lib/Drupal/ and now I want to use the namespaces in a function in my module. I understood that I need something like xautoload ( https://drupal.org/project/xautoload ) to do that so I tried something like:
$payer = new \Drupal\vendor\PayPal\Api\Payer;
with and without the first slash, and with and without parentheses at the end but it didn't work. I added:
require DIR . '/lib/Drupal/vendor/autoload.php';
but still nothing so I commented it. Meanwhile I found this: https://drupal.org/node/1976206 that explains this issue but it is unclear to me what exactly to write in hook_xautoload() or direct registration for the setup that I have. Can someone please help?
Nevermind. I solved it. Thanks to proloy03 who gave me the idea: https://drupal.org/node/2096621
You don't need xautoload to load the classes and namespace just implement hook_init to require it like so:
function my_module_init() {
require __DIR__ . '/vendor/autoload.php';
}
and then in your function write:
$payer = new PayPal\Api\Payer();
and it all works.
With xautload you can do something like this...
In mymodule.module
function mymodule_libraries_info() {
'paypal' => array(
'name' => 'PayPal SDK',
'xautoload' => function($adapter) {
$adapter->composerJson('composer.json');
}
}
Declaring this allow you to use the namespace. Like
use PayPal\Api\Amount;
Check xautoload.api.php
Your assumption that you need XAutoload to use the Paypal API installed by Composer is wrong.
The only thing you need to make any code installed by Composer available is to include the Composer autoloader in your code execution path when you need any of the provided classes. The easiest form of this is to simply require the Composer autoloader in the very first index.php (or whatever Drupal uses) file that answers every request (possibly instantiating more Drupal classes, modules and stuff).
Once the code execution comes to your own code, the autoloading allows your code to include all the classes you included with Composer.
How to use the code? Don't invent your own namespace for the existing code, it will not work. "\Drupal\vendor\PayPal\Api\Payer" sounds pretty wrong to me, I suspect the correct namespace is "\PayPal\Api\Payer". And yes, that file does indeed exist. So you have to use that.
If it still does not work, complaining the class could not be loaded, then the Composer autoloader file is not included in your scripts code path.

Yii console with different configs

In the web application we use same code and modules with different configs like:
in index.php file app will decide, wchin config to turn:
switch($_SERVER['HTTP_HOST']){
default:
$yii=$webRoot.'/framework/yiilite.php';
$config = $webRoot.'/protected/config/main.php';
break;
case 'someurl.com':
...
break;
...
}
But, how can I do it with console application?
The reason in that I use different databases ant etc.
is it possible to do something like this:
$ ./protected/yiic --application=myappname [all defined commands as default]
in the code a
--application
will set with which console config to work
more explanation
my answer to #Joe Miller
But the problem is, how choose theme?
I did in the files foloowings:
in protectes/yiic
$__appId = null;
for( $__i=1,$__max=count($argv); $__i<$__max; ++$__i ) {
if ( strpos($argv[$__i],'--appid',0) === 0 ) {
$__appId = substr($argv[$__i], 8);
unset($argv[$__i]);
}
}
require_once(dirname(__FILE__).'/yiic.php');
and in protected/yiic.php
$__appIdsList = array(
'my_site_1',
'my_site_2',
'my_site_3',
'my_site_4',
);
$yiic=dirname(__FILE__).'/../framework/yiic.php';
$config=dirname(__FILE__).'/config/console_'.$__appId.'.php';
require_once($yiic);
and it works and it catchs that config file what I need
./protected/yiic --appid=my_site_1
bu when I`m trying to do migrate
./protected/yiic --appid=my_site_1 migrate
the app cant recognize comman and gives me migrates help list
And final conslusion (I solved it)
I`d like to add transperent console command without affecting it to other execution of builtin console commands and custom console commands.
Another requirement is, solve this issue on a low-level approach, without inheritance or overloading other classes or methods.
So, my solution is:
in protected/yiic
#!/usr/bin/env php
<?php
$__appId = null;
for( $__i=1,$__max=count($argv); $__i<$__max; ++$__i ) {
if ( strpos($argv[$__i],'--appid',0) === 0 ) {
$__appId = substr($argv[$__i], 8);
unset($argv[$__i]);
unset($_SERVER['argv'][$__i]);
$argv = $_SERVER['argv'] = array_values($argv);
}
}
require_once(dirname(__FILE__).'/yiic.php');
and in /protected/yiic.php
<?php
// change the following paths if necessary
$__appIdsList = array(
'app_1',
'app_2',
);
$yiic=dirname(__FILE__).'/../framework/yiic.php';
$config=dirname(__FILE__).'/config/console_'.$__appId.'.php';
if ( !is_file($config) ) {
die("Error: There is no or wrong parametr appid. Please set parametr or correct. Example -appid={application_name}\n\tThe list of available appid:\n\t\t - ".implode("\n\t\t - ", $__appIdsList));
}
require_once($yiic);
and now it is possible to set param "appid" in any place of command line, like
./protected/yiic migrate --appid=app_1
and it acts only in that app what we need
PS: in any case, thanks #Joe Miller
Copy yiic.php for example to cron.php and modify the config file in the cron.php
then use as if it were yiic, for example:
cd ~/protected;php ~/protected/cron.php app command --param=value >> ~/runtime/crontab.log
If I've understood what you're trying to do correctly, I think you might need something like this. I've referred to this article http://www.yiiframework.com/doc/guide/1.1/en/topics.console#creating-commands. I've not tried this, so I'm just interpreting the article.
Create a base command class, from which you will extend all the other commands. The base class run() method selects the config file to load.
In protected>commands you need a file migrate.php. This must contain the class MigrateCommand, and must extend CConsoleCommand. You can then override the run() method of this class to allow parameters to be passed to the method. e.g.
In protected>commands>baseCommand.php
class MyBaseCommand extends CConsoleCommand{
public function run($args){
//Code here to select the config file to load
//$args are any arguments you have passed in the command line
}
}
In protected>commands>migrate.php
class Migrate extends MyBaseCommand{
public function run($args){
parent::run($args);
//Do your own stuff here
}
}
you should then be able to call the command as;
./protected/yiic migrate --appid=my_site_1
Note that the name of the command appears first, I'm not sure if this is important, but it's what the guide says! I hope I've understood your question this time!
I think, I founded more confortable solution!
It`s more easy, and solved all my requirements.
in the file
protected/yiic.php
I write:
...
$yiic=dirname(__FILE__).'/../lib/framework/yiic.php';
if ( strpos(__FILE__,{first/place}) !== false ) {
$config=dirname(__FILE__).'/config/first_config.php';
} elseif ( strpos(__FILE__,{second/place}) !== false ) {
$config=dirname(__FILE__).'/config/second_plase.php';
} else {
// by default
$config=dirname(__FILE__).'/config/console.php';
}
require_once($yiic);
...
where {first/place},{second/place} - a part of the project`s path. For example:
Your first project is placed in:
/var/www/aproject/first_one
and the second one on the
/var/www/aproject/second_one
than you checks will be:
// for first porject
strpos(__FILE__,'aproject/first_one') !== false
and etc.

Defining Application Constants in Codeigniter

I want to know a clean way of defining Application Constants in Codeigniter. I don't want to change any native file of codeigniter. Hence I don't want to define it in application/config/constants.php as when I need to migrate to newer version of code-igniter I will not be able to copy the native files of codeigniter directly.
I created a file application/config/my_constants.php and defined my constants there. 'define('APP_VERSION', '1.0.0');'
I loaded it using $this->load->config('my_constants');
But I am getting a error
Your application/config/dv_constants.php file does not appear to contain a valid configuration array.
Please suggest me a clean way of defining application level constants in code-igniter.
Not using application/config/constants.php is nonsense! That is the only place you should be putting your constants. Don't change the files in system if you are worried about upgrading.
just a complete answer. (None of the answers show how to use the constants that were declared)
The process is simple:
Defining a constant. Open config/constants.php and add the following line:
define('SITE_CREATOR', 'John Doe')
use this constant in another file using:
$myVar = 'This site was created by '.SITE_CREATOR.' Check out my GitHub Profile'
Instead of using define(), your my_constants.php file should look something like this:
$config['app_version'] = '1.0.0';
Be careful with naming the array key though, you don't want to conflict with anything.
If you need to use define(), I would suggest doing it in the main index.php file, though you will still need to use APP_VERSION to get the value.
config file (system/application/config/config.php) to set configuration related variables.
Or use
constant file (system/application/config/constants.php) to store site preference constants.
=======================
DEFINE WHAT YOU WANT
=======================
$config['index_page'] = 'home';
$config['BASEPATH'] = 'PATH TO YOUR HOST';
Please refer this:
http://ellislab.com/forums/viewthread/56981/
Define variable in to constants & add value on array
$ORDER_STATUS = array('0'=>'In Progress','1'=>'On Hold','2'
=>'Awaiting Review','3'=>'Completed','4'
=>'Refund Requested','5'=>'Refunded');
You can accomplish your goal by adding constants to your own config file, such as my_config.php.
You would save this file in the application/config folder, like this:
application/config/my_config.php.
It is very common to have a separate config file for each application you write, so this would be easy to maintain and be understood by other CI programmers.
You can instruct CI to autoload this file or you can load it manually, as needed. See the CI manual on "Config class".
Let me suggest that you use composer.json to autoload your own Constants.php file, like this:

Categories