I have 2 models:
Bill:
id, account_id, descripcion, monto_pagado, saldo
Payment:
id, bill_id, monto
Each time someone insert a new bill to the account or insert a new payment I pretend to calculate the balance of the account.
What would be the best place to accomplish this:
as service
as mutators in the model
as function in the controller
I know i would have to call this in others places of my project. So i would like it to be a global function. What would be the best place to do it?
You could use an event in your models. Use creating if you want to calculate before the model is actually created in the database, or created if you want to calculate after it has been created.
In your App\Providers\AppServiceProvider::boot() method, define the events for both models:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Bill::creating(function ($bill) {
// Do something with $bill
});
}
// etc
}
To avoid code repetition, you may use a trait and use it in both classes. Call it PretendCalculationTrait for example and place it in app/Traits (create the directory if needed):
<?php
namespace App\Traits;
trait PretendCalculationTrait
{
public function pretendCalculate()
{
// Do your stuff
}
}
Then in your model, use this trait:
class Bill extends Eloquent
{
use App\Traits\PretendCalculationTrait;
// etc.
}
Finally, in your AppServiceProvider, call the method defined in the trait:
public function boot()
{
Bill::creating(function ($bill) {
return $bill->pretendCalculate();
});
Payment::creating(function ($payment) {
return $payment->pretendCalculate();
});
}
See Laravel Model Events documentation for more details.
One possible solution, since you mentioned wanting it to be a global function, is to use Laravel's autoloading feature.
Create a file that contains the function for your calculation. It can be placed anywhere, and contain other functions, but for brevity we'll place it here: App/Http/customFunctions.php. In your file, create your function:
function pretendCalculation()
{
return $something;
}
Next, tell Laravel to autoload it by adding it to your autoloading list in composer.json:
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/Http/customFunctions.php" <-- Here is the new file
]
Then just execute a composer dump auto-load -o or the like, and now you'll have access to this file/all functions within the file, anywhere in your application.
Related
I have created a model like below
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class countData extends Model
{
//
public function countAbc () {
// i don't know how to write in laravel query so for understanding purpose i wrote in simple pg query
$sql=pg_query("select count(*) as countrow from s_abc");
$countfetch=pg_fetch_array($sql);
return $countfetch[0];
}
}
I don't have any route for this function. On view page I am check
#if( $Item->ClassID == 'abc' )
{
//then call the above model and use countAbc () function
countAbc();
}
Basically my view is already loaded, I need to check the condition and call the above model to count the data.
I think you're looking for helper function.
In question you've created countAbc() function and you want to call it everywhere.
Use to make function in helpers.php file instead of model file
Create a helpers.php file in your app folder and load it up with composer:
"autoload": {
"classmap": [
...
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/helpers.php" // <---- ADD THIS
]
},
After adding that to your composer.json file, run the following command:
composer dump-autoload
Afterward, put your this function in helpers.php
public function countAbc () {
$sql=pg_query("select count(*) as countrow from s_abc");
$countfetch=pg_fetch_array($sql);
return $countfetch[0];
}
Now, You can access it anywhere.
public function countAbc () {
$counts_abc = \DB::table('s_abc')->count();
return $counts_abc;
}
Create a model that corresponds to the table:
php artisan make:model Sabc
Open that model file, and set the table name:
protected $table = 's_abc';
If you want to get the count of the amount of rows within your table that corresponds to the model, it's simple:
Sabc::count();
First Of All I think you have to look Laravel Framework structure: Laravel Directory Structure And contents inside it.
Basically you don't have to define route to fetch data from database.
You have to define model properly - long story short every table in your database have to have one model in your app.
You have tablse s_abc You have to define model SAbc.
php artisan make:model SAbc - this command will make model for you.
After that you can use Eloquent aggregate functions to get count or you can write your own method in it:
Using Aggregate function:
...
use App\SAbc;
...
class SomeClass {
...
$count_sabc = SAbc::count();
...
}
...
Using Your Own Method
In your model write:
...
class SAbc extends Model {
public function getCount() {
return self::count();
// Or with raw query
// return self::selectRaw('count(*) as count')->first()->count
}
}
...
// Then you can use this methd anywhere you want like that:
(new SAbc)->getCount();
Hope this helps you
I have created some library services in app\Library. I used AppServiceProvider to bind that service using following code:
$this->app->bind('App\Library\Globalfunction', function ($app) {
return new Globalfunction();
});
app\Library\Globalfunction.php
<?php
namespace App\Library;
class Globalfunction {
protected $_ci;
public $siteConfig=array();
public $smtpConfig=array();
public $socialConfig=array();
public $paramConfig;
public $paramFrom;
public function test($param) {
return $param;
}
}
?>
To use this test() in controller i am including namespace using following:
use App\Library\Globalfunction;
once namespace is included i use following code:
$globalFunction = new Globalfunction();
echo $globalFunction->test('hello');
All of this code working fine but i don't want to add use App\Library\Globalfunction; in each file so is there anyway i can do that? is there any autoload file where i can put this and i can access Globalfunction?
I google solution for that and i tried several solutions like add this in composer or create package etc but it's not working so please if anyone have solution for this problem please let me know.
Maybe you can follow the same approach as Laravel?
Let me give you an example on how to achieve this.
First, create a Helpers.php file in app/Helpers.php.
You also need to autoload it.
"autoload": {
"classmap": [
"database/seeds",
"database/factories",
"database/providers"
],
"files": [
"app/Helpers.php"
],
"psr-4": {
"App\\": "app/"
}
}
Once that is done, you could define a function as such in your newly autoloaded Helpers.php:
if(! function_exists('global_function')) {
function global_function()
{
return new \App\Library\Globalfunction();
}
}
Then to use it anywhere, you can just do this.
global_function()->test('hello');
This is just a simple example. Obviously there are a lot of considerations you have to make before implementing this.
However, Laravel has a similar approach to providing global helper functions. For example:
use Illuminate\Support\Facades\Session;
// This
echo Session::get('key');
// is the same as
echo session()->get('key');
I have two controller file homecontroller and backendcontroller. What is the best way to create global function and access it from both files?
I found here Arian Acosta's answer helpful but I wonder if there is an easiest way. I would appreciate any suggestions.
Solution
One way to do this is to create a class and use its instance, this way you can not only access the object of the class within a controller, blade, or any other class as well.
AppHelper file
In you app folder create a folder named Helpers and within it create a file name AppHelper or any of your choice
<?php
namespace App\Helpers;
class AppHelper
{
public function bladeHelper($someValue)
{
return "increment $someValue";
}
public function startQueryLog()
{
\DB::enableQueryLog();
}
public function showQueries()
{
dd(\DB::getQueryLog());
}
public static function instance()
{
return new AppHelper();
}
}
Usage
In a controller
When in a controller you can call the various functions
public function index()
{
//some code
//need to debug query
\App\Helpers\AppHelper::instance()->startQueryLog();
//some code that executes queries
\App\Helpers\AppHelper::instance()->showQueries();
}
In a blade file
Say you were in a blade file, here is how you can call the app blade helper function
some html code
{{ \App\Helpers\AppHelper::instance()->bladeHelper($value) }}
and then some html code
Reduce the overhead of namespace (Optional)
You can also reduce the overhead of call the complete function namespace \App\Helpers by creating alias for the AppHelper class in config\app.php
'aliases' => [
....
'AppHelper' => App\Helpers\AppHelper::class
]
and in your controller or your blade file, you can directly call
\AppHelper::instance()->functioName();
Easy Solution:
Create a new Helpers folder in your app directory.
Create a php file named your_helper_function.php in that Helpers directory.
Add your function(s) inside your_helper_function.php
function your_function($parameters){
//function logic
}
function your_another_function($parameters){
//function logic
}
Add this file to the Files key of your composer.json like
"autoload": {
...
"files": [
"app/Helpers/your_helper_function.php"
]
...
}
Finally, regenerate composer autoload files. (Run this in your project directory)
composer dump-autoload
That's it! and now you can access your_function() or your_another_function() in any part of your Laravel project.
If you still have any confusion, check my blog post on how to do this:
How to Add a Global Function in Laravel Using Composer?
Updated:
Step 1
Add folder inside app folder
app->Helper
Step 2
add php Class inside Helper folder
Eg. Helper.php
Add namespace and class to the Helper.php
namespace App\Helper;
class Helper
{
}
Register this Helper.php into config/app.php file
'aliases' => [
....
'Helper' => App\Helper\Helper::class
]
Now, write all the functions inside Helper.php and it will be accessible everywhere.
How to access from Controller?
Step 1 - Add a namespace at top of the controller.
use App\Helper\Helper;
Step 2 - Call function - Assume there a getInformation() inside the Helper Class.
$information = Helper::getInformation()
In your Controller.php which extends BaseController, you can create a function like;
public function data($arr = false)
{
$data['foo'] = 'bar';
return array_merge($data,$arr);
}
And from any controller when you send a data to a view;
public function example()
{
$data['smthg'] = 'smthgelse';
return view('myView',$this->data($data));
}
The data in the the main controller can be accessed from all controllers and blades.
The Laravel Service Provider way
I've been using global function within Laravel for a while and I want to share how I do it. It's kind of a mix between 2 answers in this post : https://stackoverflow.com/a/44021966/5543999 and https://stackoverflow.com/a/44024328/5543999
This way will load a file within a ServiceProvider and register it within your Laravel app.
Where is the difference, the scope, it's always about the scope.
Composer //Autload whitin composer.json method
|
|--->Laravel App //My method
|
|--->Controller //Trait method
|--->Blade //Trait method
|--->Listener //Trait method
|--->...
This is a really simplist way to explain my point, all three methods will achieve the purpose of the "Global function". The Traits method will need you to declare use App\Helpers\Trait; or App\Helpers\Trait::function().
The composer and service provider are almost about the same. For me, they answer better to the question of what is a global function, because they don't require to declare them on each place you want to use them. You just use them function(). The main difference is how you prefer things.
How to
Create the functions file : App\Functions\GlobalFunctions.php
//App\Functions\GlobalFunctions.php
<?php
function first_function()
{
//function logic
}
function second_function()
{
//function logic
}
Create a ServiceProvider:
//Into the console
php artisan make:provider GlobalFunctionsServiceProvider
Open the new file App\Providers\GlobalFunctionsServiceProvider.php and edit the register method
//App\Providers\GlobalFunctionsServiceProvider.php
public function register()
{
require_once base_path().'/app/Functions/GlobalFunctions.php';
}
Register your provider into App\Config\App.php wihtin the providers
//App\Config\App.php
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
...
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
App\Providers\GlobalFunctionsServiceProvider::class, //Add your service provider
Run some artisan's commands
//Into the console
php artisan clear-compiled
php artisan config:cache
Use your new global functions
//Use your function anywhere within your Laravel app
first_function();
second_function();
Laravel uses namespaces by default. So you need to follow the method described in that answer to setup a helper file.
Though in your case you want to access a method in different controllers. For this there's a simpler way. Add a method to you base controller app/Http/Controllers/Controller.php and you can access them in every other controller since they extend it.
// in app/Http/Controllers/Controller.php
protected function dummy()
{
return 'dummy';
}
// in homecontroller
$this->dummy();
There are a few ways, depending on the exact functionality you're trying to add.
1) Create a function inside Controller.php, and make all other controller extend that controller. You could somewhat compair this to the master.blade.php
2) Create a trait, a trait can do a lot for you, and keeping ur controllers clean. I personally love to use traits as it will look clean, keep my Controller.php from being a mess with tons of different lines of code.
Creating a global function
create a Helpers.php file under a folder, let's name it 'core'.
core
|
-- Helpers.php
namespace Helpers; // define Helper scope
if(!function_exists('html')) {
function html($string) {
// run some code
return $str;
}
}
In your composer.json
"autoload": {
"psr-4": {
},
"files": [
"core/Helpers.php"
]
}
in the file that you want to use it
// the " use " statement is not needed, core/Helpers is loaded on every page
if(condition_is_true) {
echo Helpers\html($string);die();
}
Remove the namespace in Helpers.php if you want to call your function without the need to prefix namespace. However I advise to leave it there.
Credit: https://dev.to/kingsconsult/how-to-create-laravel-8-helpers-function-global-function-d8n
By using composer.json and put the function containing file(globalhelper.php) to the autoload > files section, then run
composer dump-autoload
You can access the function inside the file(globalhelper.php) without having to calling the class name, just like using default php function.
When using a separate class for a model observer, where exactly should I register the observer? The documentation says to call User::observe(new UserObserver); but I’m not sure where the best place to do this would be.
https://laravel.com/docs/5.4/eloquent#observers
Since an observer is just a collection of events you are listening to, I'd say place it where Laravel suggests you place individual events: on the boot method of the model itself.
class User extends Eloquent
{
public static function boot()
{
parent::boot();
User::observe(new UserObserver);
}
}
Where to put the UserObserver class is a little more flexible and depends on how complex it will end up being.
For simple observers
If you can bare having it load every time the app runs, create an app/observers.php file, then put this at the end of your app/start/global.php:
require app_path().'/observers.php';
Alternatively, you can use composer to autoload that one file, by appending your composer.json:
{
"autoload": {
"classmap": [
//...
],
"files": [
"app/observers.php"
]
}
}
For more complex observers
If you plan to have many different observers, I'd say create your own namespace and let Laravel / Composer do the autoloading for you. In order to do that, create a folder like app/MyNamespace/Observers, then place each observer file inside of it (each named exactly like the class -- i.e. UserObserver.php).
Your UserObserver.php class should now look like this:
<?php
namespace MyNamespace\Observers;
class UserObserver
{
public function saving($model)
{
// ...
}
public function saved($model)
{
// ...
}
}
And you'll have to declare the full class whenever you are using it:
User::observe(new MyNamespace\Observers\UserObserver);
Or:
use MyNamespace\Observers\UserObserver;
class User extends Eloquent
{
public static function boot()
{
parent::boot();
User::observe(new UserObserver);
}
}
Finally, edit your composer.json and add your namespace to follow PSR-0 autoloading:
{
"autoload": {
"classmap": [
//...
],
"psr-0": [
"MyNamespace": "app/"
]
}
}
PS: Don't forget to run composer dump-autoload after editing composer.json.
I am a newb learning laravel 4. I want to override specific helper functions. Or add new functions to Url, Str etc. How to do this?
Depending on what part of Laravel you want to extend or replace, there are different approaches.
Macros
Adding functions to Str is really easy, because of "macros":
Here's a short example for adding function:
Str::macro('test', function($str) {
return 'Testing: ' . $str . '!';
});
You can then call this function as expected:
echo Str::test('text'); // Outputs "Testing: text!"
Adding functions using macros are supported by Str, Form, HTML and Response.
IOC Based Extension
To extend URL one must use the IOC of Laravel. This is explained in the docs (as mentioned by BenjaminRH). I agree it can be a bit hard to understand. Here's a step-by-step to extend URL:
Create folder app/lib to hold your extension classes.
Add this folder to autoloading:
In app/start/global.php, append the lib path to the class loader:
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/lib'
));
Then add the path to composer.json classmap:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/lib"
]
},
Create the custom UrlGenerator app/lib/CustomUrlGenerator.php:
<?php
use \Illuminate\Routing\UrlGenerator;
class CustomUrlGenerator extends UrlGenerator
{
public function test()
{
return $this->to('/test');
}
}
Create a service provider app/lib/CustomRoutingServiceProvider.php:
<?php
use \Illuminate\Routing\RoutingServiceProvider;
class CustomRoutingServiceProvider extends RoutingServiceProvider
{
public function boot()
{
App::bind('url', function()
{
return new CustomUrlGenerator(
App::make('router')->getRoutes(),
App::make('request')
);
});
parent::boot();
}
}
Register the service provider in app/config/app.php:
Add CustomRoutingServiceProvider to the providers array.
For example, right after the Workbench provider:
'Illuminate\Workbench\WorkbenchServiceProvider',
'CustomRoutingServiceProvider',
Run composer dump-autoload from project root folder.
Done. Use like:
URL::test();
NOTE The code is tested, but may contain some errors
Interesting that you should mention this, actually. A whole documentation section was just recently added, which covers this in detail. It's very clear, and easy to understand. If you've been using Laravel at all, it might not even surprise you that Laravel actually provides an extend method for a lot of core components.
Following Fnatte's answer, today's versions of Laravel do some extra processing in the url binding. Redefining the whole binding is no longer a practical option.
Here is how I ended up for extending the URL facade.
First, create your child class using this boilerplate:
use Illuminate\Routing\UrlGenerator;
class YourUrlGenerator extends UrlGenerator {
public function __construct(UrlGenerator $url)
{
parent::__construct($url->routes, $url->request);
}
// redefine or add new methods here
}
Then, add this in a ServiceProvider:
$url = $this->app['url'];
$this->app->singleton('url', function() use ($url)
{
return new YourUrlGenerator($url);
});
The point is simply that the original url binding should be executed at least once before we override it with our own.