Pass Database Values to Layout - php

In my Zend application there is a layout file used in multiple modules. Now i need to retrieve data from database (table gateway) and display on layout. Then it should appear across all the modules.
How do i achieve that ?
Ex -
<?php echo $user_name; ?>
Value for $user_name should be taken from database and pass to layout file.

you dont have to set it in every controller. You could just attach it to a layout variable in your module.php.
public function onBootstrap(MvcEvent $e)
{
$sm = $e->getApplication()->getServiceManager();
$tableWhatever = $sm->get('tableWhatever');
$viewModel = $e->getApplication()->getMvcEvent()->getViewModel();
$viewModel->userName = $tableWhatever->getUserName();
}
Depending on the zf2 version you may have to access the variable in your layout like so:
$this->layout()->userName;
You also have the possibility to extend the AbstractActionController and add the layout variables trough that. I usually just go with the quick onBootstrap method though.

I believe, in Zend, your controller(s) will want:
$this->view->assign('variableName', 'variableValue');
And in your view(s), you will want:
$this->variableName;

You could use Zend Plugin to achieve something like that, like:
class MyPlugin extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
// Get instance
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
$view->user_name = 'your_username';
}
}
and register your plugin in frontController:
Zend_Controller_Front::getInstance()->registerPlugin(new MyPlugin());
then in layout , you could do:
<?php echo $this->user_name; ?>

Related

zend : use same index for different controllers?

I'm just learning Zend here:
I have different controllers for different departments to display similar but different information.
Can I use the same index file? The data that is different is determined inside the controller, so otherwise I'm just going to be copying and pasting the same html file...
class BazBatController extends AbstractActionController
{
public function doSomethingCrazyAction()
{
$view = new ViewModel(array(
'message' => 'Hello world',
));
$view->setTemplate('foo/baz-bat/do-something-crazy');
return $view;
}
}
This sets a “message” variable in the View Model, and sets the template name “foo/baz-bat/do-something-crazy”. The View Model is then returned.
Yes, you can reuse templates. Your templates can be structured however you like, so create a generic index.phtml somewhere that makes sense to you, and then in your controller actions just tell the view model to use that template instead of what it does by default:
class ShoesController extends AbstractActionController
{
public function indexAction()
{
$view = new ViewModel();
$view->setTemplate('some/shared/index.phtml');
return $view;
}
}
and do the same in your PantsController.

Yii2 Set page title from component view

I have page, for example, /about.
In page's view i may set page title: $this->title = "abc" - it works ok.
Also i have Header component in /components with his own view /components/views/Header.php
How could I change my page title from my component's view?
$this->title does not work because I'm in component's view, not page.
Not sure how you are calling your component, but to change the title you need to specify you want to change the current view.
Here is an example, in the view add something like (or use any method you already used but make sure you insert the view as a parameter):
MyComponent::changeTitle($this);
And in your component (whatever method you want to do this):
public static function changeTitle($view)
{
$view->title = 'changed';
}
If this is not related with your situation, please add an example of the view and the component so we can understand better what is the scenario.
Embed the page object into the component. Then change the properties of the page object through the aggregation composition.
The component class would read something like...
class MyComponent extends Component
{
private $pageObject;
public $title;
public function __construct(yii\web\View $view)
{
$this->pageObject = $view;
}
// this would change the title of the component
public function setTitle(string $newTitle)
{
$this->title = $newTitle;
}
public function changePageTitle(string $newTitle)
{
$this->pageObject->title = $newTitle;
}
}
Where, if you're in a view and you want to use your component in that view, you can instantiate it using
$comp = new MyComponent($this);
// where `$this` is the current page object
Now, from the component scope, $this->title = 'bleh'; would change the title of the component while $this->changePageTitle('bleh'); would change the page's title.

Zend Framework repeated functionality

I've recently started working with Zend Framework and I've absolutely fallen in love with it and I've even decommissioned my own framework in favour of it.
But I'm missing something that is probably so painfully obvious you'll chuckle a little bit.
I have a login system and in every controller I have to put the check for the login status, I had a look at accessing the Zend Session Storage in the Bootstrap but I'm on bit of a deadline and can't afford to waste time, is there a better way to check IE in the bootstrap? instead of repeating 20+ lines of code and functionality in every controller.
Thanks in advance!
You can use a controller plugin for this. See: http://framework.zend.com/manual/en/zend.controller.plugins.html
class Your_Plugin_Login extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
if (!Zend_Auth::getInstance()->hasIdentity()) {
// send the user to the login page
$request->setControllerName('login')
->setActionName('login');
}
}
}
replace the controller/action names with whatever is appropriate for your login page, and 'Your' with your application's namespace.
You then register the plugin with the Front controller either in application.ini or in your bootstrap with Zend_Controller_Front::getInstance()->registerPlugin(new Your_Plugin_Login());.
Edit: If you want to put the user details in the view as well, you can do:
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
$view->user = Zend_Auth::getIdentity();
You can write your own controller that inherits from Zend Controller (call it e.g. DaveMac_Controller - you can define the prefix in the app's config file so that the app can autoload it (and you need to be careful with which directory you save your class in)). In this class's construct function run the check for authentication. Then change all your page's controllers to inherit from DaveMac_Controller rather than the default zend one.
If I was at home I could copy and paste some code as an example, but at work right now so hopefully the above outline is enough.
*edit Good ol' dropbox :)
application.ini
includePaths.library = APPLICATION_PATH "/../library"
autoloaderNamespaces[] = "DaveMac_"
/../library/DaveMac/Controller/Action.php
<?php
class DaveMac_Controller_Action extends Zend_Controller_Action {
protected $acl;
protected $user;
protected $userRole;
public function init() {
//retrieve and store user details
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()){
$user = $auth->getIdentity();
$this->user = $user;
$this->view->user = $user;
$this->userRole = $user->role;
} else {
$this->userRole = "guest";
}
//Initialise access control list
$this->acl = new DaveMac_Acl();
}
protected function checkAuth($pageLevel, $redirect = "/") {
if($this->user) {
if(!$this->acl->isAllowed($this->userRole, $pageLevel)) {
$this->_redirect($redirect);
}
} else if ($pageLevel != DaveMac_Resources::PUBLIC_ONLY_PAGE) {
$this->_redirect('/login/returnurl/' . str_replace('/','-',$this->getRequest()->getRequestUri()));
}
}
}
You will probably already have your own functioms fdor checking authentication, but I thought I'd leave mine in anyway

Best way to deal with session handling in Zend Framework

So I'm starting up in Zend framework and looking to implement a site-wide "User" session.... something I can easily access from ALL modules/controllers in the application.
I'm like, should I make a new namespace in the library and extend the controller, like:
class MYCUSTOMLIB_Controller_Action extends Zend_Controller_Action
{
protected $_userSession;
function preDispatch(Zend_Controller_Request_Abstract $req)
{
$this->_userSession = new Zend_Session_Namespace('user');
}
}
ANd then have all my controllers/modules/etc extend from that?
Or should I create a Plugin or what? How would you go about making this plugin to pass the user session to the controller?
Or do I do it in the bootstrap?? Again how to pass to controller?
Also should I use Zend_Session_Namespace or Zend_Http_Cookie and also how do I encrypt and xss clean the cookie or is that done automagically?
I would initialise in the bootstrap too:
//Bootstrap.php
protected function _initUserSession()
{
return new Zend_Session_Namespace('user');
}
Then I would use an action helper:
// library/App/Controller/Action/Helper/Session.php
class App_Controller_Action_Helper_Session extends Zend_Controller_Action_Helper_Abstract
{
function direct()
{
return $this->getFrontController()->getParam('userSession');
}
}
You access it in your controller like this:
function indexAction()
{
$session = $this->_helper->session;
}
You should initialize your session in the bootstrap. You can either put it in the Zend_Registry and access it that way or from your controllers you can access your bootstrap by calling $this->getInvokeArg('bootstrap').
// in your controllers
public function init()
{
$bootstrap = $this->getInvokeArg('bootstrap');
$this->_session = $bootstrap->getResource('session');
}

PHP & Codeigniter - how to pass parameters to a model?

I am using the following code to initialize a model from within my controller:
$this->load->model('model_name');
Is it possible to modify the above line somehow so that the model constructor recieves a parameter? I want to use the following code in the model constructor:
function __construct($param_var) {
parent::Model();
$this->$param_var = $param_var; //I'm not even sure this works in PHP..but different issue
}
This would be very helpful so that I can reuse my model classes. Thanks.
UPDATE:
(from one of the answers, my original question is solved..thanks!)
Just to explain why I wanted to do this: the idea is to be able to reuse a model class. So basically to give a simple example I would like to be able to pass an "order_by" variable to the model class so that I can reuse the logic in the model class (and dynamically change the order-by value in the sql) without having to create a separate class or a separate function.
Is this poor design? If so could you please explain why you wouldn't do something like this and how you would do it instead?
You can't pass parameters through the load function. You'll have to do something like:
$this->load->model('model_name');
$this->model_name->my_constructor('stuff');
In the model:
function my_constructor($param_var) {
...
}
Response to update:
You could just pass the order_by value when you're calling your model function. I'm assuming in your controller action, you have something like $this->model_name->get($my_id); Just add your order_by parameter to this function. IMO this makes your model logic more flexible/reusable because the way you were doing it, I assume setting order_by in the constructor will set the order_by value for every function.
In model
<?php
/* Load Model core model */
/* BASEPATH = D:\xampp\htdocs\ci_name_project\system\ */
include BASEPATH . 'core\\Model.php';
class User_model extends CI_Model {
/* Properties */
private $name;
/* Constructor parameter overload */
public function __construct($name) {
$this->set_name($name);
}
/* Set */
public function set_name($name) {
$this->name = $name;
}
/* Get */
public function get_name() {
return $this->name;
}
}
in controller
<?php
class User_controller extends CI_Controller {
public function index() {
/* Load User_model model */
/* APPPATH = D:\xampp\htdocs\ci_name_project\application\ */
include APPPATH . 'models\\User_model.php';
$name = 'love';
/* Create $object_user object of User_model class */
$object_user = new User_model($name);
echo $object_user->get_name(); // love
}
}
I see your reasoning for this, but may I suggest looking at Object-Relational Mapping for your database needs. There is a user-made ORM library for CodeIgniter called DataMapper that I've been using lately. You can use tables in your controllers as objects, and it may be a better fit for your problem.
Instead of using DataMapper i suggested to use IgnitedRecord because that the DataMapper is no longer maintained more over it has been replaced into Ruby
I am using CI ver 3.X, so what I am about to say is it will work for Codeigniter 3.X (and I haven't checked ver 4+ yet).
When I went thru the source code of the function model() in file system/libraries/Loader.php, noticed that it does not support loading the model with construct parameters. So if you want to make this happen you have to change the source code (bold, I know, and I just did).
Down below is how I did it.
1. Firstly, replace line 355
$CI->$name = new $model();
with some modifications:
$_args_count = func_num_args();
if(3 < $_args_count){
$refl = new ReflectionClass($model);
$CI->$name = $refl->newInstanceArgs(array_slice($_args_count, 3));
}else{
$CI->$name = new $model(); // origin source code
}
2. Load the model with a bit difference:
$this->load->model("model_name", "model_name", false, $param_var); // where amazing happens
Now you can have $this->model_name as you wished.

Categories