I have a Slim application, in the main Middleware I add some generic data to the model
middleware "call" method code
$app->view->set("auths",["user","poweruser"]);
In a controller method I want to push a value to the "auths" array of the view model, is there any way to access it in a faster way than this?:
controller method code
$data=$app->view->get("auths");
$data[]="newauth";
$app->view->set("auths",$data);
In short
No, you can't, but you could define your own view subclass if you want to wrap this functionality nicely.
Native Slim
I just checked out Slim's source code (which is really, really, .. Slim), and you are using its View object which wraps a Set object. Neither supplies this functionality, since the internal array isn't exposed and the all() and getData() methods don't return the internal array by reference, so this won't work:
$view->all()['auths'][] = 'newauth';
You can reach what you want directly with the following nasty one-liner:
$view->set('auths', array_merge($view->get('auths'), ['newauth']));
Roll your own View subclass
Much better would be to define your own custom view that makes this possible!
Define a custom view class
class CustomView extends \Slim\View
{
public function pushProperty($key, $value)
{
$array = $this->get($key);
$array[] = $value;
$this->set($key, $array);
}
}
Note: this method blindly assumes that the current value is an array. You will want to add some checks!
Assign it as the default view object in your Slim app when you create it.
$app = new Slim\Slim(array('view' => new CustomView()));
And start using it :)
$app->view->set("auths",["user","poweruser"]);
$app->view->pushProperty('auths','newauth'); // this will now work. Yay :)
Related
I have a small application developed with Laravel, and I would like to share a variable (a result from a remote service, cached ) across all the controllers.
I read about ViewComposer, but they only work is a view is rendered (makes sense), and my app has many json responses.
I know that I could traditionally extend my controllers from a BaseController, but I wonder if anybody knows a way to do that without relying on inheritance.
Put that result into an object that's responsible for the caching, that you can DI that class into the controller - either in the constructor, or the specific route methods.
( If you're using laravel's caching service, then you can inject that with no extra work. )
super basic example:
class CachedResult {
public function result() {
return 'woo! caching';
}
}
...
// in your controller...
public function someJsonRoute(CachedResult $result) {
$result->result();
}
...
// in your AppServiceProvider's register method
$this->app->singleton(CachedResult::class, function() { return new CachedResult; });
You can declare the variable and/or function for the remote service in the base controller.
And in a controller that extends the base controller, you could use it like this:
$this->varName;
I have a class, in this class I have a method that sets my array.
How can I get values of this array and use them from another method in same class?
This my class:
class HomeController extends Controller
{
private $tmp = array();
public function setValues(){
array_push($this->tmp,"blue","yellow");
print_r(array_values($this->tmp)); // It works well, I can see values.
}
public function getValues(){
print_r(array_values($this->tmp)); // It doesn't work - shows empty array.
// return $this->tmp also doesn't work - shows empty array.
}
}
How can I get values of this array?
I am not sure how controllers work in Laravel. However, if it is similar to other frameworks then the Controller is not a singleton. A new controller is potentially created for each request. This means that you are calling setValues(); on one instance of the class and getValues(); on another.
I am pretty sure you can configure Laravel to treat the Controller a singleton.
http://laravel.com/docs/5.0/container Shows how you can register your controller as a singleton if you need to.
It works! You need to call setter first, and then getter:
$o = new HomeController();
$o->setValues();
$o->getValues();
Check yourself again, please: https://ideone.com/UYAfxe
Currently I'm using a view-helper to help my debugging process. Basically I call this function and it checks if 1: I'm logged in as a developer by checking a Zend_Session_Namespace variable and 2: if the application is run in debug_mode using Zend_Registry. If both of them are true I show a number of different debug variables and any parameters I give the helper as input.
Originally this function was only intended to check that I got the right info in the objects assigned to the view, but I quickly discovered that it was useful in other places as well. At the moment the function works in controllers using $this->view, and I guess I could technically use something along new Zend_View(); or Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); to get a view-object in my models, but that is just plain ugly even if it's only for debugging.
So my question is: How can I rebuild this helper into a global function (usable in models, views and Controllers) and still be able to use the Zend_Session_Namespace and Zend_Registry objects, while (as far as possible) maintaining the MVC structure.
I think if you made a static class or a singleton class, you could have all of the desired functionality without breaking your MVC structure at all.
Consider the following simple class with one static function:
<?php
class My_DebugHelper
{
public static function dump()
{
$ns = new Zend_Session_Namespace('the_namespace'); // the namespace you refer to with the developer flag
$debug_mode = Zend_Registry::get('debug_mode');
if (!isset($ns->isDeveloper) || !$ns->isDeveloper || !$debug_mode) {
return;
}
foreach(func_get_args() as $arg) {
Zend_Debug::dump($arg);
}
}
protected function __construct() {}
protected function __clone() {}
}
This code gives you:
The ability to call from anywhere in your application (model, controller, helper, view etc)
All of the protections to prevent it from being executed when called out of context
A simple base that you can expand upon
Depending on your needs, at least one thing you could do is make it static so it could store some of the information rather than access it each call, or add additional methods or specialized parameters so you could pass a Zend_View object to it if necessary and have data injected into the view.
You could call it from anywhere in your application and pass one or more values to dump:
My_DebugHelper::dump($someVar, $this->view, $model->getCustId());
I'm not sure how/what your view helper displays data currently, but hopefully that will help you merge your view helper into the generic class that you can call anywhere.
I'm using the MVC pattern in my application.
Now I need the view object in a model.
I don't want to add the view as a parameter for my function in the model (since I need it in other functions as well). And I don't want to keep on passing it.
Should a add the view as an attribute for the constructor of the model?
Is there another way? Shouldn't I be needing the view object in the model in the first place?
What would be the preferred way of doing it?
Example:
Controller
function someAction()
{
$somemodel->add();
}
Model
class SomeModel()
{
function add()
{
if ($view->user) {
// do stuff
$this->mail();
} else {
// do other stuff
}
}
function mail()
{
Mailer::send($view->user->email, $this->getitems(), $view->layout);
}
function getitems()
{
return Items::getitems($view->user);
}
}
If you're really doing MVC, then you won't need the view in the model, because only the controller should have access to the view.
Looking at the code you've provided, I can tell one thing: the add() method should not reference $view in any way (even for accessing its properties). Instead, the model should be provided with the $view->user value from the controller. The same goes for the mail() method.
Consider fixing those issues. Otherwise, you'll get into something worse later on.
The model should be separate from the view. So, as mkArtak said, the controller should be the only thing that communicates with the view. Which then passes only the necessary information to the model.
As for the model, it should really only deal with the information that it understands.
i.e. if you had a Car model... you don't want to build it dependent on it's factory. If you did, you would have to change your code if you wanted to build it in different factory.
The controller is where you 'bake' everything prepare for render. By bake I mean you consider any passed in $_REQUEST params, make model API calls to get the data you need, and set template variables to be rendered. Your action, at the end of this process should make a call to a template (view) you choose in order to render the 'baked' template variables.
I have a controller which has several methods which should all share common informations. Let's say my URI format is like this:
http://server/users/id/admin/index
http://server/users/id/admin/new
http://server/users/id/admin/list
http://server/users/id/admin/delete
I need to retrieve some informations from the database for id and have them available for all methods instead of writing a line in each of them to call the model. How can I do this?
class users extends Controller {
private $mydata = array();
function users()
{
parent::Controller();
....
$this->mydata = $this->model->get_stuff($this->uri->segment(2));
}
function index()
{
$this->mydata; //hello data!
}
Here I simply hardcoded the array (which probably is a really bad idea). Nevertheless you can store the data in a codeigniter session if you need to. Codeigniter can store this data in a cookie (if it's total is less than 4kb) otherwise you can store bigger blobs of data in the database (see the docs on how to do this).
See: http://codeigniter.com/user_guide/libraries/sessions.html
Subsection: Saving Session Data to a Database
Here's some session exercise:
$this->session->set_userdata('mydata', $mydata);
....
$mydata = $this->session->userdata('mydata');
If this cannot be solved from CodeIgniters Hook mechanism, you could override the constructor method in your controller and call your own. Judging from their SVN repository you'd probably would do something like
class YourController extends Controller
{
function YourController()
{
parent::Controller();
$this->_preDispatch();
}
function _preDispatch()
{
// any code you want to run before the controller action is called
}
Might be that the call to preDispatch has to be before the call to parent. Just try it and see if it works. I didnt know they still use PHP4 syntax. Ugh :(
Based on your url structure, and the fact that codeignitor uses a MVC pattern, I'm assuming you're using mod_rewrite to format the url path into a query string for index.php. If this is the case, the value of "id" should be available at $_REQUEST['id'] at any point in the execution of the script...