Write function in controller below controller class? - laravel

Is that a good practice to wrap some code from controller class method because it's too long and put that code in another custom function below controller class.
Here is controller method:
public function store(UploadRequest $request)
{
//Provjera duljine imena slike (max 20 znakova)
if(!is_valid_name($request->file('file'))) {
return redirect()->back()->withErrors(['File name can\'t be longer than 20 characters.']);
}
$user = Auth::user();
$time = time();
$image = $request->file('file');
//Dodaj trenutno vrijeme prije imena slike kako bi se slika mogla identificirati
$image_name = $time . $image->getClientOriginalName();
//Ako je slika png spremi ju bez konverzije
if($image->getClientOriginalExtension() == "png")
{
Storage::put('public/images/'.$user->id.'/png/'.$image_name, file_get_contents($image));
save_image_to_database($image, $user, $time);
}
Save_image_to_database() is my custom function that is written below controller class:
function save_image_to_database($image, $user, $time){
$db_image = new Image();
if($image->extension() == 'png')
{
$db_image->path = $time . $image->getClientOriginalName();
$db_image->png_size = $image->getClientOriginalSize();
}
else
{
$path = $time . pathinfo($image->getClientOriginalName(), PATHINFO_FILENAME).'.png';
$png_size = Storage::size('/public/images/'.$user->id.'/png/'.$path);
$db_image->path = $path;
$db_image->png_size = $png_size;
}
$db_image->user_id = $user->id;
$db_image->extension = $image->extension();
$db_image->size = $image->getClientSize();
$db_image->save();
return redirect('/images');
}
Problem is that redirect() method in custom function is not working, it redirects to blank window but the path in browser "localhost:8000/images" is correct.When I manually refresh the site then it works and the view is returned. If I move that redirect() method from custom function to controller store() then it works well.

Your function returns Response object but controller doesn't use it
The most simple solution for you will be to return the response of helper function like
return save_image_to_database($image, $user, $time);
However I would at least wrap it in try-catch to handle inability to save file like
try {
save_image_to_database($image, $user, $time);
} catch (\Exception $e) {
// return error response
}
// if we got here image was successfully saved
return redirect('/images');
Now back to your question about if its a good experience to handle image as another controller method.. I'd say no, you want to keep your controllers very skinny and have only methods that are used by Router
I'd either move it into a Trait (Traits in PHP) and use that trait in the controller or make an Image Service and use it via dependency injection.

Related

How do I loop over json data

I am using FlutterWave as my payment gateway, I want to loop through a transaction whenever a customer finish making payment and check for the chargeamount which the user paid. the return data is in json format. Here is my code.
public function callback(Request $request)
{
$resp = $request->resp;
$body = json_decode($resp, true);
$txRef = $body['data']['data']['txRef'];
$data = Rave::verifyTransaction($txRef);
dd($data);
return redirect()->route('success');
}
I want to loop and check for the chargedamount but I couldn't. Thanks for your help
Seems like you are dumping an object. I don't think you need a loop to access the data you need. According to your image dump, to access the chargedamount attribute:
dd($data->data->chargedamount);
The data name here repeats, perhaps $payload in this case, its a better name.
public function callback(Request $request)
{
$resp = $request->resp;
$body = json_decode($resp, true);
$txRef = $body['data']['data']['txRef'];
$payload = Rave::verifyTransaction($txRef);
dd($payload->data->chargedamount);
return redirect()->route('success');
}
Some clean up:
public function callback(Request $request)
{
$json = json_decode($request->resp);
$payload = Rave::verifyTransaction($json->data->data->txRef);
dd($payload->data->chargedamount);
return redirect()->route('success');
}
Again that data->data repeating stuff, but in this case, nothing we can do, its in the API.

laravel 5.7 how to pass request of controller to model and save

I am trying to pass $request from a function in controller to a function in model.
THis is my controller function:
PostController.php
public function store(Request $request, post $post)
{
$post->title = $request->title;
$post->description = $request->description;
$post->save();
return redirect(route('post.index'));
}
how save data in model Post.php?
I want the controller to only be in the role of sending information. Information is sent to the model. All calculations and storage are performed in the model
Thanks
You can make it even easier. Laravel has it's own helper "request()", which can be called anywhere in your code.
So, generally, you can do this:
PostController.php
public function store()
{
$post_model = new Post;
// for queries it's better to use transactions to handle errors
\DB::beginTransaction();
try {
$post_model->postStore();
\DB::commit(); // if there was no errors, your query will be executed
} catch (\Exception $e) {
\DB::rollback(); // either it won't execute any statements and rollback your database to previous state
abort(500);
}
// you don't need any if statements anymore. If you're here, it means all data has been saved successfully
return redirect(route('post.index'));
}
Post.php
public function postStore()
{
$request = request(); //save helper result to variable, so it can be reused
$this->title = $request->title;
$this->description = $request->description;
$this->save();
}
I'll show you full best practice example for update and create:
web.php
Route::post('store/post/{post?}', 'PostController#post')->name('post.store');
yourform.blade.php - can be used for update and create
<form action='{{ route('post.store', ['post' => $post->id ?? null]))'>
<!-- some inputs here -->
<!-- some inputs here -->
</form>
PostController.php
public function update(Post $post) {
// $post - if you sent null, in this variable will be 'new Post' result
// either laravel will try to find id you provided in your view, like Post::findOrFail(1). Of course, if it can't, it'll abort(404)
// then you can call your method postStore and it'll update or create for your new post.
// anyway, I'd recommend you to do next
\DB::beginTransaction();
try {
$post->fill(request()->all())->save();
\DB::commit();
} catch (\Exception $e) {
\DB::rollback();
abort(500);
}
return redirect(route('post.index'));
}
Based on description, not sure what you want exactly but assuming you want a clean controller and model . Here is one way
Model - Post
class Post {
$fillable = array(
'title', 'description'
);
}
PostController
class PostController extend Controller {
// store function normally don't get Casted Objects as `Post`
function store(\Request $request) {
$parameters = $request->all(); // get all your request data as an array
$post = \Post::create($parameters); // create method expect an array of fields mentioned in $fillable and returns a save dinstance
// OR
$post = new \Post();
$post->fill($parameters);
}
}
I hope it helps
You need to create new model simply by instantiating it:
$post = new Post; //Post is your model
then put content in record
$post->title = $request->title;
$post->description = $request->description;
and finally save it to db later:
$post->save();
To save all data in model using create method.You need to setup Mass Assignments when using create and set columns in fillable property in model.
protected $fillable = [ 'title', 'description' ];
and then call this with input
$post = Post::create([ 'parametername' => 'parametervalue' ]);
and if request has unwanted entries like token then us except on request before passing.
$post = Post::create([ $request->except(['_token']) ]);
Hope this helps.
I find to answer my question :
pass $request to my_method in model Post.php :
PostController.php:
public function store(Request $request)
{
$post_model = new Post;
$saved = $post_model->postStore($request);
//$saved = response of my_method in model
if($saved){
return redirect(route('post.index'));
}
}
and save data in the model :
Post.php
we can return instance or boolean to the controller .
I returned bool (save method response) to controller :
public function postStore($request)
{
$this->title = $request->title;
$this->description = $request->description;
$saved = $this->save();
//save method response bool
return $saved;
}
in this way, all calculations and storage are performed in the model (best way to save data in MVC)
public function store(Request $request)
{
$book = new Song();
$book->title = $request['title'];
$book->artist = $request['artist'];
$book->rating = $request['rating'];
$book->album_id = $request['album_id'];
$result= $book->save();
}

Loading view inside a Library, issues with cached vars

I am trying to implement a widgets library using load->view. I know I can use include to call directly the file and avoid the vars cache issues but just wondering why it does not work.
Here is how I have structured my code:
My Controller:
class Page extends MY_Controller {
public $data = array();
public function __construct() {
parent::__construct();
...
$this->load->library('widgetmanager');
}
public function index($slug = '') {
echo $this->widgetmanager->show(2);
echo $this->widgetmanager->show(1);
}
}
My Library
class WidgetManager
{
private $CI;
public function __construct()
{
$this->CI = & get_instance();
}
public function show($widget_id) {
$data = array();
$widget_id = (int)$widget_id;
$this->CI->db->select('*');
$this->CI->db->from('widget');
$this->CI->db->where('id', $widget_id);
$query = $this->CI->db->get();
$item = $query->row_array();
$data['widget_title'] = $item['title'];
$data['widget_content'] = $item['content'];
$widget = $this->CI->load->view('widget/'.$item['source'], $data, TRUE);
$data['widget_title'] = '';
$data['widget_content'] = '';
$this->CI->load->view('widget/'.$item['source'], $data);
return $widget;
}
}
widget 1: Calls widget/content
widget 2: Calls widget/banner
What is happening is, the vars set on the first widget call (they are same name as second widget call), get cached, meaning values from the first call are passed to same call. It is weird because are different views.
I have tried:
Using clear_vars(): $this->CI->load->clear_vars(), before and after doing load->view on the library.
Calling load->view with empty array, null, etc
Tried to add a prefix with the widget slug to the vars (that works, but I have to send in some way the prefix to the view, so it is not possible due cache issue)
Any ideas?
Here is what should work.
(I took the liberty of simplifying your database call making it require much less processing.)
public function show($widget_id)
{
$data = array();
$widget_id = (int) $widget_id;
$item = $this->CI->db
->get_where('widget', array('id' => $widget_id))
->row_array();
$data['widget_title'] = $item['title'];
$data['widget_content'] = $item['content'];
$widget = $this->CI->load->view('widget/'.$item['source'], $data, TRUE);
//clear the cached variables so the next call to 'show()' is clean
$this->CI->load->clear_vars();
return $widget;
}
On further consideration The call $this->CI->load->clear_vars(); is probably pointless because each time WidgetManager::show() is called the $data var is recreated with exactly the same keys. When the $data var is passed to load->view the new values of $data['widget_title'] and $data['widget_content'] will replace the values in the cached vars using those keys.

Why redirect show blank page in model laravel?

I'd like to ask why the following code works, redirects normally, and data is successfully inserted :
CategoriesController :
public function store()
{
$data = Input::all();
$category = new Term;
if($category->saveCategory($data)){
return Redirect::route('admin_posts_categories')->withSuccess('Category successfully added.');
}else{
return Redirect::route('admin_posts_categories')->withError('Failed to add category. #ErrorCode : 13');
}
}
Term model :
public function saveCategory($data){
$this->name = $data['name'];
$this->slug = $data['slug'];
if($this->save()){
$category_taxo = new TermTaxonomy;
$category_taxo->term_id = $this->lastCategoryId();
$category_taxo->taxonomy = 'category';
$category_taxo->description = $data['description'];
if($category_taxo->save()){
return true;
}else{
return false;
}
}else{
return "#Error Code : 4";
}
}
Where as the following only inserts the data but then shows a blank page and doesn't redirect :
CategoriesController :
public function store()
{
$data = Input::all();
$category = new Term;
$category->saveCategory($data);
}
Term Model
public function saveCategory($data){
$this->name = $data['name'];
$this->slug = $data['slug'];
if($this->save()){
$category_taxo = new TermTaxonomy;
$category_taxo->term_id = $this->lastCategoryId();
$category_taxo->taxonomy = 'category';
$category_taxo->description = $data['description'];
if($category_taxo->save()){
return redirect::route('admin_posts_categories')->withSuccess('Category successfully added.');
}else{
return redirect::route('admin_posts_categories')->withError('Failed to add category.');
}
}else{
return redirect::route('admin_posts_categories')->withError('#Error Code : 4.');
}
}
Moreover, I'd like to ask a few related questions, does my code conform to correct design patterns, and where should I put the redirect, in the model or in the controller ?
Try this for redirect:
1. return Redirect::back()->withSuccess('Category successfully added.');
OR
2. return Redirect::to(URL::to('admin_posts_categories'))->withSuccess('Category successfully added.');
Add your redirect login inside Controller. Even if you want to put in model (which is not recommended) use Ardent Hook function i.e. afterSave().
First of all never put redirect logic in model. Models are for putting business logic. Second thing check whether you have created route for admin_posts_categories in route.php or not and how you are calling views. If possible post your route code in question.
I recommend not putting redirects in your model. So the first solution would be the best of the two you have.
But back to your problem. It is showing a blank page because your store function is not returning anything. return $category->saveCategory($data); but as previously stated this method is not best practise.
An excellent tip would be to have a look at Laracasts, this will teach you everything you knew, didn't know and more about Laravel.

not able get flashdata in CodeIgniter

Here is my controller code
function index() {
echo $this->session->flashdata('message');
$this->load->view('categoryView');
}
function delete() {
$products = $this->item_model->get_category_id($category_id);
if (count($products)) {
$message = 'Category Name is used by the product. Please change them to another category!';
}
else {
$category_id = $this->product_category_model->delete($category_id);
$message = ($category_id) ? 'Category Deleted Successfully' : 'Failed to Delete Category';
}
$this->session->set_flashdata('message', $message);
redirect('category', 'refresh');
}
After calling the delete function the flashdata has to be set and retrieve that value in index() function of the same controller but I can't.
Am also tried the $this->session->keep_flashdata('message'); before redirect to index function. But still am not get any value in index function.
Also changed $config['sess_expire_on_close'] = FALSE; to $config['sess_expire_on_close'] = TRUE; Still am not get the result.
I am wasted more time(nearly half day). Please anybody help to retrieve the flas data in codeigniter.
There are several probabilities:
1- Check your browser cookie. See if it allows cookies or if any other extension is intervening.
2- Refresh might not send the browser a new request (which thus mean a new URL). Try it for another controller see if it make any change
3- hard code the set_flashdata() with hard-coded value than a variable. set_flashdata("message", "Thank you");
In codeingitor you cannot echo anything in controller.
You have to set in $this->session->flashdata('message'); in view file not in index() function of controller
Try again by putting $this->session->flashdata('message'); in "categoryView" file where you want to display flash message.
You could try:
function set_flashdata_notification($notify_type, $msg, $error_code = null)
{
$ci =& get_instance();
$flashdata_data = set_notification_array($notify_type, $msg, $error_code);
$ci->session->set_flashdata($flashdata_data);
}
function delete() {
$products = $this->item_model->get_category_id($category_id);
if (count($products)) {
set_flashdata_notification('Category Name is used by the product.','Please change them to another category!');
redirect('path_to_view/view','refresh');
}

Resources