Constructor injection of route parameter - laravel

I have a class which I am injecting into a controller along with a route parameter. I am then using a setter to set the route parameter in the class.
routes
Route::get('path/of/url/with/{paramVar}', 'testController#testFunc)
controller
class testController
{
public function testFunc(MyClassInterface $class, $routeParamVar)
{
$class->setParam($routeParamVar);
//do stuff here
...
service provider
public function register()
{
$this->bind('path\to\interface', 'path\to\concrete');
}
I would instead like to inject the route parameter into the constructor of the class I am injecting into my controller. I know from this question that I need to use the laravel container.
I can inject other route parameters using Request::class, but how can I inject the route path parameter?
I guess I would end up with something like this
class testController
{
public function testFunc(MyClassInterface $class)
{
//do stuff here
...

You can use the $router->input('foo') function to retrieve a route parameter within your service container.
https://laravel.com/api/master/Illuminate/Routing/Router.html#method_input
So in your service provider:
public function register()
{
$this->bind('path\to\interface', function(){
$param = $this->app->make('router')->input('foo');
return new path\to\concrete($param);
});
}
In regards to your comment, it wouldn't reduce the code much, but it might be best in that case to make a second service provider, something like FooValueServiceProvider who's implementation's only job is to retrieve that parameter from the router. Then in each of the bindings you could resolve a FooValueServiceProvider and retrieve the value from that. Then later if you change the name of the route param, or need to resolve it from somewhere other than the route, you only need to change out the implementation of that provider.
I don't know if you can get much more efficient than just the one extra line of code per binding, but at least this way it can be changed out for a different method down the line.

Related

How can I encrypt all ids in URL (laravel 9) using repository pattern

I need to do all url ids encrypted like :
user/edit/1
items/edit/35
posts/details/52
to below url path
user/edit/gd43dfrg
items/edit/sdfg4343
posts/details/fasdf23423
there is lots of areas in repository pattern like UserRepository , UserController blade files and in controllers that id used url ('items/edit/2')
however also in controller some function are passed by objects like
public function itemedit(Items $items)
I tried
$encrypt_val = Crypt::encrypt($value) and $decrypt_val = Crypt::decrypt($encrypt_val );
but I need to do it all over app. There is any short way or Middleware function to do it using repository pattern ?
The proper way to do this would be like so:
Use any boot function of a service provider (e.g. RouteServiceProvider) to define how a route parameter should be invoked:
public function boot()
{
// Bind any `{order}` route parameter such that it decodes the value before retrieving the order.
Route::bind('order', function ($value) {
return User::query()->where('id', $this->yourDecodeFunction($value))->firstOrFail();
});
}
Now when you create urls like route('orders.show', yourEncodeFunction($order->id)) from a route
Route::get('/orders/{order}', /*...*/);
your controller method will receive the expected order in its signature i.e.
public function show(Request $request, Order $order) {
//
}
To improve this code, you can define the getRouteKey() function (part of the UrlRoutable trait) on your Eloquent model to simplify the creation of your routes so that you can call route('orders.show', $order):
// App/Models/Order.php
public function getRouteKey()
{
return yourEncodeFunction($this->getKey());
}
This will make sure that the route parameter is automatically identified when you pass the complete object to the route call (if you don't override this function yourself it uses the model's primary key).
https://packagist.org/packages/hashids/hashids might be a good package for you if you just want to obfuscate some of the url (note that this package is an 'encoder' and not an 'encrypter').

Laravel-Class Method with Reflected Parameters

I usually use parameters like this:
public function test($parameter)
{
echo 'Parameter value: ' . $parameter;
}
While looking at laravel service container I see this code.
public function __construct(UserRepository $users)
{
$this->users = $users;
}
According to the documentation it uses reflection.But i dont understand.
I dont know how the parameter UserRepository $users works. Is that an alias or something?
This is called type-hinting and is used to inject dependencies in a constructor or to validate the right type of argument is passed to a function. The injection simply means that if the class is called with the make method, Laravel will automatically provide an instance of the class required by your constructor.
For example if you have a function public function something(string $something) it would throw an error if any other type than a String is passed to this function, making sure the right data is used.
From the laravel documentation:
Alternatively, and importantly, you may "type-hint" the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, middleware, and more. In practice, this is how most of your objects should be resolved by the container.
For example, you may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class:
Laravel has a great service container and it makes all dependency injections, so you don't need to pass a class a parameter, laravel do it for you.
without container you have to pass this parameter
class A {
public $foo;
public function __construct (Foo $foo){
$this->foo
}
$classA = new A((new Foo))
When laravel encounter with these classes, it resolves them.
Also you can define manually these classes using singleton() or bind() methods
$this->app->singleton('FooBar', function($app)
{
return new FooBar($app['SomethingElse']);
});
Or you may use interfaces. You can bind implemented class for to the interface and laravel when encounter with that interfance, it will resolve as you wish
$this->app->bind('App\ICacheManager', 'App\RedisManager');
public $redis;
public function __contruct(ICacheManager $redis){
$this->redis = $redis;
}
for more further check out laravel service container

How to Call a controller function in another Controller in Laravel 5

im using laravel 5.
I need to call a controller function but this should be done in another controller.
I dont know how to do this
public function examplefunction(){
//stuff
}
And i have a Route for this function, so at
public function otherfunctioninothercontroller(){
// I need examplefunction here
}
how Can i do this?
1) First way
use App\Http\Controllers\OtherController;
class TestController extends Controller
{
public function index()
{
//Calling a method that is from the OtherController
$result = (new OtherController)->method();
}
}
2) Second way
app('App\Http\Controllers\OtherController')->method();
Both way you can get another controller function.
If they are not in the same folder, place use namespace\to\ExampleClass; on top of your file, then you are able to instantiate your controller.
You can simply instantiate the controller and call the desired method as follows
FirstController.php:
namespace App\Http\Controllers;
class FirstController extends Controller {
public function examplefunction() {
// TODO: implement functionality
}
}
SecondController.php:
namespace App\Http\Controllers;
class SecondController extends Controller {
public function test() {
$object = new FirstController();
$object->examplefunction();
}
}
Now, after i've answered the question, i would like to add the following comment:
Controllers are classes, all rules that applies to normal classes can be applied to them
However, instantiating a controller directly inside another controller to call a desired method signifies a problem in your design for the following 2 reasons:
A controller cannot obtain an instance of another controller directly
Controller should contain as little business logic as possible, and if possible none
The closest possible solution to what you want (WITHOUT BREAKING MVC) is to make an HTTP request to the route that points to the desired method (using cURL, for example) and read the response as the returned data
But this still doesn't make much sense in this scenario because after all you're making an HTTP request from a method in a controller in your project on your server to a method in a controller in your project on your server, seems like unnecessary overhead, right ?
As i said earlier, a controller should contain as little business logic as possible because the logic should stay inside specialized classes (commonly known as Service Classes), and when a processing is requested the controller simply delegates the job of processing to the appropriate service class which does the processing and returns the results to the controller which in turn sends it back as a response
Now imagine if you've the following scenario:
We've got an application that consists of 3 functionalities:
A user can register an account from web application
There's a mobile application that talks to an API to register a user
There's an admin panel, which he can use to add new user
Obviously you need to create 3 controllers, but those controllers contains repeated logic, would you copy/paste the code everywhere ?
Why not encapsulate this logic inside a service class and call it from the controller when needed ?
Let's say I have Controller1 and Controller2. I want to call a function of Controller1 from inside a function placed in Controller2.
// Controller1.php
class Controller1 {
public static function f1()
{
}
}
And on the other controller:
// Controller2.php
use App\Http\Controllers\Controller1;
class Controller2 {
public function f2()
{
return Controller1::f1();
}
}
Points to be noted:
f1() is declared static
A call to a controller from inside another controller is a bad idea. There is no sense of meaning of controllers then. You should just redirect to web.php to save safe whole architecture like this:
class MyController {
public function aSwitchCaseFunction(Request $requestPrm){
...
//getting path string from request here
...
switch($myCase){
case CASE_1:
return redirect()->route('/a/route/path');
....
}
}
}

Laravel inject sentry user into model

I keen to make my code decouple and ready for testing.
I have an Eloquent model getBudgetConvertedAttribute is depend on sentry user attribute.
public function getBudgetConvertedAttribute()
{
return Sentry::getUser()->currency * $this->budget;
}
This throw error while testing because Sentry::getUser is return null.
My question is, How shall I code to inject user into model from controller or service provider binding or testing?
Inject a $sentry object as a dependency in the constructor instead of using the Sentry Facade.
Example
use Path\To\Sentry;
class ClassName
{
protected $sentry
public function __construct(Sentry $sentry)
{
$this->sentry = $sentry;
}
public function methodName()
{
$this->sentry->sentryMethod();
}
}
Why not just create a method on the model, then takes a Sentry user object as a parameter?
public function getBudgetConverted(SentryUser $user)
{
return $user->currency * $this->budget;
}
You’ll need to change the type-hint (SentryUser) to the actual name of your user class.
If this is to aid testing, you could go one step furhter and type-hint on an interface (which you should be any way), that way you could test your method with a mock user object rather than one that may have a load of other dependencies like a database connection, which Eloquent models do.

Dynamic router name for magento controller

How would I go about creating a custom module that has a controller with an action name that is dynamic, in the sense that it can be configured by the user in the admin area at will and be automatically updated in the custom module?
You can override this method in your controller:
public function getActionMethodName($action)
{
return 'indexAction';
}
public function indexAction()
{
//action name
var_dump($this->getRequest()->getActionName());
}
Then always will go to the index action, where you can use the original action name as a parameter.
then:
http://mysite/mymodule/mycontroller/im-dracula-blablabla
Will work!
I think you can approach this by using magic php method __call on your controller.
I assumed that you store your action name in a Magento config named 'mymodule/controller/action', so you can get the value using :
Mage::getStoreConfig('mymodule/controller/action');
Then you have the controller for example Mymodule/controllers/TestController.php
And you add the method in that controller like this :
public function __call($method, $arg) {
if ($method == Mage::getStoreConfig('mymodule/controller/action')) {
//Do whatever you want
}
}
This will make your controller //Do whatever you want when you accessing it using the action you specified in the config. The basic idea is like that. Hope this helps.

Resources