How to select disk using Filesystem - laravel-5

So if I have a controller like this:
class ExampleController extends Controller {
protected $filesystem;
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}
How can I tell Filesystem which disk I want to use?
i.e. this does not work:
public function test()
{
$this->filesystem->disk('s3')->doSomething();
}
but this does:
public function test()
{
\Storage::disk('s3')->doSomething();
}
Is there a way to specify which disk I want to use, without using the Facade?

Ok - I worked it out.
You need to use the Factory contract:
use Illuminate\Contracts\Filesystem\Factory as Filesystem;
And that gives you access to the disk() method.

Related

Laravel contextual binding to be more specific to methods rather then class only

I am trying to understand laravel bind.
let's say, I have UploadFileController.php
Route::post('/upload/images', 'UploadFilesController#uploadImage');
Route::post('/upload/pdf', 'UploadFilesController#uploadPdf');
then in the controller,
class UploadFilesController extends Controller
{
private $uploadServiceInterface;
public function __construct(UploadServiceInterface $uploadServiceInterface)
{
$this->uploadServiceInterface = $uploadServiceInterface;
}
public function uploadImage(Request $request)
{
$this->uploadServiceInterface->store();
}
public function uploadPdf()
{
$this->uploadServiceInterface->store();
}
}
Now, the uploadServiceProvider,
class UploadServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->when(UploadFilesController::class)
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
}
}
Now, I know "when" says that UploadFileController class with uploadService interface will give the imageUploadService but is it possible I make it more specific to function in uploadFileController class, like
$this->app->when(uploadFilesController::uploadImage())
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
then it takes to the imagesUploadService class same for pdf upload class.

How to write a custom function in a model?

There is a model data:
class Order extends Model
{
}
How to write a custom method inside the Order class so that it can be called in constructor like this:
Order::myMethod()
Order->myMethod()
Where myMethod is:
public function myMethod() {
return DB::query(<SQL QUERY>);
}
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Rather create a custom function in Model, You can use traits to achieve the desired output.
Please follow either steps:-
https://medium.com/#kshitij206/traits-in-laravel-5db8beffbcc3
https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5
Guess you are asking about the static functions:
class Order extends Model {
public static function myMethod() {
}
}
and you can call it anywhere like
Order::myMethod();
You can achieve the desired behavior using magic methods __call and __callStatic
if your real method is static you can use __call() to intercept all "non static" calls and use it to call the static and use __callStatic to forward the calls to a new instance to that class .
Your methods should be always static because if a non static method exists and you are calling it statically php raises an error
Non-static method Foo::myMethod() should not be called statically
No problem if your method is static
class Order extends Model {
public static function myMethod() {
return static::query()->where(...)->get(); // example
}
public function __call($name, $arguments) {
return forward_static_call_array([__CLASS__, $name], $arguments);
}
public static function __callStatic($name, $arguments) {
return call_user_func_array([app(__CLASS__), $name], $arguments);
}
}
(new Order())->myMethod();
Order::myMethod();
I can't understand your exact problem is. but if you are using laravel, then you can write custom method inside the ABC model like this
class ABC extends Model
{
//here is your fillable array;
public function abc()
{
//Here is your Eloquent statement or SQL query;
}
}
just call this abc() method inside the controller like this
use ABC;
class AbcController extends Controller
{
private $_abc; // it is private variable
// this is constructor
public function __construct(ABC $abc)
{
$this->_abc= $abc;
}
public function abcMethod()
{
$this->_abc->abc();
}
}
Thanks
I don't believe I'm understanding your intention. You've stated:
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Why does the Order->myMethod() need calling inside the constructor? If you're trying to design your data access layer to work efficiently, you can use data repositories.

Laravel: use extended controller or Traits or something else?

To maintain my Laravel application and save myself from a lot of duplicate code I have made the following solution:
BaseController
class BaseController extends Controller
{
public function get($id){
return $this->baseService->get($id);
}
public function getAll(){
return $this->baseService->getAll();
}
}
BaseService
class BaseService
{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function get($id){
return response()->json($this->model->where('id', $id)->first());
}
public function getAll()
{
return $this->model->get();
}
}
MyController
class MyController extends BaseController
{
protected $model;
protected $baseService;
public function __construct(){
$this->model= new Model();
$this->baseService = new BaseService($this->model);
}
/**
* This controller has all the functionality from BaseController now
*/
}
What I'm wondering if this is a good method. Should I stick with this or should I use a different approach? I've heard about Traits but not sure if they are doing the same thing. It's Laravel 5.5 I'm using.
Yes, traits are used to move methods out of a controller regularly. A good example that the Laravel framework uses is the ThrottlesLogin trait. Take a look at https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Auth/ThrottlesLogins.php#L20
to see how the methods are moved outside of a controller but can be still accessed by importing the trait using the use keyword.
While traits would work for your use case I wouldn't use them here for the functionality you are looking for. I would use the repository pattern. It would better separate your code and make it more reusable.
Take a look at https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more information on the repository pattern. Basically, you would separate your code into a separate repository and use Laravel's built in IoC to inject the repository into your controller.
MyController
class MyController extends Controller
{
protected $repo;
public function __construct(MyRepository $myRepository)
{
$this->repo = $myRepository;
}
public function index()
{
$myStuff = $this->repo->all();
}
// you can also inject the repository directly in the controller
// actions.
// look at https://laravel.com/docs/5.5/controllers#dependency-injection-and-controllers
public function other(MyRepository $repo)
{
$myStuff = $repo->all();
}
}
This is the perfect use case for a Trait. Traits are intended for reusable functions. They're super simple to implement, and won't take more than a few minutes to change what you have.
Here is a great article on them: https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5

Injecting Interface on class (Laravel Package)

I'm developing my own L5 package for handling payments. To be able to change the payment gateway in the future, I'm using interfaces.
My interface looks like this:
interface BillerInterface
{
public function payCash();
public function payCreditCard();
}
I also have a concrete implementation, which is the desired payment gateway.
class Paypal implements BillerInterface
{
public function payCash()
{
// Logic
}
public function payCreditCard()
{
// Logic
}
}
The Biller class is the main class, and the constructor method expects the above interface, like so:
class Biller {
protected $gateway;
public function __construct(BillerInterface $gateway)
{
$this->gateway = $gateway;
}
// Logic
}
Last, I created the service provider, to bind the interface to the gateway class.
public function register()
{
$this->app->bind(BillerInterface::class, 'Vendor\Biller\Gateways\Paypal');
}
Seems to be working, but I'm getting an error when trying to instantiate the Biller class...
Biller::__construct() must be an instance of Vendor\Biller\Contracts\BillerInterface, none given
I tried the following code but doesn't seem to work...
public function register()
{
$this->app->bind(BillerInterface::class, 'Vendor\Biller\Gateways\Paypal');
$this->app->bind(Biller::class, function ($app) {
return new Biller($app->make(BillerInterface::class));
});
}
Any clues?
You’re binding interfaces to an implementation fine in your service provider. But dependencies will only be resolved by the service container, i.e.
class SomeClass
{
public function __construct(Billing $billing)
{
$this->billing = $billing;
}
}
Laravel’s service container will read the type-hint of the constructor method’s parameters, and resolve that instance (and also any of its dependencies).
You won’t be able to “new up” the Billing instance directly (i.e. $billing = new Billing) because the constructor is expecting something implementing BillingInterface, which you’re not providing.
When you're binding interface to actual class try replacing the BillerInterface::class with a string '\Your\Namespace\BillerInterface'
This is how I've done it in my app and it seems to be working:
public function register()
{
$this->app->bind('DesiredInterface', function ($app) {
return new DesiredImplementationClass(
$app['em'],
new ClassMetaData(DesiredClass::class)
);
});
}
Talking about #MaGnetas answer
I prefer to bind class with interface using this way.
public function register()
{
$this->app->bind(AppointmentInterface::class, AppointmentService::class);
}
This helps IDEs to find the path of the class and we can jump to that class by just clicking on it.
If we pass class path as string path like shown below:
public function register()
{
$this->app->bind('App\Interfaces\AppointmentInterface', 'App\Services\AppointmentService');
}
Then IDE can not find the location of class when we click on this string.

php class do once for all instances

So I have a class whose constructor downloads some xml and reads it into properties for the class to work with. I'm instantiating this class a couple of times and this time-consuming job is done three times in exactly the same manner. Could I avoid it somehow (I guess with a static method/properties)? My class should only once go get the properties and then every instance could use them. I feel I should put the code out of my constructor in a static function, but how it's done exactly, I don't know, since I always get errors.
class MyClass {
protected $xml_file;
protected $xml_derived_array;
public function __construct($param1, $param2, $param3) {
//get xml_file and make xml_derived_array with it
//do some other stuff with parameters and properties such as $xml_derived_array
}
}
Should become something like: (but how should I call the static properties in my __construct and how should I set the properties in the static function?)
class MyClass {
protected static $xml_file;
protected static $xml_derived_array;
protected static function get_xml() {
//get xml_file and make xml_derived_array with it (?how exactly?)
}
public function __construct($param1, $param2, $param3) {
self::get_xml();
//do some other stuff with parameters and properties such as $xml_derived_array (?how exactly?)
}
}
Edit
This is how it is now working:
class MyClass {
protected static $xml_file;
protected static $xml_derived_array = array();
public function __construct($param1, $param2, $param3) {
if (!self::$xml_file) {
self::$xml_file = simplexml_load_file('xml_file.xml');
self::$xml_derived_array[0] = self::$xml_file->title;
}
echo self::$xml_derived_array[0].$param1;
}
}
You don't need a static method. Just check if the property has a value in constructor and if not get the xml file and process it.
class MyClass {
protected static $xml_file;
protected static $xml_derived_array = array();
public function __construct($param1, $param2, $param3) {
if (! count(self::$xml_derived_array)){
//get xml_file and make xml_derived_array with it
//do some other stuff with parameters and properties such as $xml_derived_array
}
}
}

Resources