I'm developing a package which has controllers in it and I want this package to be compatible with (or useable by) both Laravel and Lumen projects. My problem is Laravel controllers extend Illuminate\Routing\Controller and Lumen controllers extend Laravel\Lumen\Routing\Controller. The controller inside my package can't extend them both.
The only solution I've come up with is to have the controllers inside the package extend App\Http\Controllers\Controller.
But I see some problems:
App\Http\Controllers\Controller should exist; which means it wouldn't work if the App namespace is named differently.
The package is now "aware" that it is being included in something.
Testability: I can't test the controller independently because of the reference to App\Http\Controllers\Controller.
Is there a better way of doing this?
Edit 1
I'm finding other classes which are affected in a similar way. For example, the namespace of the trait Authorizable is Illuminate\Foundation\Auth\Access in Laravel while it is Laravel\Lumen\Auth in Lumen. I am using a model which uses that trait. How do I make my model compatible with both Lumen and Laravel?
Well, you could simply have two different files and classes wrapped in if statements and check for the corresponding classes to extend. So:
LaravelClass.php:
if(class_exists(Illuminate\Routing\Controller:class)){
class LaravelClass extends Illuminate\Routing\Controller {
use YourCodeTrait;
// any more code that is not in your trait
}
}
LumenClass.php
if(class_exists(Laravel\Lumen\Routing\Controller:class)){
class LaravelClass extends Laravel\Lumen\Routing\Controller {
use YourCodeTrait;
// any more code that is not in your trait
}
}
Loading both files will only load one of the classes. In the code above I use a trait to load the contents of your controller, assuming the contents is the same, you could use the same trait and not have to repeat yourself.
trait YourCodeTrait{
// whatever would normally go in your controllers
}
Related
I've performed a long-overdue update on a Laravel project from v5.7 to v9 and ran into a Target class does not exist error. I found this guide and used the first method to resolve the error (adding the namespace into the RoutesServiceProvider.php boot function). This resolved that error but now, everything is giving me Class "App\Whatever" not found.
I did notice that models are now stored in a Models directory within the app directory rather than directly in app, so have moved them to Models. I figured that might be breaking my use App\Whatever; lines at the top of my controllers, so I've tried use App\Models\Whatever and also use app\Models\Whatever (since the "a" is lowercase in the directory name) but no effect.
I should note I don't really have a good grasp of namespaces, MVC frameworks etc. so ELI5 etc :-)
Some of my controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Thing;
use App\AnotherThing;
...
public function thing_summary($id) // show the summary view of the thing
{
if(Auth::check()) {
$thing = Thing::find($id);
...
Laravel 7/8/9 sticks with strict namespacing. When you move the models to a new directory, you need to update the namespace in the models themselves (if specified at all) and any file that has a use for the model. If the models move from app/ to app/models, the namespace must be changed to App/Models
I have developed a package containing package controllers. Everything is loading and working fine, but currently the package controller looks like this:
<?php
namespace MyPackage\App\Http\Controllers;
use App\Http\Controllers\Controller; // Stock Laravel controller class
use Illuminate\Http\Request;
use Voice\CustomFields\App\Form;
class FormController extends Controller
{
...
}
I want the class to extend Laravel Controller class, however inside my package this class of course doesn't exist as it is a part of a standard Laravel app.
I ended up including use App\Http\Controllers\Controller;, but I don't see it as a good practice since I'm referencing something that doesn't exist up to the point I include my package in the app.
How can I do this the right way? I can replicate the class within my package, but this would be duplicating logic + additional problems if tomorrow a new Laravel version is released with a modified Controller class.
Just look in source code of App\Http\Controllers\Controller
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
You can extend BaseController in your package controllers. If Laravel team change something, it will be written in migration instructions.
If you need some specyfic logic in your package BaseController and the same logic in app BaseController, consider using trait or ServiceProvider.
Your controller doesn't necessarily need to extend the default "base controller". Usually packages either extend the Illuminate\Routing\Controller directly or have their own base controller to extend all the other controllers with.
If you are using the stock base controller without any custom code added, there won't be any duplicate lines if you choose to copy it to your package as it only consists of three optional traits providing helper functions wrapping more complicated code.
I am trying to integrate an existing library into Laravel5 which itself is not namespaced and uses its own classes in subfolders using require.
I have placed it at 'app/API/libname/mainlibclass.php'.
with sibling directory at 'app/API/libname/toolkit' which contains the classes the library uses.
Calling from a Laravel controller I am unable to create the class using a require statement (correct?) before
$objectinstance=new Mainlibclass();
so in the main Laravel app I have
use app/API/libname/Mainlibclass
then later the usual
$objectinstance=new Mainlibclass();
In the existing library and each of its own used classes I set
namespace app/API/libname
and 'use' where needed.
I now have no class not found but one of the files uses 'implements Iterator' - I am getting error Interface 'App\API\libname\Iterator' not found.
Try adding \ in front of that so it looks like this:
class ABC implements \Iterator {
Edit:
I think it would be better practice to keep external non-psr-4/0 libraries untouched (for easier update if needed in future) and outside of app/ directory.
You could use composer classmap autoload feature for this.
I'm totally new to namespaces, and Laravel in general, so their use of Facades complicates the issue a bit for me.
I have set up a class that is namespaced:
namespace Libraries;
class UploadedFile {
}
(As there is already a Symfony class uploadedFile), and now in that class I need to use one of my models, which I can only assume rests somewhere under the Eloquent facade, yet if I:
use Eloquent;
and
use \Eloquent;
in my class, I am told my model cannot be found, yet if I prepend my model with a backslash directly:
return \Object::create(...);
It works perfectly fine. What do I need to use at the top of my namespaced file to include access to my models directly without the need for a slash?
Eloquent has nothing to do with this. You have to import your actual model Object:
use Object;
Like in Codeigniter we do have 'core' folder where we can define our own controller like 'MY_Controller' and can be used to extend all the class to extend from this controller is there any possibility to do so in Symfony2.
In symfony I want to create class 'MY_Controller' which extends from the base class 'Controller', and I want all the classes in the controllers to extend from MY_Controller' class.
Thanks in Advance...
Note:
When working with Symfony2 it is strongly recommended you follow the Symfony2 coding style. It's basically the same as PHP-FIG, with one or two deviations. So underscores are a no-no in class names. Other than that: Symfony is pretty easy to work with, and fully OO, so changing the class a controller extends from is as simple as replacing extends Controller with extends AnotherClass.
But now, the symfony2-way of using a custom controller:
What you could do, is create a Core bundle (CoreBundle henceforth). Then, in this CoreBundle, define a controller, that extends from the Symfony Controller component. From the command line, in your project root, use this command:
php app/console generate:bundle --namespace=YourNameSpace/CoreBundle --bundle-name=YourNameSpaceCoreBundle
More options can be found here
After that, you'll find a DefaultController class in the bundle directories. (probably in the folder src/YourNamespace/CoreBundle/Controller). Then, set about generating your Core controller:
php app/console generate:controller --controller=YourNameSpaceCoreBundle:Core
See the documentation for more options on how to generate your core controller.
After you've finished setting up your custom controller, you can use it in any of the other bundles at will:
namespace YourNameSpace\AnotherBundle\Controller;
use YourNameSpace\CoreBundle\Controller\CoreController;
class DefaultController extends CoreController
{//extends from your custom controller
}
And that's it: you're done.
First, don't name the class using underscores as in PSR-0 each underscore char is converted to a directory separator, when used in class name.
Second, put your controllers to <bundledir>/Controller/
Third, name your controller something like BaseController and extend all other controllers from it.
Fourth, think of using dependency injection rather than coupling functionality in a base controller.