I'm using Lumen with an existing PHP application.
There's a conflict in the global namespace. The existing app also have a DB class in the global namespace which is conflicting with the Lumen's DB class.
// in vendor/laravel/lument-framework/src/Appliction.php
public function withFacades()
{
Facade::setFacadeApplication($this);
if (! static::$aliasesRegistered) {
static::$aliasesRegistered = true;
class_alias('Illuminate\Support\Facades\App', 'App');
class_alias('Illuminate\Support\Facades\Auth', 'Auth');
class_alias('Illuminate\Support\Facades\Bus', 'Bus');
class_alias('Illuminate\Support\Facades\DB', 'DB');
...
}
}
If I change class_alias('Illuminate\Support\Facades\DB', 'LumenDB'); solves the problem for me, but I don't want to edit code in the vendor folder.
Is there anyway I can change it programmatically?
Alright. I think I have a workaround for now.
In the bootstrap/app.php uncomment or remove this lines
// $app->withFacades();
and replace with.
class_alias('Illuminate\Support\Facades\App', 'App');
class_alias('Illuminate\Support\Facades\Auth', 'Auth');
class_alias('Illuminate\Support\Facades\Bus', 'Bus');
class_alias('Illuminate\Support\Facades\DB', 'LumenDB');
...
...
class_alias('Illuminate\Support\Facades\Validator', 'Validator');
So we will register the facades manually instead of calling the withFacades() function.
The correct method in newer versions of Laravel/Lumen is to pass an array of "user aliases" as the second argument to the $app->withFacades() method.
$app->withFacades(
true, // $aliases parameter set to true (default)
[
'Illuminate\Support\Facades\DB' => 'LumenDB',
] // array of $userAliases
);
Related
I have been following a tutorial to develop a mvc using php.
In the framework all the configuration settings are stored in a Config.php(Config class) under App namespace. The properties are constant so If I want to access a property, I have to use the namespace first anywhere I want to access it. So now I can access it like below
Config::DB_NAME OR Config::DB_HOST
So, Is there any way I can define a global helper function say config() using which I can access those values?
Say, If I want to access DB_NAME , I would typeconfig('DB_NAME')
Also, If I want to define some other global helper functions, How can make it?
To make the question more clear. Take Laravel's hleper functions. There is a helper function config() which returns a value from various configuration files. Like config('app.name') will return the APP Name.
These helper functions can be accessed from anywhere, Vies, Models, and Controllers.
Here is what I think can be done.
I don't want to group the functions in a class, that way I have to use namespaces.
Maybe, I can use traits to group the functions.
But How to make it available in each class. I can use use Helpers, but then
How would I access the function from a view file which doesn't have a classs?
Any, idea or suggestion would be helpful.
Config.php
<?php
namespace App;
class Config
{
const DB_HOST = 'localhost';
const DB_NAME = 'mvc';
const DB_USER = 'root';
const DB_PASSWORD = '';
const SHOW_ERRORS = false;
}
The project is currently on github, If anyone want a look of the files structure can see here
Edit
Maybe I can have config.php file which just returns an associative array.
Yet I need a helper function to get the values from it. The file would be like this.
<?php
return [
'DB_HOST'=>'localhost',
'DB_NAME'=>'mvc',
'DB_USERNAME'=>'root',
'DB_PASSWORD' =>'',
];
Thanks to you all for your help and support.
I, finally, found a solution. It's working and good for now. Maybe there is some other way but It will work for me for now.
Here are the steps that I followed to solve it.
Defined all my configuration setting in a separate file called Configs.php This file just returns an associative array.
Configs.php
<?php
return [
'DB_HOST' => 'localhost',
'DB_NAME' => 'mvc',
'DB_USER' => 'root',
'DB_PASSWORD' => '',
'SHOW_ERRORS' => false
];
I used composer to autoload my Helpers.php file. I didn't give it any namespace so it is globally loaded.
Helpers.php (OLD)
<?php
if(!function_exists('config')) {
function config($key)
{
$config_array = include 'Configs.php';
if (array_key_exists($key,$config_array))
{
return $config_array[$key];
}
}
}
Helpers.php (Updated - Suggested by Magnus Erikkson)
<?php
if (!function_exists('config')) {
function config($key, $fallback = null)
{
static $config;
if (is_null($config)) {
$config = include 'Configs.php';
}
return array_key_exists($key, $config)
? $config[$key]
: $fallback;
}
}
Both files Config.php and Helpers.php are under App directory
and here is composer.json
{
"require": {
"twig/twig": "^2.0",
"phpmailer/phpmailer": "^6.0"
},
"autoload": {
"files": [
"app/helpers.php"
],
"psr-4": {
"Core\\":"Core/",
"App\\":"App/"
}
}
}
Now, I can access it in my controller like config('DB_NAME') and it is working!
How can I pass a dynamic dependency from one registered container definition to another? In this case, a generic Database object wants to inherit from a generic Config object. The twist is config is not static, but loaded depending on a given environment variable.
Config pertinent methods
public function __construct()
{
$configFile = 'example.config.yml';
$yamlParser = new Parser();
$reader = new Config\Reader($yamlParser);
$configYaml = $reader->parse(file_get_contents($configFile));
$config = new Config\Environment(getenv('SITE'), $configYaml);
$this->config = $config;
}
public function getEnvironmentConfig()
{
return $this->config;
}
Registering config is as simple as
$container->register('config', 'Config');
Database is currently added to the container as follows:
$container
->register('database', 'Database')
->addArgument($config->getEnvironmentConfig('Database', 'db.username'))
->addArgument($config->getEnvironmentConfig('Database', 'db.password'))
;
But I want to do something like
$container
->register('database', 'Database')
->addArgument(new Reference('config')->getEnvironmentConfig('Database', 'db.username'))
->addArgument(new Reference('config')->getEnvironmentConfig('Database', 'db.password'))
;
The $config in-PHP variable makes migrating from a PHP-built config impossible. I want to define the services in yaml force the container to:
Instantiate Config
Parse the config yaml file and create an environment-specific version
Return this on a call to getEnvironmentConfig
Is this possible?
This was solved by using the Expression Language Component
So you can easily chain method calls, for example:
use Symfony\Component\ExpressionLanguage\Expression;
$container->register('database', 'Database')
->addArgument(new Expression('service("config").getEnvironmentConfig("Database", "db.username")'));
I've written a simple display_messages() function that will search Session::get('errors') for flash data and echo it to the screen.
Where do I put this function? In Codeigniter, you had a helpers folder where you could stick all your little global helper methods.
As Usman suggested,
create a file /application/libraries/demo.php
define a class Demo() { inside it
call the function like so: {{ Demo::display() }}
Works because libraries and models are autoloaded in start.php line 76. I believe that filenames must match Classnames (note capital).
<?php
class Demo {
public static function display() {
if( !$message = Session::get('errors'))
$message = 'No Errors';
echo "<pre>print_r($message)</pre>";
}
}
Can't quite figure out why I had a problem using the classname Common, there may be a conflict (you could define a namespace if this were important)...
Create a folder helpers within your app folder and create a file application_helper.php. With such code:
// app/helpers/application_helper.php
function display_messages()
{
exit('Yes');
}
Then open your composer.json file in root. autoload app/helpers/application_helper.php with composer files.
"autoload": {
....
"files": [
"app/helpers/application_helper.php"
]
Done, you can now call display_messages().
Some autoloaders may require you to run composer dump command for the first time.
Thank you memeLab provided a very useful answer which helped me a lot. I just wanted to expand on his answer as the "libraries" folder was not an auto load directory, at least not in the release/current version of L4 I am using. Also the start.php seems to have been expanded to be the start folder with global.php, local.php, and artisan.php.
So to use your own classes for separate libraries or helpers with the L4 lazy auto loader you just have to include whichever folder you want to store these in to the global.php. For example I added a libraries folder to the directory list.
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
// this a custom path
app_path().'/libraries',
));
Then whatever class you define in that folder as classname.php can be called via CLASSNAME::methodName($someVar); in your controllers.
class CLASSNAME {
public static function methodName($someVar=NULL) {
// whatever you want to do...
return $message;
}
}
So in this fashion you can create a helper class and define different methods to use throughout your controllers. Also be careful defining regular functions outside of your Class in this manner will cause you grief because they will not work (because the class is not always loaded). (for example someFunctionName($someVar); instead of CLASSNAME::methodName($someVar);) If you want to create functions in this manner you would need to make sure the is loaded, however I will not elaborate on this because it is better practice to use the lazy loader classes for such things so you only load the classes you really need.
Thanks again to memeLab and Usman, I would not have gotten as far without their answers. :)
For loading Classes:
Create app/libraries/class/Message.php, and add class in file
class Message {
public static function display() {
}
}
Add "app/libraries/class" to composer.json
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/libraries/class"
]
},
Finally run composer dump-autoload in command line.
You can access that by Message::display()
For loading plain non-object php Functions:
Create app/libraries/function/display_messages.php, and add function in file
function display_messages() {
}
add one line in start/global.php
require app_path().'/libraries/function/display_messages.php';
You can access that just by display_messages()
Add this in app/start/global.php
require app_path().'/config/autoload.php';
require app_path().'/start/loader.php';
App::instance('loader',new loader($autoload));
create a new file loader.php in app/start and add:
class loader{
private $helpers = array();
public $autoload = array(
'helpers' => array()
);
function __construct($autoload = array()) {
if (!empty($autoload))
$this->autoload = $autoload;
foreach ($this->autoload as $key => $value)
{
$function = strtolower($key);
$this->$function($value);
}
}
function helpers($helpers=array())
{
if (!is_array($helpers))
$helpers = explode(",",$helpers);
foreach ($helpers as $key => $value) {
$this->helper($value);
}
}
function helper($helper = '',$path = '/')
{
$folder = app_path().'/helpers'.$path;
if (file_exists($folder.$helper.'.php') && !in_array($helper, $this->helpers)){
$this->helpers[] = $helper;
require $folder.$helper.'.php';
}
else{
$segments = explode('/',$helper);
if (is_dir($folder.$segments[0])){
array_shift($segments);
$this->helper($segments,$path.$segments[0].'/');
}
}
}
}
create a new file autoload.php in app/config and add:
$autoload['helpers'] = array('functions'); // my autoload helpers!
create a new folder helpers in app/ , add your helper files. ( es. myhelper.php )
function myhelper()
{
echo 'helper';
}
in your controller add:
App::make('loader')->helper('myhelper');
myhelper();
In L3, I would normally create a application/libraries/helpers.php file, and require_once() it in my application/start.php. Similar to how L3 has a laravel/helpers.php file.
I'm assuming there is something similar you can do in L4.
EDIT: Just looking at the source, app/start/local.php seems like it might be the place.
I used this tutorial and i think is the easiest method: http://laravel-recipes.com/recipes/50/creating-a-helpers-file
First create the file app/helpers.php
Then either load it at the bottom of app\start\global.php as follows.
// at the bottom of the file
require app_path().'/helpers.php';
Or change your composer.json file and dump the autoloader.
{
"autoload": {
"files": [
"app/helpers.php"
]
}
}
$ composer dump-auto
then you can write your functions in helpers.php and call them from anywhere
function myfunction($result){
return $result;
}
open root_folder/vendor/laravel/framework/src/Illuminate/Support/helpers.php
and you can add your function
if ( ! function_exists('display_messages'))
{
function display_messages()
{
return ...
}
}
I want to try db connection to check is db available. In zend I can place my code in boostrap file and wrap it in try catch.
How to implement this in yii?
Is in yii analog of zend boostrap?
UPD: db is mongo, yii extention for working with db is a directmongosuite
Seems that I find appropriate solution:
Need to prohibit auto connect in config file:
'components' => array(
'edms' => array(
'class' => 'EDMSConnection',
'dbName' => 'homeweb',
'server' => 'mongodb://localhost:27017',
'options' => array('connect' => false)
)
)
all controllers should extend one custom controller (BaseController for example).
Need to write own public function beforeAction method where I can add boostrap code.
class BaseController extends CController
{
public $layout = '//layouts/main';
public $navigationMenu = array();
public $breadcrumbs = array();
public function beforeAction($action)
{
try {
Yii::app()->edmsMongo()->connect();
} catch (Exception $e) {
die('Cannot connect to the database server. Please Try again later.');
}
$isGuest = Yii::app()->user->isGuest;
$this->navigationMenu = $this->_getNavigationMenu($isGuest);
return parent::beforeAction($action);
}
In the beforeAction method need to add return true or execute parent's method.
The bootstrap in yii is pretty much the index.php file under public_html or the yiic.php file (for command line applications).
You will probably have to separate the creating of the application instance and running it (by default it does both on 1 line), so you can do your try/catch between the calls.
Just try to fetch the app component, the mongo plugin will throw an exception if it can't open the connection:
try
{
Yii::app()->mongoDb;
}
...
or Yii::app()->getComponent('mongoDb');
I just started using a PHP framework, Kohana (V2.3.4) and I am trying to set up a config file for each of my controllers.
I never used a framework before, so obviously Kohana is new to me. I was wondering how I should set up my controllers to read my config file.
For example, I have an article controller and a config file for that controller. I have 3 ways of loading config settings
// config/article.php
$config = array(
'display_limit' => 25, // limit of articles to list
'comment_display_limit' => 20, // limit of comments to list for each article
// other things
);
Should I
A) Load everything into an array of settings
// set a config array
class article_controller extends controller{
public $config = array();
function __construct(){
$this->config = Kohana::config('article');
}
}
B) Load and set each setting as its own property
// set each config as a property
class article_controller extends controller{
public $display_limit;
public $comment_display_limit;
function __construct(){
$config = Kohana::config('article');
foreach ($config as $key => $value){
$this->$key = $value;
}
}
}
C) Load each setting only when needed
// load config settings only when needed
class article_controller extends controller{
function __construct(){}
// list all articles
function show_all(){
$display_limit = Kohana::config('article.display_limit');
}
// list article, with all comments
function show($id = 0){
$comment_display)limit = Kohana::config('article.comment_display_limit');
}
}
Note: Kohana::config() returns an array of items.
Thanks
If you are reading a group of configuration items for a controller, store them in class member ($this->config), if you are reading a single configuration item; read it individually.
I think first method (A) should be fine, it has lesser code and serves the purpose fine.
If you have site wide stuff that you want access to from "anywhere", another way of doing it may be to put something like:
Kohana::$config->attach(new Kohana_Config_File('global'));
in bootstrap.php. Then create global.php in the application/config directory with something like:
return (array ('MyFirstVar' => 'Is One',
'MySecondVar' => 'Is Two'));
And then when you need it from your code:
Kohana::config ('global.MyFirstVar');
But I suppose all of this comes down to where and how you want to use it.