What is the equivalent of "always()" in guzzle promises? - promise

I have some code which uses guzzle 5 and I am trying to upgrade it to guzzle 6. One of the changes in guzzle 6 is that it no longer makes use of the react/promise library and instead uses its own promise library. My understanding is that the two are not interchangeable.
There is code which uses the the always() function from react/promise like so:
$promise->then(
// function
)->otherwise(
// function
)->always(
// function
);
The problem I have is that guzzle promises don't have an always() function. According to the react/promise documentation, this function acts as cleanup for a promise chain in a similar way to the finally block in a try/catch/finally sequence.
How can I emulate this?

Put the code from the always in both then and otherwise

You could create a Promise class which extends from \GuzzleHttp\Promise\Promise
class ReactCompatiblePromise extends \GuzzleHttp\Promise\Promise {
public function always(callable $always)
{
return $this->then($always, $always);
}
}
But unfortunately you cannot set the Promise class which is used within the guzzle project.
All promises created will always be an instance of \GuzzleHttp\Promise\Promise
If you don't mind doing something hacky then you could take a copy of the file, make your amendments and autoload your file instead.
Keep the original class name (Promise) and namespace \GuzzleHttp\Promise and dont extend or use the original \GuzzleHttp\Promise\Promise class.
Assuming you're using composer you could update your composer.json file to include
{
"autoload": {
"classmap": ["ReactCompatiblePromise.php"]
}
}

Related

Need Laravel Route::controller and Route::controllers

As we know in Laravel 5.2 Route::controller() and Route::controllers() method was deprecated but it was very handy for reducing the number of routes. I was able to write simple route like this Route::controller('admin/invoice','InvoiceController'). With this simple one route, I can manage all things related to making invoice related work by a controller.
class InvoiceController extends Controller{
public function getInvoices(){ }
public function getInvoiceDetails(){ }
public function postStoreInvoice(){ }
public function postUpdateInvoice(){ }
public function postStoreInvoiceDetails(){ }
public function postupdateInvoiceDetails(){ }
public function postDeleteInvoice(){ }
public function postDeleteInvoiceDetails(){ }
....
}
but unfortunately this Route::controller() and Route::controllers() no longer available laravel version > 5.1. An option available Route::resource() but it has a limited number of the route. The laravel route is Macroable, there is an option to extend the route features like
Illuminate\Routing\Router::macro('controller', function ($routes) {
// implementation
});
Is there anyone who implements Route::controller() and Route::controllers() method for Laravel 5.8, 6 ? or suggest any way.
You can use Route::resource() or Route::resources().
Example:
Route::resource('books', 'BookController');
this will assumes you have
class BookController extends Controller {
// to list resources.
public function index();
// to show create form.
public function create();
// to store resource in database.
public function store();
// to show single resource.
public function show();
// to show edit form.
public function edit();
// to edit and then store the modified resource in database.
public function update();
// to delete a resource from database.
public function destroy();
}
You should read https://laravel.com/docs/master/controllers#resource-controllers for more information.
Edit
Implicit controllers was removed in version 5.2 for some reason.
If you come from the CodeIgniter world, then you may have warm and fuzzy
feelings for implicit routing. You know, where the URI matches up to
the controller method that will be called. You might even want this
for your Laravel development (which Laravel can do).
Though it might seem useful at first to simply call
Route::controller('admin', 'AdminController') and then declare all of
your desired routes from the controller, there are a number of
setbacks to this. Think about how you would, when using implicit routing,
leverage named routes, or create nested resources, or even do
something as simple as rename your controller class without affecting
your URI design.
No, when it comes to implicit routing, just say no.
source: https://laracasts.com/lessons/say-no-to-implicit-routing
However if you want this functionality you can use this package:
Laravel Routes Publisher or Laravel Advanced Route

How can I create routes similar to Auth::routes()

I created a laravel package with routes. I want to do something similar to Laravel's authentication scaffolding Auth::routes(), where they are injected into whatever file you want to include them (i.e. api.php or web.php).
I am currently using
public function boot()
{
...
$this->loadRoutesFrom(__DIR__.'/routes/api.php');
...
}
But this makes the routes available from anywhere, which I do not want.
I understand I should use a Service Container, but this is my first package and first time creating my own Service Provider, so I am not too sure how to do so, and I couldn't find documentation on how to use these for routes.
Instead, I want to be able to do something along the lines of:
//routes/api.php
Route::group(['prefix'=>'v1', 'middleware:auth-api'], function(){
Logging::routes(); //<-----
...
});
Simple solution, make a class that has a static method that declares your routes.
// your/package/Logging.php
class Logging
{
public static method routes()
{
...your routes...
}
}
// routes/web.php
use Your/Package/Logging;
Logging::routes();

how to create global function that can be accessed from any controller and blade file

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.

Loading classes only if function is called

I have one FrontendController that get all requests from frontend. As all URLs are like:
Route::get('/{slug}', 'FrontendController#index');
I need to use the same controller to get all Entities. My FrontendController looks like this:
use Auth;
use App;
use Cache;
use URL;
use Redirect;
use Session;
use Response;
use App\Country;
use App\I18n;
use App\User;
use App\CMS;
use App\CMSPageContent;
use App\Slugs;
use App\News;
...
...
use App\Http\Controllers\Controller;
I have several questions regarding this:
Are ALL these services injected in each execution of FrontendController. Because maybe I'm loading the entire code and It will make my page load slow.
If answer to previous question is yes, can I load a library only if one function is called?
Is it a good way to solve the slug problem? Because all URLs have one piece only for SEO reasons and I don't know other way to treat the routes.
It varies depending on how you are using the code. For example if you required the Auth login method, but nothing else, it would be a waste of resources to initialise a model or inject the model into that function.
For example say this is a function in my model
public function doSomething()
{
//Do stuff
}
I would like to call this function in my Controller. I have a few options, I could reference the model at the top of my controller
use App\MyModel;
I believe this doesn't actually initiate the model, it acts like a reference, so that when it is called, the system knows where to find it.
I could inject it into my function
public function myControllerFunction(\App\MyModel $model)
{
return $model->doSomething();
}
This uses the most resources due to the model being assigned to the $model variable, which is fine if you need the models eloquent for database actions and its functions. If you require just one function from that model then a static call would use less resources.
In your model make the function static
public static function doSomething()
{
}
Then in your controller you can call it like this
public function myControllerFunction()
{
return \App\MyModel::doSomething();
}
This would use the less resources and would clean up the code a bit as you wouldn't need to keep referencing your uses at the top of the controller

How to extend laravel 4 core?

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.

Resources