Using Namespaces in Laravel 4

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



Leave a reply



Submit