Cannot set layout via constructor - php

I tried almost everything but I just cant get the following to run.
<?php
class BaseController extends Controller {
// Define frontpage layout manager
protected $layout = '';
public function __construct() {
parent::__construct();
$theme = Theme::where('enabled', '=', true)->first();
// HERE !! : This never changes the value of $layout class var
$this->layout = View::make('themes.front.' . $theme->folder . '.master');
// I also tried without View::make(..)
// I also checked that $theme returns something and it does return a theme
}
/**
* Setup the layout used by the controller.
*
* #return void
*/
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
}
}
I simply cannot change the value of $layout in my constructor. I need this to allow user to switch between layouts.

So what I wanted to achieve with this is: I would have multiple layouts (templates) and I would allow user to change these templates via administration so I needed a quick and easy way to manipulate the protected $layout value.
The problem with putting my code in __constructor() {} is that setupLayout() will override it and thus the error as no layout is found.
So there are two solutions:
1) Declare layout in each sub-controller
Meaning each controller that extends your base controller defines it's own protected $layout in it's own __constructor() {} method. However this is very repetitive if all your pages share the same template.
2) Maniuplate the setupLayout() method
Since all my pages share the same layout and I know for certian there will always be at least one template I was able to simply alter the setupLayout() method to:
function setupLayout()
{
$theme = Theme::where('enabled', '=', true)->first();
$this->layout = 'themes.front.' . $theme->folder . '.master';
}

Related

PHP OOP-based login system

Lets say I am building an OOP-based user authentication system, and I would like to incorporate the following principles: Direct Injection, Inheritance, Encapsulation, Polymorphism and the Single Responsibility Principle.
My background in programming is has always relied on procedural programming, and thus, am finding it difficult to really put these practices into correct use.
Assume I have these classes:
class Config
{
public function set($key, $value);
public function get($key, $default = null);
}
class User
{
public function __construct(PDO $dbh, $id = null);
public function setProfile(Profile $profile);
}
class Auth
{
public function __construct(Config $config);
public function login($username, $password, $keepLoggedIn = true);
public function isLoggedIn();
public function getLoggedInUser();
public function logout();
public function register(array $data);
}
class Session
{
public function start($sessionName = null);
public function write($key, $value);
public function read($key, $default = null);
}
class Profile
{
public function setAddress(Address $address);
public function setName($name);
public function setDOB(DateTime $date);
public function getAge();
}
class Validator
{
public function validate($input);
}
I have intentionally left off the function bodies to keep things simple.
To the best of my knowledge, I believe I'm using the principles correctly. However, I am still unclear as to how you would connect classes like: the Validator to the User model, the User model to the Auth and the Session to the Auth class. All of which depend on each other.
You are on the right track. The way these classes connect to each other is called extending. I tend to go towards an MVC setup, meaning Model, View, Controller.
Your logic goes into the controller, all your DB queries and concrete back end methods go in the model. The controller receives requests and returns responses. It's the middleman. It talks to the back end after a request has been made to it, and feeds the front in via response.
So you have a core controller (keep it bare minimal), then each class you make extends the core controller. So your controller is where you tie all this together.
<?php
//your main core controller, where you load all these things you need avilable, so long as this class is extended
class CoreController {
public $auth
public $session;
public $view;
function construct__ ()
{
$this->auth = instantiateAuthClassHere();
$this->session = instantiateSessionClassHere();
$this->view = instantiateViewClassHere();
}
public function anotherHelperForSomething(){
//helper stuff for this method
}
}
//index, page, or content controller, depending on how many you need, i.e. if you want a controller for each page, thats fine, e.g indexController, etc..
//this is the middle man, has logic, receives requst, returns response to view.
class Controller extends CoreController {
public function index (){
$userModel = new userModel();
//do something with this
$session = $this->session;
$content = 'some html';
$userInfo = $userModel->getUsers();
$view = $this->view->render( array(
'content' => $content,
'userInfo' => $userInfo,
));
return $view;
}
}
//Core LIbraries
class Validator {
//your validator stuff
}
//Core LIbraries
class Session {
//your validator stuff
}
//Core LIbraries
class Auth {
//your validator stuff
}
class CoreModel{
public $validator;
function __construct(){
$this->validator = instantiateValidatorClassHere();
}
}
//a user model class (back end). you want a model class for each db table pretty much.
class UserModel extends CoreModel {
// if you need the validator anywhere inside this class, its globally available here inside any class that extends the CoreModel, e.g. $this->validator->methodName()
public function getUsers (){
$sql = 'SELECT * from users';
$result = $db->get($sql);
return $result;
}
}
Notice, on the Controller, this is a generic name for something like indexController, or anything custom. Also, I have the word extends there. It inherits all the objects from the parent that it extends. Inside it, now they will be available via $this->. See my example where I get $this->session.
Try to avoid constructs - you probably don't need them anywhere except for the core, and under special circumstances, which you might then need to check for yourself before you do even that. I dont use constructs much anymore. It can be a bit clunky and unmanageable.

Yii 1.1: cross-controller variables (and even cross-view ones)

For each request I have to load or, at least, create instance of a MyUser, which contains username, some internal permissions info, link to avatar and so on.
The thing is that I need this info for each and every controller and, for most of the views (to render or not to render some controls depending on user status and permissions).
It sounds like the need for a global variable, created at the time request being handled. What is the best way to solve this problem?
Override CWebUser (which is what you call when you issue Yii::app()->user) with your custom class WebUser (placed in the components or other folder that has it's classes autoincluded), and define some getters like it is done with getRole() example below:
<?php
class WebUser extends CWebUser {
private $_model = null;
function getRole() {
if($user = $this->getModel()){
return $user->userRole->name;
}
}
private function getModel(){
if (!$this->isGuest && $this->_model === null){
$this->_model = User::model()->findByPk($this->id);
}
return $this->_model;
}
}
If you user the custom class instead of CWebUser, you have to explicitly tell which class to use in application's config:
'user'=>array(
'class' => 'WebUser',
// …
),
You can create (or inject) an instance of MyUser in the constructor of your base controller, and set it to a public property:
//i am not familiar with Yii naming conventions, so ignore class name etc
class BaseController
{
public $user;
//presuming you can inject, if not $user = new MyUser();
function __construct(MyUser $user){
$this->user = $user;
}
}
Then all controllers that inherit BaseController can access if they need to:
class HomeController extends BaseController
{
function someAction(){
$name = $this->user->name;
}
}
And regardless of whether an action accesses the instance, its available in all views, without passing as a parameter to render:
//someview
echo $this->user->name;

PHP/Laravel magic, how does this work?

I'm looking at the Laravel docs, and I see this snippet:
class UserController extends BaseController {
/**
* The layout that should be used for responses.
*/
protected $layout = 'layouts.master';
/**
* Show the user profile.
*/
public function showProfile()
{
$this->layout->content = View::make('user.profile');
}
}
we can clearly see that $this->layout = 'layouts.master'. However, then they define a child of the layout object (which as I understand is only a base PHP string, and does not have a field called content, via ...
$this->layout->content = View::make('user.profile');
How can a string have a field called content defined?
when I subclass BaseController and try to assign a value to
$this->layout->content, why do I get the following error: "Attempt
to assign property of non-object"?
Why not look at BaseController? It looks like they change $this->layout.
https://github.com/laravel/laravel/blob/master/app/controllers/BaseController.php
<?php
class BaseController extends Controller {
/**
* Setup the layout used by the controller.
*
* #return void
*/
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
}
}
My advice, if you use a PHP framework, don't be afraid to check its source when you don't understand why it works. There is usually much less "magic" than you think...
IMO, this seems like a bad design though, to initialize the variable as a string and then change it to be some object. Kind of just abusing the loose typing.

Laravel 3, render only one section (for ajax)

I'd like to reuse my templates and would like to return only one rendered section as an ajax response (html table) which belongs to the "content" section (index.blade.php).
#section('content')
html...
#endsection
I've created another layout called ajax (ajax.blade.php) which contains only:
#yield('content')
My controller:
class Some_Controller extends Base_Controller {
public $restful = true;
public $layout = 'layouts.main';
public function get_index (){
if ( Request::ajax() )
$this->layout = 'layouts.ajax';
$view = View::make('some.index')->with('data', 'shtg');
$this->layout->content = $view;
}
}
It works when I request the route via normal GET request... but when I request it via ajax I get an error:
Attempt to assign property of non-object
on the line containing
$this->layout->content = $view;
I've also tried
return Section::yield('content');
Which returns empty document.
Is there a way to return rendered section? I've searched over the forums and couldn't find anything apart from:
http://forums.laravel.io/viewtopic.php?id=2942
Which uses the same principle and doesn't work for me (I've tried all the variations mentioned on the link above).
Thanks!
You appear to be mixing blade templates with controller templates. If you wish to use controller layouts (my preference) then remove the #section('content') and #endsection, and replace #yield('content') with $content.
However, that is not your entire problem. The following line is picked up by the layout method and converted into a real view...
public $layout = 'layouts.main';
You could easily extend the layout function in your controller, adding a layout_ajax attribute like this...
/**
* The layout used by the controller for AJAX requests.
*
* #var string
*/
public $layout_ajax = 'layouts.ajax';
/**
* Create the layout that is assigned to the controller.
*
* #return View
*/
public function layout()
{
if ( ! empty($this->layout_ajax) and Request::ajax() )
{
$this->layout = $this->layout_ajax;
}
return parent::layout();
}

Zend Framework how to do this in order to not repeat myself

I have this thing that I need in multiple places:
public function init()
{
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
}
These two lines:
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
Whats the best way to do it in ZendFramework?To create a plugin or? I mean I want to execute it in multiple places but If I need to edit it I want to edit it in one place.
Here is an example of an Action Helper that you can call from your controllers easily.
<?php
class My_Helper_CheckFbLogin extends Zend_Controller_Action_Helper_Abstract
{
public function direct(array $params = array())
{
// you could pass in $params as an array and use any of its values if needed
$request = $this->getRequest();
$view = $this->getActionController()->view;
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) {
$this->getActionController()
->getHelper('redirector')
->gotoUrl('/'); #Logout the user
}
return true;
}
}
In order to use it, you have to tell the helper broker where it will live. Here is an example code you can put in the bootstrap to do so:
// Make sure the path to My_ is in your path, i.e. in the library folder
Zend_Loader_Autoloader::getInstance()->registerNamespace('My_');
Zend_Controller_Action_HelperBroker::addPrefix('My_Helper');
Then to use it in your controller:
public function preDispatch()
{
$this->_helper->CheckFbLogin(); // redirects if not logged in
}
It doesn't go into much detail, but Writing Your Own Helpers is helpful as well.
If you need this check in every Controller you could even set up a baseController from which you extend instead of the default one:
class My_Base_Controller extends Zend_Controller_Action
{
public function init()
{ ...
class IndexController extends My_Base_Controller
{ ...
Shift your init() into the base controller and you don't need to repeat yourself in every specific controller.
Need a varying init() in a specific controller?
class FooController extends My_Base_Controller
{
public function init()
{
parent::init();
...

Categories