Make things available in any view file Laravel - php

I have a question about making some elements available in any view file
Lets say im building a webshop and on every page i will be having my sidebar, shoppingcart, user greeting in the top.
How can i make these things available in all my view files?
I could make a class, lets say class Frontend
I could do something like this:
class Frontend {
static $me;
public function get(){
if(!self::$me){
self::$me = new self();
}
return self::$me;
}
private function getShoppingCart(){
// do things
}
public function getData(){
return array(
'Username' => User::find(1)->UserName,
'Cart' => $this->getShoppingCart()
);
}
}
Now in my controller i could pass this Frontend object into the view
View::make('file.view')->with(array('data' => Frontend::get()->getData()));
But this way i will end up with a god class containing way too much stuff and in every controller method i would have to pass these data, which is not relevant to the controller method
Is there a way in Laravel that makes specific data available across all view files?
Thanks!

Use share:
View::share('name', 'Steve');
as per http://laravel.com/docs/responses#views

To keep everything clean, every part of the page should be its own *.blade.php file which would be put together using a master template of sorts.
master.blade.php
#yield('includes.sidebar')
#yield('users.greeting')
#yield('store.shoppingcart')
Then you can use view composers so that each time these views are loaded, the data you want is injected into them. I would probably either create a new file which would get autoloaded, or if you have service providers for the separate portions of your app that these views would use, it would also go great in there.
View::composer('users.greeting', function($view)
{
$view->with('user', Auth::user());
});
In this case, it would make the user model available inside your view. This makes it very easy to manage which data gets injected into your views.

You are close with your 'god class' idea.
Setting a $data variable in a basecontroller has helped me with similar issues
class BaseController extends Controller {
protected $data;
public function __construct() {
$this->data['Username'] = User::find(1)->UserName
$this->data['Cart'] = $this->getShoppingCart()
}
}
class Frontend extends BaseController {
function someMethod(){
View::make('file.view', $this->data)
}
}

Related

Using multiple controllers inside of one view

I Need some advice, as I'm still a bit new to Laravel and MVC in general. I'm coding a small web application that presents some data on the page, fetched from a remote API. However, the page already has a controller to it. The other controller I will be using I'm hoping I can also reuse it for other pages. I'm pretty stuck here.
So the two controllers
HomeController.php
ApiController.php
The HomeController is the original controller, which gets the view file (home.blade.php), with some other data that's being loaded from the controller.
With the ApiController, I want to fetch the api (json) results, do some changes and then load those changes to the HomeController as well. The changes would be like an array of methods and such that's being loaded to the view.
So How can I load both controllers inside of the same view?
First of all controllers doesn't get loaded inside view instead, you should load a view from a controller and to make the remote request for an API call you don't need to use another controller but you may use it if you have other use of API and need a separate controller. The flow is something like this:
class HomeController extends BaseController {
public function index()
{
// make the api call/remote request
// modify the returned data
// load the view
}
}
Let's rewrite it:
class HomeController extends BaseController {
protected $apiService = null;
public function __construct(ApiService $apiService)
{
$this->apiService = $apiService;
}
public function index()
{
// make the api call/remote request
$apiData = $this->apiService->makeRequest();
// modify the returned data.... then...
// load the view
return View::make(...)->with('apiData', $apiData);
}
}
So, it seems clear that, you should use the API related process in a separate class as a service, maybe a model or a simple repository class and inject it to your HomeController then use it from the controller.
Do all the API stuffs in ApiService and call methods of that class from the HomeController, in this case you may implement the ApiServiceRepository as a concrete class by implementing an interface, i.e. ApiService. So, finally it could be like this:
interface ApiService {
public function makeRequest();
}
// Implement the interface in concrete class
class ApiServiceRepository implements ApiService {
public function makeRequest()
{
// $data = make remote request
// return $data
}
}
Use the class HomeController with __construct as given above and add a IoC binding like:
App::bind('ApiService', 'ApiServiceRepository');
So, you don't have to worry about the dependency injection in the constructor of your HomeController.
BTW, to use a method from another controller, for example ApiController from HomeController you may use something like this:
$apiController = App::make('ApiController');
// Call any method of "ApiController" class/object
$apidata = $apiController->makeCallToMethod();
You may also check this article for understanding the use of repository pattern in Laravel.

How to pass data to layout in Laravel regardless of controller?

Let's say I got ControllerA and ControllerB which both implement the same layout. Now I want to pass data to layout, for example, a message that should appear in layout no matter which controller implements it. If I had only 1 controller, I would do something like:
class Controller extends \BaseController {
public function setupLayout() {
View::share('message', 'Hello world!');
}
// further methods
}
However, when I want multiple controllers to implement a layout, I have to do this in every controller, which doesn't sound reasonable. So I wanted to ask, is there any native way in Laravel to pass data to layout and not to copy code in every controller.
Thanks in advance!
For those cases I would recommend a view composer, where you can set them for more than one view (or layout) or just all of them:
View::composer(['store.index', 'products.*'], function($view)
{
$view->with('model', 'one');
$view->with('colour', 'black');
});
You can put that in your routes file, filters file or, like, me, create a app/composers.php and load by adding
require app_path().'/composers.php';
To your app/start/global.php.

Laravel: In what situations would a service call a view, instead of a controller handling both calling the service and then calling the view?

Take a moment and consider the following Laravel controller:
class UsersController extends Controller {
public function index()
{
// some index stuff
}
public function ajax()
{
// This is how I like to do CRUD
if(Input::get('action') == "edit"){
return $this->edit(Input::get('id'));
}
if(Input::post('action') == "update"){
return $this->update(Input::all());
}
...
}
private function edit($id)
{
// Let's populate an edit users dialog (popup)
$viewData = array();
// Call edit method of my Users service & send that data to view
// (Note: "with" is a Laravel Helper)
return View::make('users.usersEdit', with(new Users)->edit($id));
// Or should I just have the service take care of the view, like this:
// return with(new Users)->edit($id);
}
}
In the spirit of "skinny controllers, fat services"...(my spin on the slogan)...
If I feel very confident that the edit method of my Users service (not shown here) is always going to need it's corresponding view, should I have the view called from the service (instead of calling the view from my UsersController as shown above)?
Your view is not a requirement for your edit user method, it is the output of the result. Users is domain logic. It should ideally have little to no dependency on Laravel, so you could stick it into another framework with little to no modification.
A controller is the perfect place to return Views. Definitely not in your domain logic. :)

Passing values between controllers

I'm learning Yii. I have a test development which contains a number of tables (employee, personalDetails, address). My understanding of MVC leads me to see these almost as individual planets, where each (MVC) component plays a clearly defined role within that world.
I have a question that’s starting to bug me because I now want to pass requests for data and calculations between these worlds. I have come across a few postings on how to do this, but they appear more like “hacks” than “prescribed” practises. I’m obviously keen not to pick up bad habits. This kind of process is obviously a root requirement of any development so would like to ask for some guidance on this.
A specific example would be to return a view of employees who have take home salaries > $100,000 including bonuses ( e.g. employee controller asks personalDetails controller to calculate {goss salary + bonuses – tax} and return all appropriate instances, it then looks up and returns the relevant employees).
So do I create a function in personalDetails and call it from inside employee controller, or should this kind of thing go in an extension ... or is there another approach?
I’d appreciate your guidance on this
For encapsulated self managed view parts use widgets. For above case you could create widget with configurable treshhold.
If you have to ask different controller to calculate something it is a bad practice. Place such calculations in model instead. Model is highly reusable, view can be reused, however controller should only respond to action and bind data to view.
Fat model, thin controller, wise view.
Here is some draft code:
First create model with any needed calculations:
class Employee extends CActiveRecord
{
public function getTotalSalary()
{
// Do any calculations here
// ...
return $salary;
}
}
Then you can reuse it in controllers:
class FirstController extends CController
{
public function actionPersonDetails()
{
$model = $this->_loadModel();
// By assigning this you will have getTotalSalary() available in view
$this->render('personDetails', ['model' => $model]);
}
}
class SecondController extends CController
{
public function actionViewSallary()
{
$model = $this->_loadModel();
// Also here you will have getTotalSalary() available in view
$this->render('viewSallary', ['model' => $model]);
}
}
And for more complex scenarios where you need something standalone create widget:
class EmployeesWidget extends CWidget
{
public $minSalary = 0;
private $_data = null;
public function init()
{
$this->_data = new CActiveDataProvider(/* Criteria here with $this->minSalary as param */);
}
public function run()
{
$this->render('employeesWidget', ['data' => $this->_data]);
}
}
Then you can easy use it in any view, even in other widgets:
$this->widget('path.to.EmployeesWidget', [
'minSallary' => 10000
]);

How to load Model into a controller in MVC

I am working on building a lightweight MVC, mainly for the learning process but I would like it to be good enough to use eventually.
Below is a basic example/demo of how a basic controller might would look, let's assume the URI has been processed and routed to this controller and these 2 methods.
1) I need to get data from database/cache/etc... inside my Model classes, I just need help on how I should load my models into my example controller below, you can see that I have added this below $profileData = $this->model->getProfile($userId) that is just made up and does not exist's, how could I get something like that to work though? Or should I load the model into the class a different way?
2) A lot of pages will require a user to be logged into the site. SHould I process that part below in the controller to check if a user is logged in, example, before building the profile page, check if user is logged in, if not then build a login page instead and add these checks inside of each controller method/page?
/**
* Example Controller
*/
class User_Controller extends Core_Controller {
// domain.com/user/id-53463463
function profile($userId)
{
//GET data from a Model
$profileData = $this->model->getProfile($userId);
$this->view->load('userProfile', $profileData);
}
// domain.com/user/friends/
function friends()
{
//GET data from a Model
$friendsData = $this->model->getFriendlist();
$this->view->load('userFriends', $friendsData);
}
}
core
abstract class Core_Controller {
protected $view;
protected $model;
function __construct(DependencyContainer $dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
}
There are probably tons of ways to accomplish what you are trying.
The "easiest" is probably to just override the constructor and instantiate the model directly.
in User_Controller:
public function __construct(DependencyContainer $dc) {
parent::__construct($dc);
$this->model = new User_Model();
}
I'm guessing that you are looking for something a little more automated though. If you want the Model to have the same name as the controller minus "_Controller", just use get_class($this) in the constructor and use PHP's string functions to parse out what you want. Once you have that in a variable, you can use that variable to instantiate the model:
in Core_Controller:
public function __construct(DependencyContainer $dc) {
$this->view = new Core_View();
// $model_class should be 'User_Model' now
$model_class = str_replace('_Controller', '_Model', get_class($this));
// now instantiate the model
$this->model = new $model_class();
}
I haven't actually worked with any framework that can only have one model associated with each controller (except may CakePHP? I can't remember). With Symfony, the models and controllers are completely decoupled so you can use any model with any controller. You just instantiate the model as need. Symfony use the Doctrine ORM so for example, in a controller action, if you needed a model you would do something like this:
$model = Doctrine::getTable('User');
It might be worthwhile to consider a design more like that in order to promote a decoupled design and I promise that you will want more than one model in some controller at some point.
2.) As far as authentication. Something that seems to be fairly common is to have some sort of setting (whether in a config file or a member variable) that says whether or not the current action needs the user to be authenticated. This is processed each time the action runs (Yii calls these kinds of things filters). If the user needs to be logged in, it stores the page that they are trying to access, and then redirects them to a log in page (you should only ever have to create one). Once they properly authenticate, it will redirect them back to where they were originally heading.

Categories