Hi can anyone clarify this for me. I have a rather large Laravel 4 app using a few models. I would like to upgrade to L5 and would simply like to use the same model calls in the controllers.
e.g.
Course::
\Course:: //if controller in a deeper folder
The course model is in App/Models. I've tried a composer mapping App/Models but to no avail.
Thanks
I don't know about anyone else. But in my installation of Laravel 5, my models are defined directly within the app folder. The app directory is psr-4 namespaced as App.
composer.json
"autoload": {
...
"psr-4": {
"App\\": "app/"
}
}
Models are then defined under the App namespace. e.g.
namespace App;
use Illuminate\Database\Eloquent\Model;
class Course extends Model {
}
So you can either:
1: Use the full path to the model whenever you use it:
\App\Course::all();
2: use your model before using it like you normally would:
namespace Your\Namespace;
use App\Course;
class YourClass {
public function yourFunction()
{
Course::all();
}
}
3: Create a folder called Models, put your models in there and make sure that their namespace reflects the path (And then call the model like in options 1 and 2):
// app/Models/Course.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Course extends Model {
}
e.g.
\App\Models\Course::all();
or
namespace Your\Namespace;
use App\Models\Course;
class YourClass {
public function yourFunction()
{
Course::all();
}
}
That's just how namespaces work. If you specify a class PHP will always search for it relative to the current namespace. Unless you prepend a backslash and use the full path or add an import statement at the beginning of your files:
namespace App\Http\Controllers;
use App\Models\Course;
class ...
Or
\App\Models\Course::all();
I should add that many editors and IDEs are able to automatically resolve and import classes, so with the right tools it's not that cumbersome...
Related
I am new to Laravel and would appreciate any help on describing how a Laravel package residing in vendor folder can be extended and wont get affected if I update the package.
I'll try to create a brief guide, and we'll expand if need be.
I suggest putting all of your files inside a separate directory / namespace. You'll benefit from this should you decide to create your own composer package afterwards.
As an example I'll extend bumbummen99/shoppingcart package which forks the great gloudemans/shoppingcart, adding support for Laravel 5.8 and some minor functionality. You will of course first need to install that package:
composer require bumbummen99/shoppingcart
Start by making a couple of folders. You can use any name for folders / classes, this is what I used, relative to the project root:
app/Repositories/ExtendedCart
app/Repositories/ExtendedCart/Facades
Create the file
app/Repositories/ExtendedCart/ExtendedCart.php
This class will extend the package's main class:
namespace App\Repositories\ExtendedCart;
use Gloudemans\Shoppingcart\Cart;
class ExtendedCart extends Cart
{
public function myMethod(){
return 'myMethod';
}
}
Then make your Service Provider. Create the file:
app/Repositories/ExtendedCart/ExtendedCartServiceProvider.php
(I'm not using artisan as generating / moving the provider will produce wrong namespace)
This is your Service Provider content, here you reference the class that extends the package's class. Note you overwrite the binding from the original package.
namespace App\Repositories\ExtendedCart;
use Gloudemans\Shoppingcart\ShoppingcartServiceProvider;
class ExtendedCartServiceProvider extends ShoppingcartServiceProvider
{
public function register()
{
$this->app->bind('cart', 'App\Repositories\ExtendedCart\ExtendedCart');
}
}
Then register your service provider in config/app.php
'providers' => [
...
//Add this line to the end of providers array
App\Repositories\ExtendedCart\ExtendedCartServiceProvider::class,
]
Lastly create a Facade, which will instantiate the class (otherwise you will get non-static method exceptions). Create this file:
app/Repositories/ExtendedCart/Facades/ExtendedCart.php
This is the contents of the file:
namespace App\Repositories\ExtendedCart\Facades;
use Illuminate\Support\Facades\Facade;
class ExtendedCart extends Facade {
protected static function getFacadeAccessor() { return 'cart'; }
}
You're all set to use your extended methods. You can safely upgrade the original package, and you can even use the default facade:
namespace App\Http\Controllers;
use Cart;
class SomeController extends Controller{
public function someFunction(){
Cart::instance('default')->myMethod();
//This should return 'myMethod'
}
}
I hope this helps, good luck!
I created a new folder in the directory app which is called Services. So the directory of Services is app/Services. I want to use now a file of Services called Connection.php in a Controller app/Http/Controllers but when I try that, I get following error:
Class App\Services\Connection does not exist
I also tried to add the directory and file in my composer.json but this didn't fixed it either.
Controller:
namespace App\Services;
namespace App\Http\Controllers;
use App\Services\Connection;
use Illuminate\Http\Request;
class ExampleController extends Controller
{
protected $conn;
public function __construct(Connection $conn)
{
$this->conn = $conn;
}
Composer.json
"autoload": {
"classmap": [
"database",
"app/Services"
],
"autoload-dev": {
"classmap": [
"tests/TestCase.php",
"app/Services/Connection.php"
]
},
Edit 17.12.2016: (problem not solved yet)
Thanks for all who stick with me so long on this problem! I'm sry, if I gave too less information so I'll sum up few things that I tried.
1 => Deleted the secound namespace App\Services
2 => Added routes(or directory) to my composer.json ( like above )
3 => Used composer updated and composer dump-autoload
4 => Used use App\Services\Connection (the path to my connection class in Services, which I want to use in my ExampleController in App\Http\Controllers\ExampleController)
Connection class:
class Connection
{
//Some guzzle stuff
}
So the ExampleController looks exact as above just without the Services namespace anymore and I get exact the same error. What am I doing wrong?
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Contracts\Auth\Guard;
use App\Http\Controllers\Controller;
use App\Services\Connection;
class ExampleController extends Controller
{
public function __construct(Guard $auth, Connection $conn)
{
$this->auth = $auth;
$this->conn = $conn;
}
}
Please try to use this code.
Presented this solution as a comment but to make it easier for future viewers:
The solution to this is to ensure that proper name spacing is in all files being referenced including the controller and the classes. If the namespace isn't correct it won't be able to access it.
In this case you have to make sure that the namespace for the Connection class was using App\Services as the namespace and that the controller accessed it in the same namespace of App\Services\Connection.
The error is on your namespace declaration. you are declaring two namespaces for the same class!
namespace App\Services;
namespace App\Http\Controllers;
The last one will be used.
Remove the App\Http\Controllers namespace line.
Also remember that you should import the base controller:
use App\Controllers\Controller;
Why?
When you try to use App\Services\ExampleController, composer will look for that class in the autoload paths, but since your namespace is different, it will not be able to load it.
Is there a way to prevent using 'use' for everything. In Laravel 4 I never used 'use' and everything just worked. I'm now finding out I have to include everything, even 'DB' use DB. This is extremely frustrating and time consuming looking all this up.
My question is, is there an easier way to include everything?
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Customer;
use DB;
class HomeController extends Controller {
}
?>
Thanks
Not really -- this is the Brave New Namespaced world of PHP 5.3+. Your class file above lives in the App\Http\Controllers namespace, which means when you type something like
$object = new SomeClass;
PHP will assume you mean the class App\Http\Controllers\SomeClass.
You'll either, as you complained about, need to use use, or you'll need to use the full classname (with a leading \ to let PHP know to start from the global namespace) whenever you want to use a class
class HomeController extends Controller {
public function someFunction()
{
$result = \DB::query(...);
$customer = new \App\Models\Customer;
//etc...
}
}
This is question is old but I found you can do this based on information from a tutorial by Tejas Jasani: http://www.theappguruz.com/blog/upgrading-from-laravel-4-2-to-5-in-web
Here are the key steps:
1 - Add the app/Http/Controllers directory to the "autoload" classmap directive of your composer.json file.
"autoload": {
"classmap": [
"database",
"app/Http/Controllers"
],
2 - Remove the namespace from the abstract app/Http/Controllers/Controller.php base class.
3 - In app/Providers/RouteServiceProvider.php file, set the namespace property to null
protected $namespace = null;
4 - Run "composer dump-autoload" from the command line.
I have a new installation of Laravel 5. The problem is that it's not recognizing my model classes. I will keep it very simple for solution purposes.
Route::get('test', function() {
$test = boxstyle::all();
....
}
My model is in the app directory
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Boxstyle extends Model {
protected $table = 'boxstyle';
protected $primaryKey = 'key1';
}
I am getting:
class boxstyle not found error
I've been searching all over the internet and can't find a solution. This installation is fresh. This isn't magic and I suspect a configuration issue but I can't find a solution. This works fine in Laravel 4.2 so I know it should work but not working in L5.
Your model is defined inside the App namespace. If the code accessing the model is not in the same namespace as the model, you need to qualify it.
Route::get('test', function() {
$test = \App\Boxstyle::all();
}
Laravel 4 did not define the models and controllers inside namespaces. Your models would have been defined inside the global namespace, so any code also in the global namespace (like your controller) would not need to qualify the model. However, Laravel 5 has made the push to put most everything inside namespaces.
To create a model in Laravel 5 try this,create a folder name "Models" folder under your App folder, now for instance you want to create a Model class for Boxstyle ...under your Models folder create a file name
"BoxstyleModel.php" inside your BoxstyleModel.php should look like this and make sure your inside the folder to namespace your model under the App\Models
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class BoxstyleModel extends Model {
public static function say_hello(){
return "Hello";
}
}
in your Boxstyle Controller to be able to use your BoxstyleModel added this code at the top of your BoxstyleController use App\Models\BoxstyleModel;
now everything should be the same like Laravel 4.X.
i want to use the alias classes on laravel 4 "facades" like App::method , Config::method.
Well the thing is that i create a custom class and i have to import the namespaces like
<?php
namespace Face\SocialHandlers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
public function registrar($perfil) {
Config::get('facebook');
}
}
is there any way to use those classes like in controllers or routes files of the framework ?
like
<?php
namespace Face\SocialHandlers;
//use Illuminate\Support\Facades\App;
//use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
public function registrar($perfil) {
Config::get('facebook');
}
}
Cya
ps: sry for my english
You can use use Config; instead of the more verbose use Illuminate\Support\Facades\Config; and the autoloader should handle it correctly.
Just as a tip, you shouldn't hardcode dependencies in your code. Instead of using the facades, you could create an "ConfigInterface" to get the common dependencies you need. Then create a "LaravelConfig class" (Or Laravel4Config.php) and implement those methods.
For a Quick Fix Answer, "catch the underliying facade instance":
namespace Face\SocialHandlers;
//use Illuminate\Support\Facades\App;
//use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
protected $config;
protected $app;
public function __construct()
{
$this->config = \Illuminate\Support\Facades\Config::getFacadeRoot();
$this->app = \Illuminate\Support\Facades\App::getFacadeRoot();
}
public function registrar($perfil) {
$this->config->get('facebook');
}
}
For a Real Answer, maybe tedious, but good in the long run, instead of using the facades use an interface.
interface SocialConfigInterface
{
public function getConfigurationByKey($key)
}
Then
class Laravel4Config implements SocialConfigInterface
{
protected $config;
public function __construct()
{
$this->config = \Illuminate\Support\Facades\Config::getFacadeRoot(); //<-- hard coded, but as expected since it's a class to be used with Laravel 4
}
public function getConfigurationByKey($key)
{
return $this->config->get($key);
}
}
And Your Code
namespace Face\SocialHandlers;
//use Illuminate\Support\Facades\App;
//use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
protected $config;
public function __construct(SocialConfigInterface $config)
{
$this->config = $config;
}
public function registrar($perfil) {
$this->config->get('facebook');
}
}
This way, if you want to change between frameworks you just need to create a SocialConfigInterface Implementation, or imagine the scenario where Laravel 5 wont use Facades, you want your code to be independent of "outsider changes" this is inversion of control IoC
First run,
php artisan dump-autoload
This will add your class namespace to vendor/composer/autoload_classmap.php. Now locate the entry for your class in this classmap array and get the proper namespace from there.
For example, you will get something like,
'Illuminate\\Support\\Facades\\App' => $vendorDir . '/laravel/framework/src/Illuminate/Support/Facades/App.php',
For this particular entry you have an alias in app/config/app.php
'App' => 'Illuminate\Support\Facades\App',
At the same way, locate your entry and use an alias in app/config/app.php.
You just have to create a folder, or place a class wherever already is listed for autoload. Me, for exemple, have this class PDFMaker, that uses a DomPDF Laravel implementation. I created a folder named libraries and put the path to it (under the app folder) in the autoload:classmap key on composer.json
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/libraries",
"app/models",
"app/helpers",
"app/database/migrations"
]
I did the same with commands for artisan commands! When you do that, you only have to declare a new object for any class under that folder, or call it in a static way, if the class has defined static methods. Something like Class::method.
Hope it helps you, have a nice day! :D
EDIT: After that, don't forget the dump-autoload for placing the new class in autoload scope.
EDIT 2: Remember that once you've put the class on autoload, it will be in same scope the others, so you won't have to import it to other, neither others to it!
You can also prefix the class names with a backslash, to use the global namespace: \Config::get('facebook') and \App::someMethod() will work without the need to add a use statement, regardless of the file's namespace.