How can i define a global variable such that my current_user method can work were ever i want it to, all i simple need to do is check if there is a current user my example code is below
if (isset($_SESSION['company_id'])) {
$current_user = Companies::find($_SESSION['company_id']);
}
else
{
$current_company = null;
}
how can i use the current user method where ever i want without passing it to my app->render() method just like in my header.html
{% if current_user %}
hi {{current_user.name}}
{% endif %}
You can inject a value into the app object:
$app->foo = 'bar';
More on Slim’s documentation.
Injection is not working in the callback function.
To have access to the variable in a callback function you can use "use() " function :
$mydata = array ( ... );
$app->get('/api', function(Request $request, Response $response) use($mydata) {
echo json_encode($mydata);
});
Inject the object it like this:
$app->companies = new Companies();
You can also inject it as a singleton if you want to make sure its the same one each time:
$app->container->singleton('companies', function (){
return new Companies();
});
The call it like this:
$app->companies->find($_SESSION['company_id']);
UPDATE DOC LINK:
Slim Dependency Injection
The accepted answer does not work for Slim 3 (as the hooks have been removed).
If you are trying to define a variable for all views and you are using the PhpRenderer, you can follow their example:
// via the constructor
$templateVariables = [
"title" => "Title"
];
$phpView = new PhpRenderer("./path/to/templates", $templateVariables);
// or setter
$phpView->setAttributes($templateVariables);
// or individually
$phpView->addAttribute($key, $value);
i was finally able to get it to work with this
$app->hook('slim.before.dispatch', function() use ($app) {
$current_company = null;
if (isset($_SESSION['company_id'])) {
$current_company = Company::find($_SESSION['company_id']);
}
$app->view()->setData('current_company', $current_company);
});
With twig/view
creating a middleware
<?php
namespace ETA\Middleware;
class GlobalVariableMiddleware extends Middleware {
public function __invoke($request, $response, $next) {
$current_path = $request->getUri()->getPath();
$this->container->view->getEnvironment()->addGlobal('current_path', $current_path);
return $next($request, $response);
}
}
Related
Does anyone know if it's possible to make use of URL query's within Laravel.
Example
I have the following route:
Route::get('/text', 'TextController#index');
And the text on that page is based on the following url query:
http://example.com/text?color={COLOR}
How would I approach this within Laravel?
For future visitors, I use the approach below for > 5.0. It utilizes Laravel's Request class and can help keep the business logic out of your routes and controller.
Example URL
admin.website.com/get-grid-value?object=Foo&value=Bar
Routes.php
Route::get('get-grid-value', 'YourController#getGridValue');
YourController.php
/**
* $request is an array of data
*/
public function getGridValue(Request $request)
{
// returns "Foo"
$object = $request->query('object');
// returns "Bar"
$value = $request->query('value');
// returns array of entire input query...can now use $query['value'], etc. to access data
$query = $request->all();
// Or to keep business logic out of controller, I use like:
$n = new MyClass($request->all());
$n->doSomething();
$n->etc();
}
For more on retrieving inputs from the request object, read the docs.
Yes, it is possible. Try this:
Route::get('test', function(){
return "<h1>" . Input::get("color") . "</h1>";
});
and call it by going to http://example.com/test?color=red.
You can, of course, extend it with additional arguments to your heart's content. Try this:
Route::get('test', function(){
return "<pre>" . print_r(Input::all(), true) . "</pre>";
});
and add some more arguments:
http://example.com/?color=red&time=now&greeting=bonjour`
This will give you
Array
(
[color] => red
[time] => now
[greeting] => bonjour
)
Query params are used like this:
use Illuminate\Http\Request;
class ColorController extends BaseController{
public function index(Request $request){
$color = $request->query('color');
}
public function fetchQuery(Request $request){
$object = $request->query('object');
$value = $request->query('value');
}
I want to perform CRUD operations through REST, I am implementing this in codeigniter, The code whatever I pasted here is working, but I have to handle a way to fetch all the datas from the database and also a way to fetch the data by id. Is there any best way to do this?
Backbone.js
(function(){
Backbone.emulateHTTP = true;
//Backbone.emulateJSON = true;
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
App.Models.Task = Backbone.Model.extend({
defaults: {
title: '',
done: 0
},
urlRoot: 'index.php/taskController/task'
});
})();
Controller
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
class taskController extends REST_Controller {
public function task_get($id){
$this->load->model('Task', 'task');
$data['task'] = $this->task->findbyid($id);
}
public function tasks_get(){
$this->load->model('Task','task');
$data['task'] = $this->task->find();
$this->response($data,200);
}
public function task_put($id)
{
# code...
$this->load->model('Task', 'task');
$data = json_decode(file_get_contents('php://input'), true);
// $data['title'] = $var['title'];
// $data['done'] = $var['done'];
echo var_dump($data);
$data['task'] = $this->task->updatebyid($id,$data);
//$this->response($data,200);
}
public function task_delete($id){
$this->load->model('Task','task');
$data['task'] = $this->task->delete($id);
}
public function task_post(){
$this->load->model('Task','task');
$data = json_decode(file_get_contents('php://input'),true);
return $data['task'] = $this->task->create($data);
}
}
I use /get/id for the items and /list/number_to_show/limit
So add a list_get($number, $limit)
method
if code for a /get/id is no id is passed, Send the entire lot ?
The principle of REST is that the CRUD actions are represented by the HTTP verbs. GET = select, PUT = update, POST = create and DELETE = delete.
You use nouns in your URL to represent your resources (e.g. tasks).
From your CI code it looks like you use always GET and have verbs+nouns in your URLs.
In REST, to get all tasks you would need to do GET http://example.com/tasks. To get one specific task you would need to do GET http://example.com/tasks/1234
Please read http://info.apigee.com/Portals/62317/docs/web%20api.pdf to understand the principle.
newbie in laravel.
In laravel sample routing
Route::get('books/{genre}', 'controller#method');
The link would be something like this
link.com/books/crime or link.com/books/programming
how do i do it if I want to get both genre?
if this possible is to achieve
link.com/books?genre=crime,programming
how do i write that in routes? and also how do i get the value in controller?
I have tried something like this. But I don't have any idea how to achieve it.
Route::get('books?{genre?}', 'controller#method');
Controller part
function method($fields = null) {
return jsonData;
}
Found a way but its kinda awful...
route
Route::get('books', 'controller#method');
url
link.com/books?genre=crime,programming,love,religion
method
function method() {
$array = explode(',',$_GET['fields');
//.....
return jsonData;
}
there are few ways you can achieve that.
if want to achieve,
http://link.com/books/crime/programming
or
http://link.com/books/crime
you can use the following routes:
Route::get('books/{genre}/{genreOptional?}', function($genre, $genreOptional = null)
{
dd($genre, $genreOptional);
});
or
Route::get('books/{genre}/{genreOptional?}', 'controller#method' );
Your controller:
public function method($genre, $genreOptional = NULL)
{
//
}
I want a global array that I can access through controller functions, they can either add or delete any item with particular key. How do I do this? I have made my custom controller 'globals.php' and added it on autoload library.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$notification_array = array();
$config['notification'] = $notification_array;
?>
following function on controller should add new item to my array
function add_data(){
array_unshift($this->config->item('notification'), "sample-data");
}
after add_data adds to the global array, whenever following function is called from client, it should give the updated array to the client.
function send_json()
{
header('content-type: application/json');
$target = $this->config->item('notification');
echo json_encode($target);
}
But my client always gets empty array. How can I make this happen? Please help.
Hi take advantage of OOP, like this
// put MY_Controller.php under core directory
class MY_Controller extends CI_Controller{
public $global_array = array('key1'=>'Value one','key2'=>'Value2'):
public function __construct() {
parent::__construct();
}
}
//page controller
class Page extends MY_Controller{
public function __construct() {
parent::__construct();
}
function send_json()
{
header('content-type: application/json');
$target = $this->global_array['key1'];
echo json_encode($target);
}
}
One solution I came up is to use session, its easy to use and its "fast" you need to do some benchmarking.
As I commented on both answers above/below there is no way you get same data in different controllers just because with each request everything is "reset", and to get to different controller you need to at least reload tha page. (note, even AJAX call makes new request)
Note that sessions are limited by size, you have a limit of 4kb (CodeIgniter stores session as Cookie) but wait, there is way around, store them in DB (to allow this go to config file and turn it on $config['sess_use_database'] = TRUE; + create table you will find more here)
Well lets get to the answer itself, as I understand you tried extending all your controllers if no do it and place some code in that core/MY_Controller.php file
as follows:
private function _initJSONSession() { //this function should be run in MY_Controller construct() after succesful login, $this->_initJSONSession(); //ignore return values
$json_session_data = $this->session->userdata('json');
if (empty($json_session_data )) {
$json_session_data['json'] = array(); //your default array if no session json exists,
//you can also have an array inside if you like
$this->session->set_userdata($ses_data);
return TRUE; //returns TRUE so you know session is created
}
return FALSE; //returns FALSE so you know session is already created
}
you also need these few functions they are self explainatory, all of them are public so you are free to use them in any controller that is extended by MY_Controller.php, like this
$this->_existsSession('json');
public function _existsSession( $session_name ) {
$ses_data = $this->session->userdata( $session_name );
if (empty( $ses_data )) return FALSE;
return TRUE;
}
public function _clearSession($session_name) {
$this->session->unset_userdata($session_name);
}
public function _loadSession($session_name) {
return (($this->_existsSession( $session_name )) ? $this->session->userdata($session_name) : FALSE );
}
the most interesting function is _loadSession(), its kind of self explainatory it took me a while to fully understand session itself, well in a few words you need to get (load) data that are in session already, do something with it ([CRUD] like add new data, or delete some) and than put back (REWRITE) all data in the same session.
Lets go to the example:
keep in mind that session is like 2d array (I work with 4+5d arrays myself)
$session['session_name'] = 'value';
$session['json'] = array('id' => '1', 'name' => 'asok', 'some_array' => array('array_in_array' => array()), 'etcetera' => '...');
so to write new (rewrite) thing in session you use
{
$session_name = 'json';
$session_data[$session_name] = $this->_loadSession($session_name);
//manipulate with array as you wish here, keep in mind that your variable is
$session_data[$session_name]['id'] = '2'; // also keep in mind all session variables are (string) type even (boolean) TRUE translates to '1'
//or create new index
$session_data[$session_name]['new_index'] = FALSE; // this retypes to (string) '0'
//now put session in place
$this->session->set_userdata($session_data);
}
if you like to use your own function add_data() you need to do this
well you need to pass some data to it first add_data($arr = array(), $data = ''){}
eg: array_unshift( $arr, $data );
{
//your default array that is set to _initJSONSession() is just pure empty array();
$session_name = 'json';
$session_data[$session_name] = $this->_loadSession( $session_name );
// to demonstrate I use native PHP function instead of yours add_data()
array_unshift( $session_data[$session_name], 'sample-data' );
$this->session->set_userdata( $session_data );
unset( $session_data );
}
That is it.
You can add a "global" array per controller.
At the top of your controller:
public $notification_array = array();
Then to access it inside of different functions you would use:
$this->notification_array;
So if you want to add items to it, you could do:
$this->notification_array['notification'] = "Something";
$this->notification_array['another'] = "Something Else";
I have come up with the following bits of code to call a method via AJAX in my PHP classes:
PHP:
class Ajax extends Controller {
private $class;
private $method;
private $params;
function __construct()
{
$this->params = $_POST; // Call params
$call = explode('->', $this->params['call']);
$this->class = new $call[0]; // e.g. controller->method
$this->method = $call[1];
array_shift($this->params);
$this->parse();
}
public function index()
{
//Dummy
}
public function parse()
{
$r = '';
$r = call_user_func_array(array($this->class, $this->method), $this->params);
echo $r;
}
}
Client:
function creditCheck2(id)
{
$.post(ROOT + 'Ajax', {call: 'Record->creditState', id: id, enquiryid: enquiryId}, function(data) {
alert(data)
}, 'json')
}
It seems to work great, but is it secure and could it be better?
Just for reference, I have added my code with the changes suggested by the answers:
class Call extends Controller {
private $class;
private $method;
private $params;
private $authClasses = array(
'Gallery'
);
function __construct()
{
$this->params = $_POST; // Call params
$call = explode('->', $this->params['call']);
if(!in_array($call[0], $this->authClasses))
{
die();
}
$this->class = new $call[0]; // e.g. controller->method
$this->method = $call[1];
unset($this->params['call']);
$this->parse();
}
public function parse()
{
$r = '';
$param = array();
// Params in any order...
$mRef = new ReflectionMethod($this->class, $this->method);
foreach($mRef->getParameters() as $p) {
$param[$p->name] = $this->params[$p->name];
}
$this->params = $param;
if($r = #call_user_func_array(array($this->class, $this->method), $this->params))
{
echo $r;
}
else {
}
}
}
Small issues
It could be better in that array_shift($this->params) unnecessarily assumes that the first item in the params array will always be call. That's not true and it does not agree with the direct access $this->params['call'] you are doing a little earlier. The array_shift should be replaced with simply unset($this->params['call']).
Bigger issues
There is also the problem that the order of values in the params array must match the order of parameters in the signature of the method you are trying to call. I don't think there is a guarantee that the order will be the same as the order of the parameters in the AJAX request, so that's a theoretical problem.
VERY big problem
More importantly, this way of doing things forces the author of the AJAX code to match the order of parameters in the signature of the method you are trying to call. This introduces a horrible level of coupling and is a major problem. What's worse, changing the order of the parameters by mistake will not be apparent. Consider:
public function bankTransfer($fromAccount, $toAccount, $amount);
$.post(ROOT + 'Ajax', {
call: 'Bank->bankTransfer',
from: "sender",
to: "recipient",
amount: 42
}, function(data) { ... });
This would work. But if you do this
$.post(ROOT + 'Ajax', {
call: 'Bank->bankTransfer',
to: "recipient", // swapped the order of
from: "sender", // these two lines
amount: 42
}, function(data) { ... });
You will get the opposite result of what is expected. I believe it's immediately obvious that this is extremely bad.
To solve the problem you would have to use reflection to match the array keys in $this->params with the formal names of the parameters of the method being called.
Security
Finally, this code is insecure in that anyone can make a request that directs your code to call any method of any class with the appropriate parameters -- even methods that should not be accessible from a web environment.
This is another serious problem and cannot really be fixed unless you introduce some type of filtering to the dispatch logic.
It seems to work great, but is it secure and could it be better?
Are you using your own framework or using other framework? I believe that it isn't secure at all, if the attacker know what might be inside your framework. For example: there is database class in your framework, attacker can do the following:
{call: 'Database->execute', sql: 'SELECT * FROM information_schema.`tables`'}
Filtering
You can limit the number of class that you allow user to access. For example:
if (!in_array($this->class, array('Record', 'Hello'))) {
die();
}
Reflection
This is sample of reflection that I just learn (Thanks to #Jon for the reference). This solve the problem of passing argument in different order from the PHP function.
class Email
{
public function send($from, $to, $msg) {
return "Send $from to $to: $msg";
}
}
$rawParam = array('msg' => 'Hello World',
'to' => 'to#gmail.com',
'from' => 'from#gmail.com');
$param = array();
// Rearrange
$methodRef = new ReflectionMethod('Email', 'send');
foreach($methodRef->getParameters() as $p) {
$param[$p->name] = $rawParam[$p->name];
}
var_dump($rawParam);
var_dump($param);