This might not be best practice- however my functions will be rather comprehensive and used by additional controllers, thus I would like to separate them from the controller's public class. (what is best practice? I just want to load the functions to specific pages/controllers.)
Laravel 7
class HomeController extends Controller
{
function add($a, $b) {
print($a + $b);
}
public function show($id) {
add(1,2)
}
}
You shouldn't perform logic in the controller.
I recommend you to create a Calculator folder for example where you store the sum, something like this:
The controller:
declare(strict_types=1);
namespace App\Controller;
use App\Calculator;
final class HomeController extends Controller
{
// $id not needed, although, if you are going to use it,
// try to declare the type!
public function show() {
return (new Calculator())->add(1, 2);
}
}
And the calculation class:
declare(strict_types=1);
namespace App\Calculator;
final class Calculator
{
public function add(float $firstOp, float $secondOp): float
{
return $firstOp + $secondOp;
}
}
PS: Do not print in the controller, you have to follow the SRP (Single Responsibility Principle)! :)
You can replace the return (new Calculator())->add(1, 2); in the show() method by a dd(new Calculator())->add(1, 2)); for example.
Seems like a solution for using a trait a common practice in Laravel.
namespace App\Http\Controllers;
use App\Traits\MySpecialFunctions;
class HomeController extends Controller
{
use MySpecialFunctions;
}
namespace App\Traits;
trait MySpecialFunctions {
function add($a, $b) {
print($a + $b);
}
public function show($id) {
add(1,2)
}
}
Related
I have some repetitive codes inside my laravel(7.23.0)controller
use App\ModelA;
use App\ModelB;
use App\ModelC;
use App\Traits\DbTrait;
class DarsController extends Controller
{
use DbTrait;
public function A($id) {
return ModelA::where('column', $id)->get(*);
}
public function B($id) {
return ModelB::where('column', $id)->get(*);
}
public function C($id){
return ModelC::where('column', $id)->get(*);
}
//the only difference in these codes is model, all codes are the same
}
I had created a folder named Traits and inside that I had defined a trait DbTrait.php
<?php
namespace App\Traits;
trait DbTrait
{
public function getAllz($ModelName , $id){
return $ModelName::where('column', $id)->get('*');
}
}
so I modified my controller's functions to this
public function A($id) {
// return ModelA::where('column', $id)->get(*); works fine
$this->getAllz('ModelA', $id);// throws an error
}
it throws an error message: "Class 'ModelA' not found"
thank you
update:
i should apologize, i am really sorry, 3 of the answer worked, and i see the data inside network tab,i am using vue to display data,
and i think using trait made a complex array
this is my simple vue
axios.get('/api/emla/' + id).then(response =>{
this.data = JSON.parse(JSON.stringify(response.data));
}
Import the classes which will be used in your trait as you have done in the controller class.
use App\ModelA;
use App\ModelB;
use App\ModelC;
the reason you're getting Class 'ModelA' not found is because it's looking for that class in your traits directory, which it won't find. so you need this instead:
<?php
namespace App\Traits;
trait DbTrait
{
public function getAllz($ModelName , $id) {
return app( "\App\\" . $ModelName )::where('column', $id)->get('*');
}
}
assuming that you've defined your models under \App namespace
you need to modify your trait
ModelName::where it try to load the class in trait so use $ModelName->where here $ModelName is already instance of that class so you can call function via -> operator
<?php
namespace App\Traits;
trait DbTrait
{
public function getAllz($ModelName ,$columnName ,$id){
return $ModelName->where($columnName, $id)->get('*');
}
}
and to call this function
$this->getAllz(new ModelA, $id);
this way you don't need to import class inside trait
your final code will be like this
use App\ModelA;
use App\ModelB;
use App\ModelC;
use App\Traits\DbTrait;
class DarsController extends Controller
{
use DbTrait;
public function A($id)
{
return $this->getAllz(new ModelA,'column', $id);
}
public function B($id)
{
return $this->getAllz(new ModelB,'column', $id);
}
public function C($id)
{
return $this->getAllz(new ModelC,'column', $id);
}
}
100% should work if you follow this
public function A($id) {
// return ModelA::where('column', $id)->get(*); works fine
$model = new ModelName(); // new ModelName;
$this->getAllz($model, $id);// throws an error
}
public function getAllz($ModelName , $id){
return $ModelName->where('column', $id)->get('*');
}
I am writing system for players where I use Laravel freamwork (just for learn) and I have question for more experience developer. I have one function which return me some data to view. I use this function in 3 controllers (but i copy and paste this function to each Controller files) and can I just put this function in one file and then use it in these 3 controllers? How can I use the same function in diffrent controller without copy and past?
You can also use Traits to share methods, however, traits are more usually for describing characteristics and types.
You should create a utility class, or use consider an abstract controller class if this is desired.
You can create Base Controller:
<?php
namespace App\Http\Controllers;
class BaseController
{
protected $playersRepository;
public function __construct(PlayersRepository $playersRepository)
{
$this->playersRepository = $playersRepository;
}
}
Which is injected with a repository object:
<?php
namespace App\Http\Controllers;
class PlayersRepository
{
public function getPlayers()
{
return Player::all();
}
}
Which has a common method, that can be used in more than one extended controller:
Games
<?php
namespace App\Http\Controllers;
class Games extends BaseController
{
public function index()
{
return view('games', ['players' => $this->playersRepository->getPlayers()]);
}
}
Matches
<?php
namespace App\Http\Controllers;
class Matches extends BaseController
{
public function show()
{
return view('matches', [
'matches' => $matches,
'players' => $this->playersRepository->getPlayers()
]);
}
}
Create module (util) or override main Controller class.
I have MyRequest.php class extending App\Http\Requests\Request. I want to trim() every input before validation because an e-mail with a space after it does not pass validation.
However sanitize() was removed from src/Illuminate/Foundation/Http/FormRequest.php
Create an abstract SanitizedRequest class that extends the usual Request class.
YourRequest class should extend your SanitizedRequest abstract class.
Your SanitizedRequest class overrides Request::all() as like so...
namespace App\Http\Requests\Forms;
use App\Http\Requests\Request;
abstract class SanitizedRequest extends Request{
private $clean = false;
public function all(){
return $this->sanitize(parent::all());
}
protected function sanitize(Array $inputs){
if($this->clean){ return $inputs; }
foreach($inputs as $i => $item){
$inputs[$i] = trim($item);
}
$this->replace($inputs);
$this->clean = true;
return $inputs;
}
}
Then a normal CustomRequest, but extend SanitizedRequest instead of laravel's Request class
class ContactRequest extends SanitizedRequest{
public function authorize(){ return true; }
public function rules(){ return []; }
}
I just came across for the same problem.
I'd like to show you another way of doing it without extends but with traits. ( I will take the Example Classes from Tarek Adam ).
PHP Traits are like functions which will be injected into the used class. The one main difference is that a Trait doesn't need any dependency like a extends do. This means you can use a trait for more then just one class e.x. for Controllers, Requests and whatever you like.
Laravel provides some traits in the BaseController, we can do the same.
How to do it with a trait
Create a trait as file in \App\Traits\SanitizedRequest.php. You can create it anywhere it doesn't matter really. You have to provide the correct namespace for sure.
namespace App\Trait;
trait SanitizedRequest{
private $clean = false;
public function all(){
return $this->sanitize(parent::all());
}
protected function sanitize(Array $inputs){
if($this->clean){ return $inputs; }
foreach($inputs as $i => $item){
$inputs[$i] = trim($item);
}
$this->replace($inputs);
$this->clean = true;
return $inputs;
}
}
In your Request you can use the trait with use SanitizedRequest keyword.
namespace App\Http\Requests\Forms;
use App\Http\Requests\Request;
use App\Trait\SanitizedRequest; // Import the Trait
class ContactRequest extends Request {
use SanitizedRequest; // This line adds all the Trait functions to your current class
public function authorize(){ return true; }
public function rules(){ return []; }
}
In Laravel 9 (not sure about older versions) you can extend \Illuminate\Foundation\Http\Middleware\TransformsRequest middleware and do apply your logic there. So lets say you need to encode your input with htmlemntities() function, create a middleware
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
class TransformsRequest extends \Illuminate\Foundation\Http\Middleware\TransformsRequest
{
/** #inheritDoc */
protected function transform($key, $value)
{
return is_string($value) ? htmlentities($value, ENT_QUOTES, "UTF-8") : $value;
}
}
Dont forget to apply this middleware globally in App\Http\Kernel.php
protected $middleware = [
// other middlewares...
\App\Http\Middleware\TransformsRequest::class,
];
This middleware will encode each value that comes from input for all requests.
I have been facing a problem of not able to use the model inside the controller in the new laravel framework version 5. i created the model using the artisan command
"php artisan make:model Authentication" and it created the model successfully inside the app folder, after that i have created a small function test in it, and my model code looks like this.
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Authentication extends Model {
protected $table="canteens";
public function test(){
echo "This is a test function";
}
}
Now i have no idea, that how shall i call the function test() of model to my controller , Any help would be appreciated, Thanks in advance.
A quick and dirty way to run that function and see the output would be to edit app\Http\routes.php and add:
use App\Authentication;
Route::get('authentication/test', function(){
$auth = new Authentication();
return $auth->test();
});
Then visit your site and go to this path: /authentication/test
The first argument to Route::get() sets the path and the second argument says what to do when that path is called.
If you wanted to take this further, I would recommend creating a controller and replacing that anonymous function with a reference to a method on the controller. In this case, you would change app\Http\Routes.php by instead adding:
Route::get('authentication/test', 'AuthenticationController#test');
And then use artisan to make a controller called AuthenticationController or create app\Http\Controllers\AuthenticationController.php and edit it like so:
<?php namespace App\Http\Controllers;
use App\Authentication;
class AuthenticationController extends Controller {
public function test()
{
$auth = new Authentication();
return $auth->test();
}
}
Again, you can see the results by going to /authentication/test on your Laravel site.
Use scope before method name
<?php
namespace App\Models;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model;
class Mainmenu extends Model
{
public function scopeLeftmenu() {
return DB::table('mainmenus')->where(['menu_type'=>'leftmenu', menu_publish'=>1])->orderBy('menu_sort', 'ASC')->get();
}
}
above code i tried to access certain purpose to call databse of left menu
than we can easy call it in Controller
<?php
Mainmenu::Leftmenu();
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Authentication extends Model {
protected $table="canteens";
public function scopeTest(){
echo "This is a test function";
}
}
Just prefix test() with scope. This will become scopeTest().
Now you can call it from anywhere like Authentication::Test().
For me the fix was to set the function as static:
public static function test() {..}
And then call it in the controller directly:
Authentication::test()
You can call your model function in controller like
$value = Authentication::test();
var_dump($value);
simply you can make it static
public static function test(){
....
}
then you can call it like that
Authentication::test();
1) First, make sure your Model is inside a Models Folder
2) Then supposing you have a model called Property inside which you have a method called returnCountries.
public function returnCountries(){
$countries = Property::returnCountries();
}
of course, in your case, replace Property by the name of your Model, and returnCountries by the name if your function, which is Test
and in the Model you write that function requesting the countries
so in your Model, place a:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Authentication extends Model {
protected $table="canteens";
public function test(){
return $test = "This is a test function";
}
}
and this is what your Controller will be getting
You should create an object of the model in your controller function then you can model functions inside your controller as:
In Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Authentication extends Model {
protected $table="canteens";
public function test(){
return "This is a test function"; // you should return response of model function not echo on function calling.
}
}
In Controller:
namespace App\Http\Controllers;
class TestController extends Controller
{
// this variable is used to store authenticationModel object
protected $authenticationModel;
public function __construct(Request $request)
{
parent::__construct($request);
$this->authenticationModel= new \App\Authentication();
}
public function demo(){
echo $this->authenticationModel->test();
}
}
Output:
This is a test function
I have seen a few posts in various places about this and they all seem to have a similar answer. However for the life of me I cannot get the Mockery object working properly.
The Attribute model looks like this
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Attribute extends Model {
public function test()
{
return (new \App\Models\Value())->hello();
}
}
The Value model like this
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Value extends Model
{
public function hello()
{
return 'goodbye';
}
}
The PHPUnit test looks like this
use App\Models\Attribute;
class AttributeModelTest extends TestCase
{
public function testThing()
{
$mock = Mockery::mock('\App\Models\Value');
$mock->shouldReceive('hello')
->once()
->andReturn('hello');
$this->app->instance('\App\Models\Value', $mock);
$a = new \App\Models\Attribute();
$return = $a->test();
var_dump($return);
}
}
PHPUnit outputs 'goodbye', where I though that I am telling it to return 'hello' in the mock and it doesn't. Any ideas what I might be doing wrong?
As discussed in comments:
Change return (new \App\Models\Value())->hello(); with return (\App::make('App\Models\Value'))->hello();
And in the test: $a = new \App\Models\Attribute(); with $a = App::make('App\Models\Attribute'); so Laravel will resolve the dependencies through the container