pass function with argument to method call - php

I'm trying to use flight PHP framework for routing and medoo framework for database usage.
//connect database
$database = new medoo([
'database_type' => 'sqlite',
'database_file' => 'db.sqlite'
]);
//my function
function database($database){
$database->insert("ppl", [
"fn" => "joe","ln"=>"doe"]);
}
//
Flight::route('/add/', array(database($database)));
How to invoke my function with argument from this place:
Flight::route('/add/','database')
Tried different variants but getting errors.

I don't know medoo or flight, but you might be able to use an anonymous function with use:
Flight::route('/add/',
function() use($database) {
$database->insert("ppl", ["fn"=>"joe","ln"=>"doe"])
});
I think you need to re-architect this into an OOP style that will make it much easier and modular, but in a crunch if $database is defined in the global scope:
function database() {
$GLOBALS['database']->insert("ppl", ["fn"=>"joe","ln"=>"doe"]);
}
Flight::route('/add/', 'database');

Related

Using slim's Container::get('settings') versus accessing array directly

The following three approaches produce the same effect. Which approach should be used? Are there times one should be used over another?
function getConfig() {
$config=parse_ini_file(__DIR__.'/../config.ini',true);
$config['directories']['base']=dirname(__DIR__);
return $config;
}
$c = new \Slim\Container(['settings' => [
'displayErrorDetails'=>true,
'addContentLengthHeader'=>false,
'determineRouteBeforeAppMiddleware'=>true,
'config'=>getConfig()
]]);
$config=getConfig();
$c['pdo'] = function ($c) use($config){
$db1 = $c['settings']['config']['mysql'];
$db2 = $c->get('settings')['config']['mysql'];
$db3 = $config['mysql'];
return new \PDO(/* ... */);
};
Side note. Is it recommended to use a separate settings property for any application settings as I did with "config" to reduce the chance of conflicts with Slim's internal settings (i.e. httpVersion, responseChunkSize, outputBuffering, determineRouteBeforeAppMiddleware, displayErrorDetails, addContentLengthHeader, routerCacheFile)?
The get all settings just call the get() method like this:
$settings = $container->get('settings');

PHP Page Blank - Not understanding scopes

So, simply put, I feel like this code should work. Literally at this moment I am just trying to create a PHP class that takes in some information and runs a command against the database. I know the command works so it's not that, it something to do with the scope of my variables.
I'm new to PHP, and it's been interesting to handle.
<?php
require __DIR__ . '/../bin/composer/vendor/autoload.php';
$cx = new Customer();
$cx->WriteCxToDB();
class Customer {
public $database = new medoo([
'database_type'=>'mysql',
'database_name'=>'dbname',
'server'=>'localhost',
'username'=>'dbusername',
'password'=>'dbpassword',
'charset'=>'utf8'
]);
public function WriteCxToDB(){
global $database;
if($database->has("customer", [
"OR"=>[
"username"=>"cxusername",
"email"=>"email#gmail.com"
]
]))
{
echo "User already exists";
}else{
$database->insert("customer", [
"username"=>"username",
"keyword"=>"keyword",
"email"=>"email#gmail.com",
"phone"=>"444-444-4444",
"first_name"=>"First",
"last_name"=>"Last"
]);
echo "User added";
}
echo "Done";
}
}
?>
I am using composer and medoo to do this database entry. I know the database code works because I've ran it on it's own and it runs fine.
What I'm struggling with the seems to be the variable $database in the code. The function call works if I remove that variable from the mix. I feel like I'm just not understanding where I am supposed to declare the variable / how to reference it from within / outside the function. Thanks.
As suggested in the previous example you should be using something like this and pass a db connection into the class, extending a base class would allow reuse of the db connection:
private $database;
public function __construct($db_connection = null){
//do stuff or set db
$this->database = $this->db_connect;
}
OR make a method in the class to do it
private function db_connect(){
return new medoo([
// required
'database_type' => 'mysql',
'database_name' => 'name',
'server' => 'localhost',
'username' => 'your_username',
'password' => 'your_password',
'charset' => 'utf8',
]);
}
to check consider catching the errors. Using a unique or primary key on the DB would be a safer way of doing this otherwise you have to do validation and searching on the DB. Add the keys and check for duplicate errors.
if($database->error()){
//deal with return or pass to logging
}
The problem here is the use of global scope. Instead of:
global $database;
if($database->has("customer",
use
if($this->database->has("customer",
you could also consider instantiating $database in the constructor, i.e.
private $database;
public function __construct() {
$this->database = new medoo([args....

Call FluentPDO once

I am using slim framework together with FluentPDO query builder and this is what I'm currently doing:
$app->get('/song/remove/:songID', function($songID) use($app) {
$pdo = new PDO("mysql:dbname=songs", "root");
$fpdo = new FluentPDO($pdo);
$query = $fpdo->deleteFrom('songlist')->where('songID', $songID)->execute();
$app->flash('msg', 'Song ID '.$songID.' removed.');
$app->redirect('/');
});
$app->get('/song/view/:songID', function($songID) use($app) {
$pdo = new PDO("mysql:dbname=songs", "root");
$fpdo = new FluentPDO($pdo);
$song = $fpdo->from('songlist')->where('songID', $songID);
$app->render('view-song.html', [
'song' => $song //pass variable to template
]);
});
As you can see, I am calling this code in every function:
$pdo = new PDO("mysql:dbname=songs", "root");
$fpdo = new FluentPDO($pdo);
What I wanted to do is to just call it once, so that if I will change something in my database, I'll only change a single line. How can I accomplish that? THank you.
It depends on your project structure, the logic is to create a bootstrap or configuration file that will contains all your project constants (database connection, paths ...) that will be loaded by default in your entire application.
this video by codeschool may help setting up one:
https://www.youtube.com/watch?v=NFeWo1cqxnM
here is a project skeleton that you may consider:
https://github.com/slimphp/Slim-Skeleton
Hope it helps

Is there zend bootstrap analog in yii?

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');

Unable to access variable from included file

As the title says there is a problem accessing variable (associative array) inside class from included file. Here is the source code both class and include file:
require("applications/cw_database.php");
require("config/dbConfig.php");
require("config/appConfig.php");
class APP_ASSESMENTS
{
private $dbObj;
private $DisplayOutput = "";
public function __construct($PageParams)
{
try
{
$dbObj = new CW_DB($dbConfig['hostname'],$dbConfig['username'],$dbConfig['password'],$dbConfig['name'],$dbConfig['port']);
} catch (Exception $e) {
throw new ErrorException($e);
}
}
...
The other part has nothing to do with $dbConfig.
Also this is the included file (config/dbConfig.php):
/*
Testing configuration for MySQL database
*/
$dbConfig['username'] = "phpcoursework"; // changed on demand
$dbConfig['password'] = "phpcoursework"; // changed on demand
$dbConfig['hostname'] = "localhost"; // changed on demand
$dbConfig['name'] = "students"; // changed on demand
$dbConfig['port'] = 3306; // default for MySQL
First, $dbObj will not automatically assume class member scope, it will create a local copy of CW_DB and discard it when __construct returns. You need to explicitly reference the property;
$this->dbObj = ...
Anyway, global state using global as suggested by others will "work", but if you're using OOP practices you're best not to do that. You can actually return from an include(), so an option would be to do the following:
// your config file dbConfig.php
return array(
'username' => "phpcoursework",
'password' => "phpcoursework",
'hostname' => "localhost",
'name' => "students",
'port' => 3306,
);
And inject it into the object, via constructor or method (here's constructor)
class APP_ASSESMENTS
{
private $dbObj;
public function __construct($dbConfig, $PageParams)
{
$dbObj = new CW_DB($dbConfig['hostname'], $dbConfig['username'],
$dbConfig['password'], $dbConfig['name'], $dbConfig['port']);
// ...
}
}
// include() here, will actually return the array from the config file
$appAssesments = new \APP_ASSESMENTS(include('dbConfig.php'), $PageParams);
It would be recommended that you go another level up: instead, inject the database object itself, taking the dependency out of your APP_ASSESSMENTS class.
(Also, PascalCase is the typical convention of class naming, such as AppAssessments and CwDb)
$dbObj = new CwDb(include('dbConfig.php'));
$appAssessments = new AppAssessments($dbObj, $etc, $etc);
This simple change allows you to remove the dependency from AppAssessments on CwDb. That way, if you extend CwDb for some reason, you can just pass in an instance of the extended class without having to change any code in AppAssessments
You can change the AppAssessments constructor like so:
public function __construct(CwDb $db, $etc, $etc){
$this->db = $db;
// ...
}
This takes advantage of PHPs (limited, albeit still useful) type-hinting, ensuring the first argument is always of the correct type.
This plays into part of the open/closed principle: classes should be open to extension but closed for modification.
Includes are used in the scope of access. So, to access the variables you need to include the files within your class. As earlier mentioned global will let you access variables from another scope too. But global should be used with caution! See the documentation.
See the manual for more information.
Edit: I need to make it clear that globals are never a good alternative for handling these kind of critical variables..
public function __construct($PageParams){
global $dbConfig;
try{
$dbObj = new CW_DB($dbConfig['hostname'],$dbConfig['username'],$dbConfig['password'],$dbConfig['name'],$dbC onfig['port']);
} catch (Exception $e) {
throw new ErrorException($e);
}
}
or you could use $GLOBALS['dbConfig'].

Categories