How to configure middleware in DI in Slim 3 - php

I want to configure several middleware in Dependency Container in Slim, so that I can set several constants in a same place and add middleware in a ease.
E.G.
$configuration = [
'settings' => [
'displayErrorDetails' => true,
],
'auth_settings' => [
'serect' => 'garyAPIserver',
],
];
$container = new Slim\Container($configuration);
$container['auth'] = function ($c) {
return new AuthMiddleware($c['auth_settings']);
};
$app = new Slim\App($container);
And I try to invoke the middleware in DI:
$app->add($app->get('auth'));
And I got the warning message print by php:
Warning: Missing argument 2 for Slim\App::get(), called in E:\www\slimServer-3.0\index.php on line 12 and defined in E:\www\slimServer-3.0\vendor\slim\slim\Slim\App.php on line 146
And the error message print by Slim:
Type: RuntimeException
Message: is not resolvable
File: E:\www\slimServer-3.0\vendor\slim\slim\Slim\CallableResolver.php
Line: 82
I am new in Slim, there it possible to set middleware in DI? Is there any guides with the similar scenario?

You can do it using the $container variable:
$app->add($container->get('auth'));
Then you can use it in your router functions using:
$auth = $this->get('auth');
Take a look here for more information.

Related

How do I pass a registered service singleton into another registered service's constructor in Laravel 7?

I have recently been learning about the AppServiceProvider. I have registered a service in the AppServiceProvider which creates a singleton - an instantiated GuzzleHttp Client, like so:
$this->app->singleton('GuzzleHttp\Client', function($api) {
return new Client([
'base_uri' => env('ELASTICSEARCH_HOST'),
'auth' => [
env('ELASTICSEARCH_USER'),
env('ELASTICSEARCH_PASS')
],
]);
});
This is connecting to an ElasticSearch API, and that currently works:
$response = app('GuzzleHttp\Client')->request('GET');
I have set up a facade called ElasticSearchFacade, which contains only the getFacadeAccessor():
protected static function getFacadeAccessor()
{
return 'elasticSearch';
}
I have also registered elasticSearch in my AppServiceProvider, like so:
$this->app->bind('elasticSearch', function() {
return new ElasticSearch();
});
This creates a new ElasticSearch instance. However, I would love to pass the GuzzleHttp\Client into the elasticSearch service. So I have tried adding the following to my ElasticSearch.php file:
use GuzzleHttp\Client;
class ElasticSearch
{
protected $client;
public function __contruct(Client $client)
{
$this->client = $client;
}
public function handle()
{
$response = $this->client->request('GET');
die($response->getBody()->getContents());
}
}
I have now changed the registered service to pass through the GuzzleHttp Client like so:
$this->app->bind('elasticSearch', function() {
return new ElasticSearch(app('GuzzleHttp\Client'));
});
However I am getting the error:
PHP Error: Call to a member function request() on null
The constructor method is __construct not __contruct. You have not defined a custom constructor for your ElasticSearch class. So that member variable is null.
Side Note: do not call env outside of the configuration files.
To avoid having to make these env calls outside of configuration files you can just add configuration files as needed or add to current configuration files. Something like Elastic Search credentials can probably get added to the services.php configuration file:
<?php
return [
...
'elasticsearch' => [
'host' => env('ELASTICSEARCH_HOST'),
'user' => env('ELASTICSEARCH_USER'),
'password' => env('ELASTICSEARCH_PASS'),
],
...
];
Now that you have these in the configuration you can use the configuration system to pull these values:
config('services.elasticsearch'); // that whole array of values
config('services.elasticsearch.host'); // just that host value
Config::get('services.elasticsearch');
app('config')->get(...);
There are multiple ways to access the configuration system.

How to use Symfony Messenger component in standalone code to send AMQP messages

We're using Symfony Messenger in a Symfony 5 project to integrate with RabbitMQ. It works fine when sending messages within Symfony, but I need the ability to use the Messenger component to send messages from some legacy PHP applications that are not built with the Symfony framework.
Under Symfony, it handles all the magic by injecting the MessageBusInterface and all I need to do is something like this:
public function processTestMessage(MessageBusInterface $bus)
{
$bus->dispatch(new TestMessage('Hello World!');
}
I need to somehow instantiate my own version of $bus that will send AMQP messages the same way that Symfony does. I've been trying to recreate everything that Symfony does behind the scenes to accomplish this, but have not been able to put all the details together.
The crux of the problem is to create my own SendMessageMiddleware that does the same thing as Symfony. After that, it's simple:
$sendersLocator = ???
$eventDispatcher = ???
$sendMessageMiddleware = new($sendersLocator, $eventDispatcher);
$bus = new MessageBus([$sendMessageMiddleware]);
Does anyone have any examples of working code that uses the Messenger component to send AMQP messages outside of Symfony?
This can be improved but it works for me:
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface;
$sendersLocator = new class implements SendersLocatorInterface {
public function getSenders(Envelope $envelope): iterable
{
$connection = new Connection(
[
'hosts' => 'localhost',
'port' => 5672,
'vhosts' => '/',
'login' => 'guest',
'password' => 'guest'
],
[
'name' => 'messages'
],
[
'messages' => []
]
);
return [
'async' => new AmqpSender($connection)
];
}
};
$middleware = new SendMessageMiddleware($sendersLocator);
$bus = new MessageBus([$middleware]);
$bus->dispatch(new MyMessage());
I modified the above answer to let me pass the RabbitMQ credentials as an environment variable. This is what I needed for my application. I was trying to write my own DSN parser and discovered that Symfony already does it, so I basically lifted the code from there.
If the environment variable is not set, it defaults to use the same settings shown in the example above.
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface;
$sendersLocator = new class implements SendersLocatorInterface {
public function getSenders(Envelope $envelope): iterable
{
$dsn = getenv('MESSENGER_TRANSPORT_DSN') ?: $_ENV['MESSENGER_TRANSPORT_DSN'];
$connection = Connection::fromDsn($dsn);
return [
'async' => new AmqpSender($connection)
];
}
};
$middleware = new SendMessageMiddleware($sendersLocator);
$bus = new MessageBus([$middleware]);
$bus->dispatch(new MyMessage());

Lumen 5.5 Socialite Providers doesn't works with setConfig()

I use Laravel Socialite Providers (https://socialiteproviders.github.io/) to login user on Lumen 5.5 API.
setConfig() method, to force config, doesn't works for me...
Here below, my error and my code. The problem is that I do not know why I have this error.
Display Error:
Type error: Argument 1 passed to
Laravel\Socialite\SocialiteManager::formatConfig() must be of the type
array, null given, called in
/home/vagrant/www/project1/api.website.app/vendor/laravel/socialite/src/SocialiteManager.php
on line 125
PHP code:
$clientId = env('TWITTER_KEY');
$clientSecret = env('TWITTER_SECRET');
$redirectUrl = env('TWITTER_REDIRECT_URI');
$additionalProviderConfig = [];
$config = new SocialiteConfig($clientId, $clientSecret, $redirectUrl, $additionalProviderConfig);
return Socialite::with('twitter')->stateless()->setConfig($config)->redirect();
You need to configure services configuration first! Create a services.php file inside config folder (you may create this one if you don't have it already).
File services.php
return [
'twitter' => [
'client_id' => env('TWITTER_KEY'),
'client_secret' => env('TWITTER_SECRET'),
'redirect' => env('TWITTER_REDIRECT_URI'),
]
];
Your code should be like this:
use Laravel\Socialite\Facades\Socialite;
// You may not this one, read below explanation
app()->configure('services');
return Socialite::with('twitter')->stateless()->redirect();
It is better if you move the configure line to bootstrap/app.php file:
// Just right before register SocialiteProvider
$app->configure('services');
$app->register(SocialiteProviders\Manager\ServiceProvider::class);
If you have moved this configure, your code now should be:
use Laravel\Socialite\Facades\Socialite;
return Socialite::with('twitter')->stateless()->redirect();
PS:
If you have call to undefined stateless method, it means you don't set the listener yet, you can read here. Open your App\Providers\EventServiceProvider, add this line:
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
'SocialiteProviders\Manager\SocialiteWasCalled' => [
'SocialiteProviders\Twitter\TwitterExtendSocialite#handle',
]
];
}
And don't forget to add this line to your bootstrap/app.php file:
$app->register(App\Providers\EventServiceProvider::class);

Slim 3: how to access settings?

Before the Slim 3 is released, codes below work fine:
settings.php,
return [
'settings' => [
'displayErrorDetails' => true,
'modules' => [
'core' => 'config/core/modules.php',
'local' => 'config/local/modules.php'
],
],
];
index.php
// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$app = new \Slim\App($settings);
$MyClass = new MyClass($app);
MyClass.php
class MyClass
{
private $app;
public function __construct($app)
{
$this->app = $app;
$local = require $app->settings['modules']['local'];
}
But after the release, I get this error below:
Notice: Undefined property: Slim\App::$settings in /...
So I can't use $app->settings anymore? What should I use then?
You can get settings like this:
$container = $app->getContainer();
$settings = $container->get('settings');
You can access settings route callables via $this
$modulesSettings = $this->get('settings')['modules']['local'];
For more information read here
The address of the SLIM 3 configuration file is pro/src/settings.php,
and you can add additional settings; In any route you can access them like this:
var_dump($this->get('settings')['logger']);

Phalconphp OAuth2.0 Wrapper problems

I am trying to get this phalconphp OAuth2.0 wrapper working on my OAuth2.0 server.
The README of this repository is not very clear on how to use the namespaces.
I have followed the guide but I keep getting the following error :
Fatal error: Class 'Sum\Oauth2\Server\Storage\Pdo\Mysql\Client'
not found in C:\localhost\oauth2-phalcon\public\index.php on line 56
Here is my index.php file :
<?php
require __DIR__."/../vendor/autoload.php";
// Setup IIS Rewrite Rules
// Enable the verbs GET,PUT,POST,DELETE
// Check URL Scan for dissallowed seperators eg ; :
$config = new \Phalcon\Config([
'database' => [
'oauth' => [
'host' => 'localhost\test',
'port' => 1433,
'instance' => 'INSTANCENAME',
'username' => 'test',
'password' => 'test',
'dbname' => 'oauth',
'pdoType' => 'sqlsrv',
'dialectClass' => '\Twm\Db\Dialect\Mssql'
],
],
# ...
]);
# Register The Lib to the loader
$loader = new \Phalcon\Loader();
$loader->registerNamespaces([
"Twm\Db\Adapter\Pdo" => "../app/library/db/adapter/",
"Twm\Db\Dialect" => "../app/library/db/dialect/",
"League" => "../vendor/league/oauth2-server/src/League/OAuth2/Server",
//"Sum\Oauth2\Server\Storage\Pdo" => "../Oauth2/Server/Storage/Pdo/Mysql",
"Sum" => "../Oauth2/Server/Storage/Pdo/Mysql",
//"Sum\Oauth2\Server\Storage\Pdo\Mysql" => "../Oauth2/Server/Storage/Pdo/Mysql "
# ...
])->register();
$app = new \Phalcon\Mvc\Micro();
# set as service
$app->setService('oauth', function() use ($config) {
// HERE! We use our custom MSSQL Adapter
//$oauthdb = new Phalcon\Db\Adapter\Pdo\Mysql($config->database->oauth->toArray());
$oauthdb = new \Twm\Db\Adapter\Pdo\Mssql($config->database->oauth->toArray());
$server = new \League\OAuth2\Server\Authorization(
new \Sum\Oauth2\Server\Storage\Pdo\Mysql\Client($oauthdb),
new Sum\Oauth2\Server\Storage\Pdo\Mysql\Session($oauthdb),
new Sum\Oauth2\Server\Storage\Pdo\Mysql\Scope($oauthdb)
// new \Sum\Oauth2\Server\Client($oauthdb),
//new \Sum\Oauth2\Server\Session($oauthdb),
//new \Sum\Oauth2\Server\Scope($oauthdb)
);
# Not required as it called directly from original code
# $request = new \League\OAuth2\Server\Util\Request();
# add these 2 lines code if you want to use my own Request otherwise comment it
$request = new \Sum\Oauth2\Server\Storage\Pdo\Mysql\Request();
$server->setRequest($request);
$server->setAccessTokenTTL(86400);
$server->addGrantType(new League\OAuth2\Server\Grant\ClientCredentials());
});
$app->get('/hello', function() use($world){
$world = "world";
echo "hello {$world}:)";
});
$app->get('/access', function () use ($app) {
try {
$params = $app->oauth->getParam(array('client_id', 'client_secret'));
echo json_encode(
$app->oauth
->getGrantType('client_credentials')
->completeFlow($params)
);
} catch (\League\OAuth2\Server\Exception\ClientException $e) {
echo $e->getTraceAsString();
} catch (\Exception $e) {
echo $e->getTraceAsString();
}
});
$app->handle();
//echo $app->handle()->getContent();
The project repository for the phalcon wrapper is here :
https://github.com/sumeko/phalcon-oauth2
I have contacted the author already but he is not replying to my emails.
I appreciate any help or advice, thanks.
UPDATE
So I solved my issue. Basically you need to have the standard OAuth2 library installed via composer and the phalconphp OAuth2 wrapper.
That solved it :)
This might be a long shot, but the problem might be with the autoloader that you are explicitly defining. If you use composer's autoload, you don't need to include Sum namespace in Phalcon's loader. Remove all vendor-specific paths from $loader->registerNamespaces() and only use require __DIR__ . "/../vendor/autoload.php" for that.
Also, it's often more convenient use composer's autoloader for your internal things too, e.g.:
{
"require": {
"phpunit/dbunit": "*",
"phpunit/phpunit": "*",
"…": "…"
},
"autoload": {
"psr-0": {
"": "../src"
}
}
}
So I solved my issue. Basically you need to have the standard OAuth2 library installed via composer and the phalconphp OAuth2 wrapper. That solved it :)

Categories