Make view depend on variables in laravel - php

It might just be me coming from a more restricted java background, but I'm feeling the connection between views and controllers in Laravel is error prone. For example, consider a controller looking something like this
ReceiptController extends BaseController {
...
public function show() {
$data = array($receipt, $offer);
View::make('registration', $data);
}
}
and a view which depends on a receipt object and an offer string
...
<div id="receipt">
<h1>Receipt</h1>
{{$receipt->items}}
#if ($receipt->price > 10000)
<p>{{$offer}}</p>
#endif;
</div>
...
What if a controller somewhere don't include the offer string? Worst case scenario it might go unnoticed until someone purchase something with a price over 10000. How would I go about throwing an error if the controller doesn't pass all variables required to make the view? Bonus if it also makes an IDE such as PHPStorm recognize the variables.

You could use a view composer, and ensure that whenever your receipt view is called, a offer is always included. That way you know the object is always passed.
View::composer('receipt', function($view)
{
$view->with('offer', Offer::get(1));
});
Or you could just handle it directly in your view
<div id="receipt">
<h1>Receipt</h1>
{{$receipt->items}}
#if ($receipt->price > 10000)
<p>{{$offer or 'Sorry - no special available'}}</p>
#endif;
</div>
Lastly - the 'best' option is to always test your code, and check your view is always called with a $offer variable
$this->assertViewHas('offer');

That kind of logic if intented to work in the Controller, if the price is higher than a value, set a $var = false and check if in the view.
if($receipt->price > 10000) {
$offer = $offer;
} else {
$offer = false;
}
And about the compatibility between PHPStorm and Blade Template Engine, PHPStorm 7.1 doesn't support it, but you help to build a better world voting for it for the next version: http://youtrack.jetbrains.com/issue/WI-14172

Related

how to use DD() method in Laravel projects?

I know that for some it might be stupid or funny question (but I am newbie) but I need to find know how to properly use DD() method in laravel projects.
For example - I have got tasks to debug some code and functionality in my project (PHP laravel). And it always takes me for ever to find the exact file or folder or code where the problem is.
My mentor says to use DD() method to find things faster (but for learning purposes he didn't explain me a lot about how to actually use it and said to find out my self), but said that I should start with Route (we use backpack as well for our project). So after finding Route (custom.php file) which controller connects to my required route what should I do next? How do I implement dd() method (or as my mentor says dd('call here') method) to fast find what I should be looking for to solve my problem and complete my task? Where should I write this dd() and how should I write it?
Thank you for the answer in advance!
for example I have a:
public function create(): View
{
return view('xxxxxx. \[
//
//
\]);
}
and if I put dd() anywhere in the code, I get error message in my URL :(
first of all ,in Laravel we use dd() before return in order to read any variable.
in controller we often use two kinds of variables : collection(which we get its members via foreach) or singular variable (we get it via its name)for example:$var = 1; dd($var).
notice:
if you are using ajax response you will not be able to see dd() results in page ,you can see the result via network tab in your browser (if u inspect your page).
dd stands for "Dump and Die."
Laravel's dd() function can be defined as a helper function, which is used to dump a variable's contents to the browser and prevent the further script execution.
Example:
dd($users,$variable1,$var2);
You can use dd() in blade
#foreach($users as $user)
#dd($user)
OR
{{dd($user)}}
#endforeach
#dd($var1)
You can read this article, the have more example and comparison
https://shouts.dev/articles/laravel-dd-vs-dump-vs-vardump-vs-printr-with-example
As Laravel is following model-view-controller or MVC design pattern. First go to the route and check which controller is called in the URL with the related URL.
Then go to the controller. **dd**() function is basically a dump and die. you also can do this by **print** or **echo** function too.
Lets assume that I have a controller name ProductController where I have method name index.From where I need to show a list of products in a table.
// in controller
public function index()
{
$products = Products::all();
// here you think ,I need to check whether I am getting the output or
not.
dd( $products );
//Or echo $products;
return view ('product.list',compact('products'));
}
let's suppose you are getting everything but in view when you loop through the products you declare the wrong variable name or mistakenly do some spelling mistakes. and want to see the result.
In view just do the dd() method by the following way:
{{ dd($products) }}

Laravel - Model const in a blade?

Is it bad practice to use Model:CONST in a blade view or what is other approach?
For example in the model, I have like this:
class ServiceType extends Eloquent
{
protected $table = 'service_type';
const TYPE_LANDLINE = 1;
const TYPE_SIP = 4;
}
and in the controller:
if ($packageDb->service_type_id == ServiceType::TYPE_SIP) {
$summary[service_type] = $packageDb->service_type_id;
}
if ($packageDb->service_type_id == ServiceType::TYPE_LANDLINE) {
$summary[service_type] = $packageDb->service_type_id;
}
return View::make("order.order-billing")->with('summary', $summary);
In blade I could do something like this (not tested):
#if ($summary['service_type'] == ServiceType::TYPE_SIP)
..
#endif
tl;dr
It is up to you.
Alternate solution
You could create a variable for your constant and pass it to the view:
$roleNames = User::ROLE_NAMES;
return View::make("membership.edit", compact('roleNames'));
Then in the view:
<td>#lang("app.{$roleNames[$member->pivot->role_id]}")</td>
Advantages
Shorter: You don't have to write the fully qualified name of the model. This is pretty handy if you have a deep model structure or long model names.
You can "rename" the constant: Sometimes constant names are general. By passing a variable you can give a more descriptive name for the variable that can tell how exactly you use those constants in that given context.
It is clearer what the view works with: The controller's job is to provide the needed resources (for the view) to generate a response to the request. If you pass the constants to the view in the controller, you can see what resources the view works with.
Disadvantages
Of course there can be down sides too, when using this method is cumbersome. If you have many constants (for example for each user role) then probably you don't want to pass all of them to the view, because you will end up with something like this:
$noRole = User::NO_ROLE;
$memberRole = User::MEMBER_ROLE;
$adminRole = User::ADMIN_ROLE;
$moderatorRole = User::MODERATOR_ROLE;
$reviewerRole = User::REVIEWER_ROLE;
$publisherRole = User::PUBLISHER_ROLE;
return View::make("membership.edit", compact(
'noRole',
'memberRole',
'adminRole',
'moderatorRole',
'reviewerRole',
'publisherRole'
));
The main problems with this:
Lot of unnecessary code for a trivial functionality.
Hard to maintain, especially if your view uses only a few of them.
Violates DRY, especially if you need to do this in almost all function that returns a view.
Of course you could refactor this, create helper functions, but why would you deal with all of this hassle when (in this case) using the constants directly in the view is straightforward and easy to understand:
#if ($user->role === App\User::ADMIN_ROLE)
The rule of thumb is to use the solution that is easier to read and understand. Except if you have a style guide, then you should follow that.
In your blade file you can inject the model
#inject('ServiceTypeModel', 'App\Models\ServiceType')
and then use constants like this
{{ ServiceTypeModel::SIP }}
or
#if ($x < ServiceTypeModel::SIP)...

What is a quick way to check if a user has a particular role in my Laravel application?

I'm currently building a web application using Laravel 4 PHP Framework, and part of my app is only visible to subscribers and administrators; and obviously I don't want guests to see these sections of my site.
Each user has a role_id which corresponds to a value in an abstract static class in acts as an enum:
abstract class UserRole {
const Unauthenticated = 1;
const Member = 2;
const Subscriber = 3;
const CharterSubscriber = 4;
const Moderator = 5;
const Administrator = 6;
}
Because a lot of my content is dynamic depending on the role a user has; I'm finding I'm checking if a user is of a particular role or greater using the Blade PHP syntax in my Views.
To do this, I'm having to use a rather verbose syntax:
#if (Auth::user() && Auth::user()->role_id == UserRole::Administrator)
...is a good example. The problem here is I first have to check if Auth::user() exists; if it doesn't, the second logical comparison will fail, so I can't even do this:
#if (Auth::user()->role_id == UserRole::Administrator)
...which is cleaner, but still pretty verbose. Ideally, I'd like to do something like:
#if (Auth::isAdmin())
...or...
#if (Auth::isSubscriberOrGreater())
How can I accomplish this? I don't know that much about Laravel's IOC container, so any answers are going to have to be reasonably well explained.
I can propose a solution, though it might be a little bit ugly:
Auth::user() method returns you the User model or NULL, so in the user model you can check if the user is admin with isAdmin method (or you can perform any other check) like this:
public function isAdmin(){
if( $this->role_id == 6){
return True;
}
return False;
}
(really you can call method any other name and perform any other check there).
and in then in blade template you'll have something like this:
#if (#Auth::isAdmin())
To avoid throwing a notice you simply put '#' which is an Error Control Operator in front of the variable.

error handling in codeigniter: who should call show_error()

I have a question about error handling in codeigniter.
My first question is who should call the show_error method? The model or the controller or the view?
I was going to put it in the model for this particular case because the model is where the error is generated, but since most of my business logic is in the controller I decided to do it there. BUt I'd like to know if there is a "correct" way to do this.
My second question is this. In the model, i have added two functions- one to return data, and the other to return an error message. My controller tests for an error condition after calling my model, and attempts to display it. But its always empty.
My model looks something like this:
public function errormessage()
{
return $this->_emess;
}
public someotherfunction()
{
if ( $switch_obj->connect() )
{
$retdata = $switch->showInterfaceAll();
$switch->disconnect();
$this->_data = $retdata;
return true;
}
else
{
print 'debug: assigning error message in model:';
$this->_emess = $switch->errormessage();
print $this->_emess;
return false;
}
}
Then in my controller, i have the following logic:
if ($this->switches_model->someotherfunction($this->uri->segment(7) ) )
{
$data['listofports'] = $this->switches_model->data;
}
else {
print '<BR>in error path<BR>';
show_error($this->switches_model->errormessage(), 123);
}
From my debug print statements in the model, i know that an error message has been set. But by the time the controller tries to display it using the show_error() method, i'm getting the following error message:
No status text available. Please check your status code number or
supply your own message text.
To prove that its not because the model has already been destroyed, I tried adding a destructor in my model and printing out a debug line...
public function __destruct()
{
print 'in the destructor';
}
The message "in error path" is printed before "in the destructor" so I'm assuming that the model is still alive and well...
Any suggestions would be appreciated.
Thanks.
UPDATE 1
I found my problem. You need to pass a legit status code, if you're going to pass one at all.
I thought you could create custom status numbers, but they must be HTTP codes. But if someone could comment on question 1 about who should call show_error() that'd be much appreciated.
Thanks.
The short answer to your first question is no, there is not a "correct" way to do it.
In your question, you said:
since most of my business logic is in the controller I decided to do it there.
This is up for debate and is probably not a debate that should be had on this site but I have found that generally, the controller is meant to be more of a dispatcher then anything else. So, your controller should be as small as possible. That being said, since the show_error() function is also deciding what view to display, I would call that a dispatching function and would put it in the controller. If you were not using that function but were using log_message() instead to store the error in a log and continue processing, then I would put that in the model because you can continue through the process after using that function. Again, this is personal choice and can be done either place but that is how I usually look at it.

Correct way to deal with application-wide data needed on every pageview

I am currently involved in the development of a larger webapplication written in PHP and based upon a MVC-framework sharing a wide range of similarities with the Zend Framework in terms of architecture.
When the user has logged in I have a place that is supposed to display the balance of the current users virtual points. This display needs to be on every page across every single controller.
Where do you put code for fetching sidewide modeldata, that isn't controller specific but needs to go in the sitewide layout on every pageview, independently of the current controller? How would the MVC or ZF-heads do this? And how about the rest of you?
I thought about loading the balance when the user logs in and storing it in the session, but as the balance is frequently altered this doesn't seem right - it needs to be checked and updated pretty much on every page load. I also thought about doing it by adding the fetching routine to every controller, but that didn't seem right either as it would result in code-duplication.
Well, you're right, having routines to every controller would be a code-duplication and wouldn't make your code reusable.
Unlike suggested in your question comments, I wouldn't go for a a base controller, since base controllers aren't a good practice (in most cases) and Zend Framework implements Action Helpers in order to to avoid them.
If your partial view is site-wide, why don't you just write your own custom View Helper and fetch the data in your model from your view helper? Then you could call this view helper directly from your layout. In my opinion, fetching data through a model from the view doesn't break the MVC design pattern at all, as long as you don't update/edit these data.
You can add your view helpers in /view/helpers/ or in your library (then you would have to register your view helper path too):
class Zend_View_Helper_Balance extends Zend_View_Helper_Abstract
{
public function balance()
{
$html = '';
if (Zend_Auth::getInstance()->hasIdentity()) {
// pull data from your model
$html .= ...;
}
return $html;
}
}
Note that you view helper could also call a partial view (render(), partial(), partialLoop()) if you need to format your code in a specific way.
This is a pretty simple example, but to me it's enough is your case. If you want to have more control on these data and be able to modify it (or not) depending on a particular view (or controller), then I recommend you to take a look on Placeholders. Zend has a really good example about them here on the online documentation.
More information about custom view helpers here.
When you perform such a task, consider using the Zend_Cache component too, so you won't have to query the database after each request but let's say, every minute (depending on your needs).
What you are looking for is Zend_Registry. This is the component you should use when you think you need some form of global variable. If you need this on EVERY page, then you are best adding it to your bootstrap, if you only need it in certain places add it in init method of relavent controllers.
application/Bootstrap.php
public _initUserBalance()
{
$userId = Zend_Auth::getInstance()->getIdentity()->userId;
$user = UserService::getUser($userId);
Zend_Registry::set('balance', $user->getBalance());
}
application/layouts/default.phtml
echo 'Balance = ' . Zend_Registry::get('balance');
That wee snippet should give you the right idea!
In this case, I usually go with a front controller plugin with a dispatchLoopShutdown() hook that performs the required data access and adds the data to the view/layout. The layout script then renders that data.
More details available on request.
[UPDATE]
Suppose you wanted to display inside your layout the last X news items from your db (or web service or an RSS feed), independent of which controller was requested.
Your front-controller plugin could look something like this in application/plugins/SidebarNews.php:
class My_Plugin_SidebarNews
{
public function dispatchLoopShutdown()
{
$front = Zend_Controller_Front::getInstance();
$view = $front->getParam('bootstrap')->getResource('view');
$view->sidebarNews = $this->getNewsItems();
}
protected function getNewsItems()
{
// Access your datasource (db, web service, RSS feed, etc)
// and return an iterable collection of news items
}
}
Make sure you register your plugin with the front controller, typically in application/configs/application.ini:
resource.frontController.plugins.sidebarNews = "My_Plugin_SidebarNews"
Then in your layout, just render as usual, perhaps in application/layouts/scripts/layout.phtml:
<?php if (isset($this->sidebarNews) && is_array($this->sidebarNews) && count($this->sidebarNews) > 0): ?>
<div id="sidebarNews">
<?php foreach ($this->sidebarNews as $newsItem): ?>
<div class="sidebarNewsItem">
<h3><?= $this->escape($newsItem['headline']) ?></h3>
<p><?= $this->escape($newsItem['blurb']) ?></p>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
See what I mean?

Categories