Using namespaces in Laravel 4
Namespacing is pretty easy once you get that hang of it.
Take the following example:
app/models/File.php
namespace App\Models;
class File {
public function someMethodThatGetsFiles()
{
}
}
app/controllers/FileController.php
namespace App\Controllers;
use App\Models\File;
class FileController {
public function someMethod()
{
$file = new File();
}
}
Declare the Namespace:
namespace App\Controllers;
Remember, once you've put a class in a Namespace to access any of PHP's built in classes you need to call them from the Root Namespace. e.g: $stdClass = new stdClass();
will become $stdClass = new \stdClass();
(see the \
)
"Import" other Namespaces:
use App\Models\File;
This Allows you to then use the File
class without the Namespace prefix.
Alternatively you can just call:
$file = new App\Models\File();
But it's best practice to put it at the top in a use
statement as you can then see all the file's dependencies without having to scan the code.
Once that's done you need to them run composer dump-autoload
to update Composer's autoload function to take into account your newly added Classes.
Remember, if you want to access the FileController via a URL then you'll need to define a route and specify the full namespace like so:
Route::get('file', 'App\\Controllers\\FileController@someMethod');
Which will direct all GET /file requests to the controller's someMethod()
Take a look at the PHP documentation on Namespaces and Nettut's is always a good resource with this article
Laravel 4 Namespaces routes and namespaces in controllers
Your controller is in the admin
namespace, and referring to other classes from there will be relative to that namespace.
So you need to refer to your model with a preceding backslash (just like you did with BaseController
) like this:
<?php namespace admin;
class ScholarGroupController extends \BaseController
{
public function index()
{
$scholarGroups = \ScholarGroup::paginate(10);
return View::make('scholar_groups.index',compact('scholarGroups'));
}
}
or import it above the class declaration like this:
<?php namespace admin;
use ScholarGroup;
class ScholarGroupController extends \BaseController
{
public function index()
{
$scholarGroups = ScholarGroup::paginate(10);
return View::make('scholar_groups.index',compact('scholarGroups'));
}
}
Also, you don't need to do Route::group
twice. you can do this:
Route::group(array('prefix' => 'admin', 'namespace' => 'admin'), function() {
// . . .
});
How to register a namespace in laravel 4
On the laravel irc channel I found out the namespaces should work in L4 without a need for registering them anywhere. This is because the composer dump-autoload adds them to the composer/autoload file for me. So that was not an issue.
The issue turned out to be a typo apparently(I can't find it in the code above but after going through every line copy/pasting the class names and namespaces something changed), and also somehow in my real code I left out the 'use' statement for EloquentPostRepository.php
use App\Models\Interfaces\PostRepositoryInterface;
Now I've hit another wall trying to use the namespaced interface with ioc and the controller constructor (target interface App\Models\Interfaces\PostRepositoryInterface is not instantiable) but I guess that should be a different question.
Adding a namespace to Laravel 4
If your namespace is
Components
And your application is in
/var/www/application
And your namespaced classes are inside the subfolder
app/API
And this is an example of class file name:
/var/www/application/app/API/Components/Services/Common.php
Then you have to add to your composer json:
"autoload": {
"psr-0": {
"Components": "app/API"
}
},
If you are loading from another base path and your namespaced classes are in /var/www/Components
, you can:
"autoload": {
"psr-0": {
"Components": "/var/www"
}
},
But if they are in /var/www/components/Components
, then you have to
"autoload": {
"psr-0": {
"Components": "/var/www/components"
}
},
Because "Components"
is the base of your namespaces and will always be added to the path before Composer search files to autoload.
Creating a Namespace in Laravel 4
Just to clarify: according to comments, what works in this case is a composer.json formatted this way:
"autoload": {
"classmap": [
<usual data...>
"app/repositories",
"app/services", <---- this is the only entry needed to autoload your services
],
Then you should execute
composer dump-autoload
And check if your class appeared in the file
vendor/composer/autoload_namespaces.php
Laravel 4 Add Method to Class (IoC / Namespaces)
To be honest, I'm pretty new to all this IoC, dependency inversion/injection concept too. But I think I've gone through the same struggle before. What I would do, as much as my knowledge allows, is...
Add a constructor to src/controllers/admin/AdminPageController.php:
protected $pageModule;
public function __construct(PageModule $pageModule)
{
$this->pageModule = $pageModule;
}
Then where you did $module = new PageModule
in the same file. You replace it with:
$module = $this->pageModule;
The two modifications above makes use of Laravel's IoC to allow injecting a different PageModule object into your controller, instead of strictly creating PageModule in your code.
Now at this point Laravel should know that when it constructs the AdminPageController, it should create a PageModule and inject into the controller for you.
Since your controller now expects a PageModule class, you can no longer do class PageModule extends Eloquent
in your app anymore, because even though the name is the same, PHP does not think that it is! You'll need to extend it:
So let's rename your app/models/PageModule.php
to app/models/CustomPageModule.php
, and in the file change the class to:
class CustomPageModule extends \PageModule {
Up to this point, you also have a CustomPageModule
class that is a child of your package's PageModule
. All you need to do now is to let Laravel knows that if any controllers ask for PageModule
, it should serve the controller with your MyModels\CustomPageModule
instead.
So at the top of your app's routes.php
file:
App::bind('PageModule', 'MyModels\CustomPageModule');
Your AdminPageController
should now be using your CustomPageModule
and can use whatever public methods that are in there!
I'm expecting to be editing this answer heavily since this will be quite a long discussion. My first try at answering above isn't the best code you can write, but I hope it takes the least amount of edit to the original code, and then we can work up from there.
Or fast track by reading up articles like http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories
Automatic namespace aliases in laravel 4
I can only instantiate it as new Acme\Foo\Bar(); ... The only workaround is namespace aliasing on top of the file which implements the Bar class. Any workaround?
There's (mostly, see below) no work around, this is how modern PHP works. Your class's full name is actually Acme\Foo\Bar
, so that's what you need to use to reference it. If you want to reference it by a short-name (Bar
), then your use the use
statement at the top of your file after the namespace declaration. This is how things work now.
Laravel does have a solution for this. If you look in app/config/app.php
, you'll see the following section
#File: app/config/app.php
...
'aliases' => array(
'App' => 'Illuminate\Support\Facades\App',
'Artisan' => 'Illuminate\Support\Facades\Artisan',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Blade' => 'Illuminate\Support\Facades\Blade',
'Cache' => 'Illuminate\Support\Facades\Cache',
...
'Eloquent' => 'Illuminate\Database\Eloquent\Model',
The array lets you setup short aliases for fully namespaced classes. Laravel uses it mostly for Facades, but it's also what allows you to do class MyModel extends Eloquent
, where Eloquent
is really Illuminate\Database\Eloquent\Model
. You could add your own alias to this array
'Bar' => 'Acme\Foo\Bar'
And then refer to your class globally with Bar
. However, you'll probably be better off getting used to the idea of namesapced classes, as that's the direction most PHP frameworks are headed.
Also, if you're curious, the aliases in the aliases
array above are implemented via PHP's class_alias
function.
Laravel 4 class not found and namespaces
Whenever you put your class in a namespace, any other class that you reference in that class assumes that it is also in that same namespace unless you tell it otherwise.
So, since you set your namespace to Arg\Tagcloud
when you directly reference Request::url()
, PHP thinks that you're telling it to use the Request
class inside the Arg\Tagcloud
namespace.
There's two solutions to this:
Solution 1
Add a \
in front of Request
to tell PHP to use the global namespace, not the Arg\Tagcloud
namespace.
e.g., <a href='".\Request::url()."/myroute/'>
Solution 2
use
the class.
Just add use Request
to the top of your class (under your namespace), this will let PHP know that you want to use this class, but it doesn't belong in the current namespace.
e.g.,
<?php namespace Arg\Tagcloud;
use Request;
how to use different namespaces in a controller in laravel 4.1
if you use App
inside your App\Modules\Facebook\Controllers
namespace, it will be interpreted as App\Modules\Facebook\Controllers\Facebook\App
class.
since you don't want to have the previous namespace, you use a \
before App
like:
\App::()
or put a use statement of top the class like use App;
Related Topics
Laravel 5:Class 'Input' Not Found
What Does Header('P3P: Cp="Cao Psa Our"'); Do
Guzzle 6: No More JSON() Method for Responses
Is There a PHP Function for Swapping the Values of Two Variables
Why Would I Use Dirname(_File_) in an Include or Include_Once Statement
Setting Up Domainkeys/Dkim in a PHP-Based Smtp Client
What Is Sapi and When Would You Use It
Laravel - Seeding Relationships
How to Check If an Integer Is Within a Range of Numbers in PHP
When Is It Good to Use Pass by Reference in PHP
Difference Between Array_Push() and $Array[] =
Magento - Passing Data Between a Controller and a Block