Proper way to create a service provider in Laravel - laravel

I am having trouble creating a service for my Laravel application. I wish to use this service to easily communicate with an API to perform IO operations. To be specific, my Laravel application needs to communicate with InvoiceNinja. There is an invoiceninja/sdk-php which I am using to facilitate this communication. According to their docs, it is used like this:
require __DIR__ . '/vendor/autoload.php';
use InvoiceNinja\Config as NinjaConfig;
use InvoiceNinja\Models\Client; // Model can be Invoice, Payment, etc
NinjaConfig::setURL('https://ninja.dev/api/v1');
NinjaConfig::setToken('Your Token');
$clients = Client::all();
The code snippet above is an example of using the API to fetch a list of clients. Now, since I am using Laravel, I did not see the need of setting the API URL and Token every time I needed to send a request to the API. And so I decided to use a Service Provider. Below is my code in InvoiceNinjaServiceProvider.php register method:
$this->app->singleton(NinjaConfig::class, function ($app) {
NinjaConfig::setURL(config('invoice-ninja.API_URL')); // I created a config/invoice-ninja.php which has these variables set
NinjaConfig::setToken(config('invoice-ninja.API_TOKEN'));
});
I then registered this provider in config/app.php. I thought that would be enough to use the API in my controllers like this:
use InvoiceNinja\Models\Client;
public function index(InvoiceNinjaServiceProvider $invoiceNinja)
{
$clients = Client::all();
dd($clients); // To test that I actually receive data
}
But I get an error Unresolvable dependency resolving [Parameter #0 [ <required> $app ]] in class Illuminate\Support\ServiceProvider. I am not very well versed with Service Providers and I am hoping someone out there can point me in the right direction to get this to work.
Thank you. Thank you!

You should return the resolved instance when you bind your singleton, the instance will be injected as a parameter in yout index method.
From the doc:
$this->app->singleton('HelpSpot\API', function ($app) {
return new \HelpSpot\API($app->make('HttpClient'));
});
note the return

Related

Laravel use query in creating event

what is best and clean way to insert a query value on creating event model like this (Laravel 5.7)
public static function boot() {
parent::boot();
self::creating(function ($model) {
$model->person_job = App\Job::where('person_name',$request->name);
});
}
i don't wanna put this routine query in my controller , so what do professional developers here?
You can use request() function(helper) anywhere in your project if you have no $request variable.
In MVC architecture logic must locate in Controller mostly, Here in Laravel, events mostly are used to do some specific logic(I think that logic mostly does not rely on a user's given data as you do here) on every model based on the event, for example, if you want to generate a unique_id for each Model on created || creating event, or doing caching or something like that.
See here for more about events.

security with method not working

I'm trying to set up security on my entities in API Platform and found that I can call a method instead of the property example used in the docs (found this in some example somewhere on the web):
* attributes={"access_control"="is_granted('ROLE_USER') and object.belongsTo(user)"},
This is necessary in my case as I keep the user account data seperate from the user profile data and the entity in question is linked to the profile, not the user entity.
This works like charm on an individual getter (/api/data/{id}) but fails with a server 500 error on the list (/api/data):
"hydra:description": "Unable to call method \"belongsTo\" of object
\"ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator\".",
Wondering what is going wrong and how to fix it.
the "belongsTo()" method is fairly simple:
public function belongsTo(User $user) {
return $user == $this->owner->user;
}
Try this way
Create custom extension

Non-static method Cartalyst\Sentinel\Sentinel::getUser() should not be called statically

Hi I am using laravel Sentinel as my Auth, also I am trying to use laravel auditing I am getting "Non-static method Cartalyst\Sentinel\Sentinel::getUser() should not be called statically".
In my user model I have added a static function resolveId() for adding user_id in Laravel Auditing 'audits' table
public static function resolveId(){
return Sentinel::getUser()->getUserId();
//return auth()->check() ? auth()->user()->getAuthIdentifier() : null;
}
When I try to use \Sentinel::getUser() I am getting the error below.
Non-static method Cartalyst\Sentinel\Sentinel::getUser() should not be called statically
From the docs:
After installing the package, open your Laravel config file located at config/app.php and add the following lines.
In the $aliases array add the following facades for this package.
'Sentinel' => Cartalyst\Sentinel\Laravel\Facades\Sentinel::class,
Then just add this to the top of the class:
use Sentinel;
Put this use on top of the file in question:
use Cartalyst\Sentinel\Laravel\Facades\Sentinel;
I'm aware that the package version #manikandan k was asking help for is 4.x or 5.x, and while the documentation does mention the use case for Sentinel, it doesn't provide an actual example.
Since version 6.x, the Audit Resolvers documentation has this very use case, where Sentinel is used instead.
I suggest updating the resolver logic to the following:
return Sentinel::check() ? Sentinel::getUser()->getUserId() : null;
This will prevent calling getUserId() on null, when a user isn't logged.

laravel routing based on convention

I'm trying to setup a simple routing system based on convention.
My app will have this structure
Http
--Controllers
----Admin
------User.php
----Books
------Add.php
----etc...
I want to be able to add new Folders and controllers without adding routes manually to the web.php file.
For example I want the route to respond to /Admin/User URL with User.php controller.
I'm trying something like this, but I don't understand how to write the internal router...
Route::any('/{module}/{action?}', function($module, $action = 'index') {
Route::get('*',$module.'\'.$action.'#index' );
});
It seems that Rout:get('*'... never matches.
PS the controller namespace is correct and I reloaded with composer.
The controller works if called harcoded.
I tried also to escape '\'
$r=$module.'\\'.$action.'\\'.$action.'Ctl#index';
Route::get('/',$r );
But no result. The route is intercepted but nothing i served
It seems I came up with this
Route::get('/{module}/{action}', function($module,$action) {
return App::make('\App\Http\Controllers\\'
.$module.'\\'.$action)->callAction('index', []);
});
Any other better way?

How can I render a twig template in a custom controller in Silex?

I'm playing with Silex microframework to build a very simple app.
The Silex documentation briefly illustrates how to keep your code organised using controller as class and I've also found this useful article talking about the same practice:
https://igor.io/2012/11/09/scaling-silex.html
but still can't solve my problem
The issue:
in my app.php I'm using
$app->get('/{artist}', 'MyNamespace\\MyController::getAlbum');
This is working. MyController is a class correctly loaded through composer using psr-4.
At the moment the return method of getAlbum($artist) is return $player;
What I'd like to do instead, is returning a twig view from getAlbum, something like:
return $app['twig']->render('player.twig', $player);
To do so, what I've tried to do in my custom class/controller is:
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
[...]
public function getAlbum(Request $request, Application $app, $artist)
but this is generating the following error when I try to access the routed pages:
ReflectionException in ControllerResolver.php line 43:
Class MyNamespace\Request does not exist
Whic made me think that there's a namespace conflict between myNamespace and the Silex namespaces?!
What am I doing wrong?
Is this the right way to make $app visible in my custom controller in order to use return $app['twig']... ?
Thank you in advance!
EDIT
After several other tries still didn't get to the point (replies still welcome!) but I've found a workaround solution that could be useful to anyone will incur in a similar issue. Directly in my app.php I added this
$app->get('/{artist}', function (Silex\Application $app, $artist) use ($app)
{
$object = new MyNamespace\MyController();
$player = $object->getAlbum($artist);
return $app['twig']->render('player.twig',
array(
//passing my custom method return to twig
'player' => $player,));
});
then in my player.twig I added:
{{player | raw}}
And this basically means that I still need an anonymous function to get use of my custom method which is a working solution I'm not really happy with because:
I'm using 2 functions for 1 purpose.
The return value of getAlbum is dependent from the use of "raw" in twig.
SOLVED
The workflow described works fine. It was a distraction error: I've placed the namespace of my custom class after use Symfony\Component\HttpFoundation\Request;
namespace declaration in PHP needs always to be at the top of the file, Silex wasn't able to injects $app and $request for this reason.

Resources