I created an helper and I try to use it in one of my controllers,but I got an error, and I am not sure why.
//StringHelper.php
namespace App\Helpers;
class StringHelper
{
public function example($str1){
//CODE
}
}
//config/app.php
'aliases' => [
'StringHelper' => App\Helpers\StringHelper::class,
]
//In controller
use StringHelper;
$percentage = StringHelper::example($title);
Non-static method App\Helpers\StringHelper::example() should not be
called statically
Because the method example($str1) is not static, you need to call it by instance.
I think you are calling other instance's methods in example, so the simple way is call the method by instance.
$helper = new StringHelper();
$percentage = $helper->example($title);
Or you need to defined all those methods to static.
Related
think about this scenario:
I have a class (for example A) with this constructor. :
public function __construct(SocialChannelContract $channel, CallBackQueryDVO $message)
{
$this->message = $message;
$this->channel = $channel;
}
and this is the register method in AppServiceProvider:
$this->app->singleton(SocialChannelContract::class, MyChannel::class);
now I want to create an instance of class A.
return new A($callBackQueryDVO);
But it returns me this error that you should pass parameter 1 to class A while I introduce the class in AppServiceProvider. what is wrong in this example?
If you want to use constructor injection you need to let the service container make the class:
App::make(A::class);
app(A::class);
app()->make(A::class);
If you want to create the class manually you need to give the constructor all the arguments.
$channel = new SocialChannelContract(...); or $channel = app(SocialChannelContract::class);
Then, new A($channel, $myOtherStuff, ...)
Then
how do they achieve, that Illuminate\Database\Eloquent\Relations\Relation has access to all query builder functions?
I see they have a $query property, but does not explain how all its methods are available inside relation
If you are aware of php magic methods then you will know __call method
this method will be called when you initialize a php object and you try to call a method which is not available in the class. By using __call method from the Illuminate\Database\Eloquent\Relations\Relation class they are forwarding the call to Illuminate\Database\Eloquent\Builder. I will explain it very clearly by pointing out the code.
Inside the laravel framework there is a trait named as ForwardsCalls . This trait is used in many classes to handle the call forwarding to another class.
So here is how the call from the Relation class is forwarded to Builder class. While initilting the new Relation class Builder class will be initialized. So when you try to call a method from reltion class which is not available it will call __call method. After that it will look for a available macros . So when a macros method is not found. Then it will use forwardDecoratedCallTo from ForwardsCalls Trait.
So forwardDecoratedCallTo will accept 3 arguments namely $object, $method and $parameters. Whereas
$object will be $this->query which has a Illuminate\Database\Eloquent\Builder instance.
$method will be the method the you try to access from Builder Method.
$parameters will be the all the parameters that is be passed to the method.
I will try to Demonstrate will the example without the traits and helpers from laravel
class ClassTwo {
public function classTwoMethodOne()
{
dd(__FUNCTION__.' has been called');
}
public function classTwoMethodTwo()
{
dd(__FUNCTION__.' has been called');
}
public function classTwoMethodThree()
{
//you cannot call this method dynamically
dd(__FUNCTION__.' has been called');
}
}
class ClassOne {
public function classOneMethodOne()
{
dd(__FUNCTION__.' has been called');
}
public function classOneMethodTwo()
{
dd(__FUNCTION__.' has been called');
}
public function __call($methodName, $arguments)
{
$methodsTobeForwarededtoClassTwo = [
'classTwoMethodOne',
'classTwoMethodTwo',
// 'classTwoMethodThree'
//i have commented this method so you cannot access it
//from dynamic calls
];
if(in_array($methodName,$methodsTobeForwarededtoClassTwo))
{
return (new ClassTwo)->{$methodName}($arguments);
}
dd(sprintf(
'Call to undefined method ClassTwo::%s()', $methodName
));
}
}
So here comes the testing part.
$classOneobj = new ClassOne;
Basic Test
dump($classOneobj->classOneMethodOne()); will output as classOneMethodOne has been called
dump($classOneobj->classOneMethodTwo()); will output as classOneMethodTwo has been called
Dynamic Call Test
dump($classOneobj->classTwoMethodOne()); will output as classTwoMethodOne has been called
dump($classOneobj->classTwoMethodTwo()); will output as classOneMethodTwo has been called
dump($classOneobj->classTwoMethodThree()); will output as Call to undefined method ClassTwo::classTwoMethodThree() Because i have commented that method in __call function in ClassOne.
If you still need clarity please post a comment
whenever we call a Facade Method it involves Facade design pattern and it called for some hidden class by using Facade. for instance for File, if we call
File::get(public_path().'test.txt');
this will call the method in class
Illuminate\Filesystem\Filesystem
and in this class we will have get($path) method.
Now my question is how Facade Abstract Class is related to File and Filesystem and where Laravel is telling them to call get in Filesystem. is there some kind of register which i am missing ?? i want to find complete link.
If you go in your config/app.php, you will notice that there's an array called aliases which looks like this
'aliases' => [
//
//
//
//
'File' => Illuminate\Support\Facades\File::class,
];
So, basically whenever you call File, the Service Container will try to resolve an instance of Illuminate\Support\Facades\File::class which is just a Facade.
If you look into Illuminate\Support\Facades\File::class, you will see that it contains only one method:
class File extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'files';
}
}
As you can see, it extends the Facade class and whenever a Facade is being resolved, Laravel will try to find a key in the Service Container that is equal to whatever is returned by getFacadeAccessor().
If you check the source of Illuminate\Filesystem\FilesystemServiceProvider, you will see this:
$this->app->singleton('files', function () {
return new Filesystem;
});
As you can see, the key files is being bounded to a FileSystem implementation. So, that's how Laravel knows how to resolve the File facade.
I have an associative array which I use in approx all controllers and i was wondering if possible to define that array somewhere at one place and just use in in all controllers?
Kind of like we do in angular.
Like if i can define it in env file or something.
Please let me know if there is a way.
Creating an entry in the config/app.php
'myVar' => [
'key' => 'value'
],
and accesing it via config('app.myVar')
Put it in a helper file and access using that helper file
check out this answer https://stackoverflow.com/a/32772686/5808894
Using AppServiceProvider
In your app/providers/AppServiceProvider.php in the boot method add this, make sure to import App use App in AppServiceProvider
public function boot()
{
App::singleton('myVar', function(){
return [
'key' => 'value'
];
});
}
and access the variable in your controller using app('myVar');
Reference https://stackoverflow.com/a/25190686/5808894
Mentioning it here since no one else did:
public class SharedArrayContainer {
public static $data = [ 'key' => 'value' ];
}
and you can use it as:
SharedArrayContainer::$data
Not as good as adding it to the service container but this is what pre-framework me used to do.
I would recommend to create a provider class (service) for it and use laravel Service Container for injection. This way you can create helper methods like get, find, etc... and make use of laravels Dependency Injection (having single instance injected whenever & almost everywhere you want)
Laravel docs
class ExampelService
{
// associative array
private arr = []
public function get(item) { }
public function save(item) { }
public function has(item) { }
}
I have UserController and PetController.
In my UserController, I have rewardUser() method.
in my PetController, I'm using the $user variable which indicates the current logged in user.
How I can run my rewardUser() method from my PetController?
I've been trying to user $user->rewardUser(); but for some reasons its not recognizing my method this way.
"Call to undefined method Illuminate\Database\Query\Builder::rewardUser()"
The best way is to use a trait.
Create a trait file, in App\Common.php, for e.g. Then copy the rewardUser() method to the trait.
Your trait file:
namespace App\Forum;
trait Common {
public function rewardUser() {
// Your code here...
}
}
Then in yourUserController.php and PetController.php, use the trait.
// UserController and PetController.php
namespace App\Http\Controllers
use App\Common; // <- Your trait
class UserController extends Controller {
use Common // <- Your trait
public function doSomething() {
// Call the method from both your controllers now.
$this-rewardUser();
}
}
You can use the straight in as many controllers as you want and you can call the method in the straight using $this->methodName().
Very simply and effective.
It seems like you are missing some structure concepts, but if you really need it, you may use the container to do so:
$userController = app()->make(UserController::class);
return app()->call([$userController, 'rewardUser']);
may be you should define the method rewardUser() in the User Model and import it with use App\User