Zend Framework - Use data collected from database in multiple actions - php

If I want to gather some data from the database and use it in multiple actions of a controller, how would I do this?
Currently I just access the model and retrieve the data separately in each action (yes, I know this is inefficient... it's why I'm asking you all!):
public function indexAction()
{
$model = $this->_getStuffModel();
$this->view->results = $model->fetchEntries();
}
public function anotherAction()
{
$model = $this->_getStuffModel();
$foo = $model->fetchEntries();
foreach($foo as $k => $v)
{
//manipulate the data
}
$this->_helper->json($theoutput);
}
If I were not doing this in Zend Framework I would just put it in the constructor and then be good to go with $this->whatever in any method of the object but I don't see how to do this in ZF (I tried sticking it in init() but it didn't work... maybe I just made a stupid coding error and that is actually the correct place to do this?).
*EDIT: If I have, say, 7 actions in a controller and I put the code that hits the database in the init() method then I will hit the database with each and every action that is called. That won't do.

The init() Action is called on every request against the controller. If you do:
protected $model;
public function init()
{
$this->model = $this->_getstuff();
}
public function indexAction()
{
echo $this->model->name;
}
than it should work.

I think the #ArneRie init() solution is what you want.
Another solution will be to cache the Zend_Db_Rowset object with all the entries using Zend_Cache and serve it from cache. You can hit the database only when new data is added ( and the save function can register an observer that will delete related cache entries), or maybe each 10 minutes ( and you check the timestamp of the cache entry) or another business logic of your choosing.

Related

Php Yii: parameter passing to action vs load model in action

I'm trying to optimize my code, and i can't decide on what to use, and whichever is the best practice.
I have a view say view1.php, that is rendered by an action. Now view1 contains a model $model that was passed on to the view by its action; now i'm using the $model again to use it in another different action like below:
view1.php:
$studyDetails = $this->actionStudyDetails($model);
and in the StudyDetails action, i'm going to use the $model,
StudyController.php:
public function actionStudyDetails($model){
//do some processing of the model here and return an object
}
My question is, is it a good idea to pass an entire object that's already been loaded, supposing the model is very large? in terms of optimization , or probably best practice?
or should i just pass the id or primary key say $model->id? and then load the model after; making my action like this:
StudyController.php:
public function actionStudyDetails($id){
$model = $this->loadModel($id);
//do some processing of the model here and return an object
}
Should i pass the entire object unto the action or is it best to just reload the model once inside the action? Thanks, i hope i explained it well
I much prefer loading that single row the database. It's an optimization I wouldn't worry about until it becomes an issue.
You can store the model in your controller to prevent running the same query multiple times:
// Store model to not repeat query.
private $model;
protected function loadModel( $id = null )
{
if($this->model===null)
{
if($id!==null)
$this->model=SomeModel::model()->findByPk($id);
}
return $this->model;
}
It's a trick I learned here.

Initializing View, Template and Controller and Model is optional

I was too sleepy when I asked the question, so sorry for that, anyway to make things clear I prepared the question for 2 hours.
I'm trying to organize my code and decided to organize it mvc'ish(mvc-like), I don't know if I can follow all the principles, but I wanted to be at least close to that.
My application has a front-controller (dunno if my definition is right), so that all the http-request of my application will be passing through a single point, in my case the index.php in the root directory of my application.
Having said that I have set it up like that, you can imagine that I used .htaccess to direct all request to index.php.
I exploded the url and created an array out of it, $url[] like so. So whenever I access my app like this http://localhost/app/pagename it'll be accessing a controller (pagename_controller)
I did it like this :
$file = $controller_path . $page . '_controller.php';
if (file_exists($file)) {
require $file;
$class_name = ucfirst($page) . '_controller';
$target = new $class_name();
}
also I wrap it up in a Container, the 'decorator pattern', for future use, validations maybe.
like this :
$controller = new Wrap($target);
$controller->index();
I don't know if the use of $controller variable name is appropriate so please forgive me when it is all wrong.
I kinda think that I can setup my application like this :
user sends a request, how? by using the application means that he/she sends out a http-request, that will load the initial state of the application
As you can see in the diagram of my desired application structure, I was able to do only the first part which is to direct the request to a single entry (index.php)
Now the problems are the initialization of other parts of the application.
As of this moment, I have 3 files that I want to setup, but I am confused on how.
index_controller, index_view, Template
class Index_controller {
private $model;
private $view;
public function __construct(){
// optional model -> $this->model = 'index'
$this->view = 'index' //
}
public function index(){
$this->load->view($this->view)
}
}
class Index_view {
private $model;
private $template;
public function __construct(Model $model = null){
$this->template = new Template('default');
}
public function view() {
$this->template->assign('css', 'default_css'); // don't know if this is efficient
// or $this->template->assign('header', 'default_header');
// or $this->template->assign('sidebar', 'default_sidebar');
// or $this->template->assign('footer', 'default_footer');
// or any other things I want to use in the template
}
}
class Template {
public $data = array();
private $tmpl;
public function __construct($template) {
$this->tmpl = $template . '_tmpl.php';
}
public function assign($name, $value){
$this->data[$name] = $value;
}
// public function output
// function that will explode the data array and render it out as a webpage
// I'll create templates and
}
With that at hand, I want to know now how do I link those things together. At the moment I have a system folder that can contain classes, and I setup a autoloader for that folder.
I am thinking of creating a Controller class and View class that acts as the ActionFactory and ViewFactory as illustrated in the diagram, although I know that these are not their responsibilities.
I am thinking of this :
class Controller {
protected $load;
public function __construct() {
$this->load = new View();
}
}
class View {
public function __construct() {
// some things i don't know
}
public function view() {
// some things i don't know
}
}
What are your suggestions and comments in my setup. How can I initiate the triad?
Well, let's not get stuck on your implementation details too much. You can go read about securing your framework at some other time. Let's deal with your question...
I actually created a framework that works along the lines you are trying to implement. I think what you are missing is a RoutingHandler class. Routing is the physical manipulation of the URL, which tells your application which Controller to load, and which Action to run.
In my world I also have Modules, so the basic routing scheme is
Module -> Controller -> Action
These three items map to my URI scheme in that fashion. Variables can be appended also like so...
http://www.domain.com/module/controller/action/var1/val1/var2/val2
So, what happens after the URI is parsed, and control is passed over to the appropriate controller and action? Let's make some code up to demonstrate a simple example...
<?php
class indexController extends Controller {
protected function Initialize() {
$this->objHomeModel = new HomeModel;
$this->objHeader = new Header();
$this->objFooter = new Footer();
$this->objHeader
->SetPageId('home');
}
public function indexAction() {
$this->objHeader->SetPageTitle('This is my page title.');
}
}
?>
In the Initialize method, I'm setting some controller-wide stuff, and grabbing an instance of my Model to use later. The real meat is in the indexAction method. This is where you would set up stuff to use in your View. For example...
public function randomAction() {
$this->_CONTROL->Append($intSomeVar, 42);
}
_CONTROL is an array of values that I manipulate and pass onto the View. The Controller class knows how to find the right template for the View because it is named after the Action (and in a sibling directory).
The Controller parent class takes the name of the action method and parses it like so...
indexAction -> index.tpl.php
You can also do some other fun stuff here, for example...
Application::SetNoRender();
...would tell the Controller not to render inside a template, but just complete the method. This is useful for those situations where you don't actually want to output anything.
Lastly, all of the controllers, models, and views live inside their own directory like so...
my_module
controllers
indexController.class.php
someotherController.class.php
:
:
models
HomeModel.class.php
:
:
templates
index.tpl.php
someother.tpl.php
:
:
I could go on, but I'm writing this from memory, and there are some wrinkles here and there, but hopefully this gives you food for thought.

PHP views relate controllers

I would like to implement controllers that connect to any specific views like MVC does. I'm not using any framework that provided in PHP.
So, I need some guide and advice on doing it.
I have some controllers and views. For my views,i would like to just output my data only.
My concern now is how my function (like create() ) in controllers, can get all the $_POST['params'] that users input data in my views/create.php, and create a new Model in the create() controllers's function.
So,right now, i'm thinking to do in this way, I will create MyViews class in my controllers folder. The purpose is loading the specific views and get all the $_POST params into an object. Then, every controllers like Users_controllers, will create MyViews. In the function of Users_controllers, like create(), destroy(), I might use the function in MyViews to load specific views to load the object.
I found a source that load views
<?php
class MyView {
protected $template_dir = 'templates/';
protected $vars = array();
public function __construct($template_dir = null) {
if ($template_dir !== null) {
// Check here whether this directory really exists
$this->template_dir = $template_dir;
}
}
public function render($template_file) {
if (file_exists($this->template_dir.$template_file)) {
include $this->template_dir.$template_file;
} else {
throw new Exception('no template file ' . $template_file . ' present in directory ' . $this->template_dir);
}
}
public function __set($name, $value) {
$this->vars[$name] = $value;
}
public function __get($name) {
return $this->vars[$name];
}
} ?>
hmm,I have no idea How I can detect the _POST params
if(isset($_POST['Post']))
{
$model->attributes=$_POST['Post'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
this is the Yii framework I observed. How could I detect params whether is $_POST or $_GET after load a specific views.
Any guidance and advice to archive my tasks?
Unrelared to question You have one major problem: your ability to express what mean is extremely limited. The question, which you asked, was actually unrelated to your problem.
From what I gather, you need to detect of user made a POST or GET request. Do detect it directly you can check $_SERVER['REQUEST_METHOD'], but checking it withing controller might be quite bothersome. You will end up with a lot of controller's methods which behave differently based on request method.
Since you are not using any of popular frameworks, is would recommend for you to instead delegate this decision to the routing mechanism.
A pretty good way to handle this, in my opinion, is to prefix the controller's method names with the request method: postLogin(), getArticles() etc. You can find few additional example here. If there is a POST request, it will have something in $_POST array.
What are calling "views" are actually templates. If you read this article, you will notice, that the code there is actually an improved version of your MyView. Views are not templates. Views are instances which contain presentation logic and manipulate multiple templates.
P.S. If you are exploring MVC and MVC-inspired patterns in relation to PHP, you might find this post useful.

CodeIgniter Controllers and AJAX

EDIT: Previous title, because no one was reading the question: "If I'm making AJAX calls in an MVC framework, is it common to have 'getter' controller methods over the model?"
It's all in the title: If I want to make an AJAX call to delete a user, that DB code clearly lives in the model $this->userModel->delete($id).
If I'm making all of the CRUD calls via AJAX, do I just have passthrough controller methods to expose those model calls to a URL?
function delete($id) {
$this->userModel->delete($id);
}
etc? This seems silly, but it also makes sense... but it also makes me feel like I'm missing something. Is this the most common pattern?
Thanks!
When it comes down to Ajax under the MVC Framework I usually tend to have each function with a specified keyword such as fetch / set.
something like this
class Users extends Controller
{
public function Fetch($id){}
public function Create(){}
public function Update($id){}
public function Remove($id){}
}
To answer your question: yes
The task of the controller is the decision maker, so that you would perform authentication checks etc within the controller for security purposes.
Think of it this way, you would not use the same controller for changing records in your administration as you would within your users front-end, but you would use the same models.
the models should be used in more places than just the front end, so you would not place a session check, input validation in the model methods as you would perform different checks depending on the location the action is taking place.
Your frontend controller would have something along the lines of:
public function Fetch($id)
{
if($this->session->get_userdata("auth_level") & USER_AUTH_LEVEL_READ)
{
//Show data
}
}
where as your administration would have:
public function Fetch($id)
{
if($this->session->get_userdata("auth_level") & IS_ADMINISTRATOR)
{
//Show data
}
}
if you place the very same check in your models then you would have generate several models that would do return the same data regardless of the location.

Passing parameters to controller's constructor

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...

Categories