I'm using a laravel custom helper to print data in my view blade file. I pass a foreign key from a table to the custom helper and the custom helper checks the foreign key and returns its associated data. Recently my colleage suggested it is a bad idea to use a custom helper in a foreach loop of a view file. I didn't experience any performance issues, however my colleague suggested that when uploading to an AWS server, each request to the database would be charged. This is my code:
<?php
foreach($data as $key => $details) { ?>
<td>{{ helper::getstatename($details>stateid)}}</td>
<? }
?>
This is the helper file:
public static function getstatename($id) {
$getstatename = states::select('statename','id')->where('id',$id)->first();
if($getstatename){
return $getstatename->statename != '' ? $getstatename->statename : '';
} else {
return false;
}
}
My controller:
public function index() {
$locations = DB::table('locations')->select('locations.id','locations.locationname','cityid','stateid','countryid','locations.status')
->where('locations.status','!=',2)->orderBy('id','desc')->get();
return view('location/listlocation',['data'=>$locations]);
}
So I want to know, is this practice of using a helper file bad? Or should I stick to using a left join and print that data?
better you use joins to get state name at the $locations in the controller itself
Related
I have this route
Route::get('/post/{post:uuid}', [\App\Http\Controllers\PostController::class, 'showPost']);
And it works, if the user inputs an inexisting uuid, the app responses a 404 error, but now I want to add one more condition by using enums on route.
I have an enum called PostStateEnum.php
<?php
namespace Modules\Muse\Enum;
use App\Http\Traits\EnumTrait;
enum PostStateEnum: string
{
use EnumTrait;
case DRAFT = 'draft';
case WAITING_APPROVAL = 'waiting_approval';
case APPROVED = 'approved';
case REJECTED = 'rejected';
case PUBLISHED = 'published';
case UNPUBLISHED = 'unpublished';
}
I want to add a condition in the route: if the $post->state is PostStateEnum::PUBLISHED I want to go to the 'showPost' in my PostController
Currently, I'm handle that logic on my controller
public function showPost(Post $post)
{
if ($post->state == PostStateEnum::PUBLISHED)
{
dump($post);
} else {
return abort(404);
}
}
According to the laravel 9 docs I understand is that I need to create another enum with only one state to be able to validate that from the route, is that correct?
Is possible? Or my way is better?
I think you are confusing what enums in the route can bring. It is not about what is already saved, but more to use it as a filter / input. Imagine you want to have a route, that show posts based on status.
Route::get('posts/{PostStateEnum}');
In your controller you would be able to filter based on that.
public function index(PostStateEnum $enum) {
if ($enum ==PostStateEnum::PUBLISHED) {
// query filter published
} else if ($enum ==PostStateEnum::UNPUBLISHED) {
// query filter unpublished
}
}
Your enum is not from the input, but from the model, therefor what you are doing is actually the correct aproach. If not done, remember to cast your enum.
class Post extends Model {
protected $casts = [
'status' => PostStateEnum::class,
];
}
As a more general code improvement tip, doing if else, like you did in your example is non optimal for readability, you can in these cases, reverse the if logic and do an early return approach.
public function showPost(Post $post)
{
if ($post->state !== PostStateEnum::PUBLISHED)
{
return abort(404);
}
return $post;
}
Hi I have problem when i tried to save attribute of model to database. I write in OctoberCMS and i have this function:
public function findActualNewsletter()
{
$actualNewsletter = Newsletter::where('status_id', '=', NewsletterStatus::getSentNowStatus())->first();
if (!$actualNewsletter) {
$actualNewsletter = Newsletter::where('send_at', '<=', date('Y-m-d'))->where('status_id', NewsletterStatus::getUnsentStatus())->first();
$actualNewsletter->status_id = NewsletterStatus::getSentNowStatus();
dd($actualNewsletter);
}
return $actualNewsletter;
}
getSentNowStatus()=2;
getUnsentStatus()=1;
dd($actualNewsletter) in my if statement show that status_id = 2 But in database i still have 1. I used this function in afterSave() so i dont need:
$actualNewsletter->status_id = NewsletterStatus::getSentNowStatus();
$actualNewsletter->save();
becosue i have error then i use save in save.
Of course i filled table $fillable =['status_id']. And now i dont know why its not save in database when it go to my if. Maybe someone see my mistake?
If you are trying to modify the model based on some custom logic and then save it, the best place to put it is in the beforeSave() method of the model. To access the current model being saved, just use $this. Below is an example of the beforeSave() method being used to modify the attributes of a model before it gets saved to the database:
public function beforeSave() {
$user = BackendAuth::getUser();
$this->backend_user_id = $user->id;
// Handle archiving
if ($this->is_archived && !$this->archived_at) {
$this->archived_at = Carbon\Carbon::now()->toDateTimeString();
}
// Handle publishing
if ($this->is_published && !$this->published_at) {
$this->published_at = Carbon\Carbon::now()->toDateTimeString();
}
// Handle unarchiving
if ($this->archived_at && !$this->is_archived) {
$this->archived_at = null;
}
// Handle unpublishing, only allowed when no responses have been recorded against the form
if ($this->published_at && !$this->is_published) {
if (is_null($this->responses) || $this->responses->isEmpty()) {
$this->published_at = null;
}
}
}
You don't have to run $this->save() or anything like that. Simply modifying the model's attributes in the beforeSave() method will accomplish what you desire.
Here is my controller:
class CommonController extends CI_Controller {
public function __construct() {
parent::__construct();
$this->load->model('common_model'); //load your model my model is "common model"
}
public function add_work(){
$names = $_POST['name'];
$works = $_POST['work'];
$allValues = array(); // array to contains inserted rows
foreach($names as $key => $name){
$name= "your specified name";
$insertdata = array();
$insertdata['work'] = $works[$key];
$insertdata['name'] = $name;
$this->common_model->insert($insertdata);
array_push($allValues,$insertdata);
//$insert = mysql_query("INSERT INTO work(name,work) values ( '$name','$work')");
}
foreach($allValues as $insertRow){
echo $insertRow['work'];
echo $insertRow['name'];//this shows data well. but how to pass data in view.php
}
//view code will add here to show data in browser
}
Basically I want to pass all data to view.php for printing or exporting purpose. How can I do so.
To load a view you should do like this.
$this->load->view("filename");
If you want to pass data to view, you should do like this.
$this->load->view("filename",$data);
$data should have all parameters which you want to print in view.
The syntax goes like this.
$this->load->view("filename","data to view","Returning views as data(true / false");
If third parameter is true, view will come as data. It will not go to browser as output.
Edit:
Change
$this->load->view('print_view',$insertdata);
to
$data['insertdata'] = $insertdata;
$this->load->view('print_view',$data);
For more info, check this link
How CI Classes Pass Information and Control to Each Other
Calling Views
We will see.how the controller calls a view and passes data to it:
First it creates an array of data ($data) to pass to the view; then it loads and calls the view in the same expression:
$this->load->view('testview', $data);
You can call libraries, models, plug-ins, or helpers from within any controller, and models and libraries can also call each other as well as plug-ins and helpers.
However, you can't call one controller from another, or call a controller from a
model or library. There are only two ways that a model or a library can refer back to a controller:
Firstly, it can return data. If the controller assigns a value like this:
$foo = $this->mymodel->myfunction();
and the function is set to return a value, then that value will be passed to the variable $foo inside the controller.
//sample
public function display()
{
$data['text_to_display'] = $this->text_to_display;
$data['text_color'] = $this->text_color;
$this->load->view('display_view',$data);
}
Adding Dynamic Data to the View
Data is passed from the controller to the view by way of an array or an object in the second parameter of the view
loading method. Here is an example using an array:
$data = array(
’title’ => ’some’,
’heading’ => ’another some’,
’message’ => ’and another some’
);
$this->load->view(’view’, $data);
And here’s an example using an object:
$data = new Someclass();
$this->load->view(’view’, $data);
Sending Multiple Dimensional array
if we pull data from your database it will typically be
in the form of a multi-dimensional array.
<?php
class foo extends CI_Controller {
public function index()
{
$data[’Books’] = array(’POEAA’, ’TDD’, ’Clean C’);
$data[’title’] = "Title";
$data[’heading’] = "Heading";
$this->load->view(’view’, $data);
}
}
in view
<html>
<head>
<title><?php echo $title;?></title>
</head>
<body>
<h1><?php echo $heading;?></h1>
<h3>My Books List</h3>
<ul>
<?php foreach ($Books as $item):?>
<li><?php echo $item;?></li>
<?php endforeach;?>
</ul>
</body>
</html>
More Learning
NOTE:
There is a third optional parameter lets you change the behavior of the method so that it returns data as a string rather
than sending it to your browser.The default behavior is false, which sends it to your browser. Remember to
assign it to a variable if you want the data returned:
$string = $this->load->view(’view’, ’’, TRUE);
Above will not solve your problem directly but definetly help in understanding concepts.
I have a form that contains a list of settings, all with their own IDs, shown via simple foreach loop. When the user clicks the update button, I want to be able to update all of the values using Anahkiasen/Former. However, I can't seem to find the documentation on how to submit more than one set of records.
For instance, if I was opening the form to edit just one setting instead of all of them, I would just do the following:
{{ Former::open()->method('PUT')->action(URL::to('settings/' . $setting['id'])) }}
This would send it to my 'update' resource method and the following code would take care of the update:
public function update($id)
{
$setting = Setting::findOrFail($id);
if ($setting->save()) {
return Redirect::back()->with('message', "Setting #$id updated!");
} else {
return Redirect::back()->withInput()->withErrors($setting->errors());
}
}
Is it possible to do this with multiple records at once and still use the convenient $autoHydrateEntityFromInput and $forceEntityHydrationFromInput features?
I'm using Laravel 4.1 and Former 3.4.2.
This had to be done by just putting the values into an array and forcing the existing value in the Blade template:
#foreach ($settings as $s)
<div class="row">
{{ Former::text('values[' . $s['id'] . ']', $s['name'])->forceValue($s['value']) }}
</div>
#endforeach
Then retrieve the values in the controller:
public function update()
{
$values = Input::get('values');
foreach ($values as $id => $val) {
$setting = Setting::findOrFail($id);
$setting['value'] = $val;
if (!$setting->save()) {
return Redirect::back()->withInput()->withErrors($setting->errors());
}
}
return Redirect::back()->with('message', "Settings updated!");
}
Doing it this way, a standard resource won't work like Route::resource('settings', 'SettingsController'); so instead I had to simply do Route::post('settings/update', 'SettingsController#update');
As far as I can tell, auto hydration also won't work in this case.
Where should we process mysql queries in CodeIgniter application?
For example in a simple project we do like this :
for controller:
class Blog extends CI_Controller {
function posts(){
$data['query'] = $this->blog_model->index_posts();
$this->load->view('blog_view', $data);
}
}
and in view :
<?php
while ($post = mysql_fetch_object($query)):
?>
<div>
<p><?= $post->body; ?></p>
</div>
<?php endwhile; ?>
But, if we want to do something with body of post before print where should it be done?
For example, I want to write a function that formats the body of post and pass the body to it before doing echo.
Where should it be placed according to CoeIgniter's structure and recommended practices? (best option)
in the controller? (if so , how to use it)
in the view?
write a helper?
other approaches ?
Here's what is recommended:
Controller:
function posts() {
$this->load->model("blog_model");
$data['rows'] = $this->blog_model->index_posts();
$this->load->view("blog_view", $data);
}
Model: (blog_model.php)
function index_posts() {
$this->load->database();
$query = $this->db->get('your_table');
$return = array();
foreach ($query->result_array() as $line) {
$line['body'] = ... do something with the body....
$return[] = $line;
}
return $return;
}
View: (blog_view.php)
<?php foreach ($rows as $line): ?>
<div>
<p><?php echo $line['column']; ?></p>
</div>
<?php endforeach; ?>
Basically what happens is your model returns a multidimensional array that is passed the view and processed using a foreach() loop.
Good luck!
If you want to reuse that function create a helper. If you want this function only once put it in your controller and call from that controller.
Models are just for accessing database or maybe in few other cases, but mostly just for accessing things in database or editing, deleting etc. and sending the result to controller for further processing.
In your case I would stick with helper.
E.g. you will create a file top_mega_best_functions.php and put it inside helpers folder.
Than you write ther e.g. something like
function red_text($input) {
echo '<span style="color: red;">';
echo $input;
echo '</span>';
}
Then load the helper in your autoloader file or load before using.
And use in your view or controller like
$blablabla = "This text will be red";
red_text($blablabla);