laravel - namespacing controllers and models - lot of code repetition - laravel

Here is the example of beginning of my TurnoverController
namespace App\Controllers;
// libraries
use \Turnover\Form;
use \Turnover\StatsByEventNames;
use \Utilities\Utils;
// models
use \Card;
use \GameClient;
use \Gametypes\Dogs;
use \Manager;
// Facades
use \Session;
use \App;
use \URL;
class TurnoverController extends BaseController
Since PSR standard says every class should be in a namespace of at least one level, I added namespace.
But now to load just simple models, without namespace yet, I always have to call use
\ModelName
Plus also same for things like Session, App, Etc.
And also there is a plan to have models in a namespace
App\Models
So to use a model then will have to write
use App\Models\ModelName
. Without namespaces all this was automatic - controllers knew where the models and Facades are. How can I fix that so at least models in default model folder would not required to call use statement?
Same for Facades.

Related

Basic OOPS concept needs clarification

I am new to OOPS and MVC hence, have confusion about certain concepts which I would like to clarify. As mentioned below in the code, I think, namespace App\Http\Controllers\Admin; that is mentioned corresponds to the directory structure and thus means the class AdminController is contained in Admin folder as is pointed there. But then we have the use keyword inorder to use the following namespace. Now the question is why do we use use App\Http\Controllers\Controller;, particular line. What purpose does it serve?
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
class AdminController extends Controller
{
public function index()
{
echo "admin controller";
}
}
namespace App\Http\Controllers\Admin; as you stated is used to let laravel know where to access your AdminController from.
And your AdminController which extends the base Controller uses the default classes of base Controller so we need to use the use specification. use App\Http\Controllers\Controller; is used to let declare that you are going to use the base Controller classes in your AdminController.
For more info read the official laravel docs.
use usually allows a developer to shorten the namespace.
It copies another class from same or different namespace so you can use that class in your code with its class name. You need to write the full namespace if you will use another class without use.
This might help you understand it better. https://daylerees.com/php-namespaces-explained/
namespaces basically group your functions, classes and constants under a particular 'name', which we call a namespace.
Now use keyword allows a developer to shorten the namespace.use is useful when we are going to call the same function again and again in the same code file or call different functions, constants or classes under a particular namespace.

Laravel constants in class Facades

I have a class called Awesome and have used the ServiceProvider and the Facade to register it to the app. Now I can use it as Awesome::Things().
I want to add constants to this class, so I tried
<?php namespace Helper\Awesome;
class Awesome()
{
public static $MOVIE = 'I love the Lego Movie!";
}
but when I call Awesome::$MOVIE, I get Access to undeclared static property: Helper\\Aesome\\Facades\\AwesomeFacade::$MOVIE
Can someone help?
The short version is -- you don't really want to do that. Laravel facades aren't mean to be used like normal classes, and if your application uses them that way you'll likely confuse future developers.
Warning out of the way. When you create a "facade" in Laravel, you're actually creating a class alias. When you added Awesome to the alias list in app/config/app.php, at some point code like the following ran
class_alias('Helper\Aesome\Facades\AwesomeFacade','Awesome');
That means whenever you use a global non-namespaced class Awesome, PHP substitutes Helper\Aesome\Facades\AwesomeFacade. If you wanted to add constants, you'd need to add them to this class.
Laravel's able to pass through methods because of the base Facade class implements a __callStatic method that passes on your call to the actual service implementation object. Facades don't pass on static constant access. Additionally, PHP does not (appear to?) have similar magic methods for passing along requests for constants.
If you're curious about the in depth version of this answer, I'm currently writing a series on Laravel's object system, including some in-depth information about the facade implementation.

Namespacing and autoloading in Laravel

This might be a simple question but I'm wondering how do I autoload useful classes without declaring use statements on every single file.
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Input;
class HomeController extends Controller
{
public function index()
{
Input::get('query');
}
}
If I remove the use Illuminate\Support\Facades\Input; line I will get a class not found error because I'm using the Input class.
Is there a way to autoload useful classes like Input, Response, View like in Laravel 4. What's the point of the Aliases in app.php?
You can import input class using both:
use Illuminate\Support\Facades\Input;
or
use Input;
then you can use Input::get('query'); code. That's how PHP namespaces work - you can also look at How to use objects from other namespaces and how to import namespaces in PHP for more details about it.
If you don't use use statement for importing class, you can use \Input::get('query'); or \Illuminate\Support\Facades\Input::get('query');.
Aliases allow you not to use fully qualified classes for example \Illuminate\Support\Facades\Input but shorter form \Input. That's why I showed above 2 versions - the shorter one uses aliases and the longer uses full class path. The same mechanism is both in Laravel 4 and Laravel 5 I believe.
The problem is not really in Laravel, but in PHP. When you namespace a class, it assumes that everything inside that class will be in the same namespace, so you have to tell it that, for a particular class, you need it to use a different namespace.
You can use them by referring to the root namespace, like this:
class HomeController extends Controller
{
public function index()
{
\Input::get('query');
}
}

Laravel: conflict between model name and built-in facade

I have a Model in my Laravel app called Event. As I just discovered, this creates a conflict between my model and Illuminate\Support\Facades\Event, a built-in facade. The obvious solution here is to either change the name of my Model, which is not ideal because there is really no other name I could give my Model that makes any sense, or to rename the alias in app.php for Illuminate\Support\Facades\Event, which I'd like to avoid for fear of breaking anything that may rely on that alias in the future (I'm afraid I may forget).
It's been suggested that perhaps I could use namespaces, which I attempted as follows:
app/models/Event.php
namespace Models; #<-- I've also tried using "\Models" here
class Event extends \Eloquent{
app/database/seeds/DatabaseSeeder.php
Models\Event::create(); #<-- again, I've also used "\Models\Event"
All 4 combinations above have yielded a Class 'Models\Event' not found error when I run php artisan db:seed.
Perhaps I simply don't understand namespaces properly, but the more pressing issue is how to solve my problem. If it can be solved using namespaces as suggested, great, but I'm open to any other ideas as well.
I made this mistake early on as well, not necessarily understanding the role of namespace throughout the entire app.
The namespace should mark the business logic within the domain or responsibility of the app itself, so giving a namespace of Models isn't necessarily useful. Instead create a root namespace named after the app, your company, you, or whatever you like, then provide a Model sub-namespace.
For example:
namespace MyGreatApp\Models;
class Event extends \Eloquent{ }
Then you would reference this model under:
use MyGreatApp\Models\Event;
$event = new Event();
In the long run this is a cleaner and more organized approach. This does mean moving your models into a different folder, though. But there's nothing wrong with that. At least that way you know you have all your custom code in your MyGreatApp namespace. :)

How to autoload multiple classes in Laravel 4 application?

I’ve created a workbench package in Laravel 4, which is name-spaced and has two directories: Models and Contexts. Somehow, Laravel is loading my models in my Models directory (I have a model in there called User), however, it doesn’t know about my classes in the Contexts directory.
I want to be able to use my context classes in my app’s controllers without specifying the whole namespace, so I thought I’d add them to Laravel’s IoC container. However, it seems I need to create a façade class for each class I wish to add to the container. This isn’t desirable if I have dozens of context classes, as it would mean creating an equal amount of façade classes too.
Is there a way in Laravel to bulk-add classes to its IoC container?
if you want to use one term facades for your classes the laravel way (e.g. MyModel::someAction()) then you have to create your facades. but i'd advise not to do so for so many classes.
if your classes inside contexts folder aren't found then you should check your composer.json file under the autoload entry or do a composer dump-autoload -o.
I'd just DI the classes within the constructor of the class that uses them, so you end up using $this->myService->someAction().
This should answer both Laravel 4 and 5.
First, you need to use the bind method Illuminate\Foundation\Application class, which serves to register binding in the service container. In the Laravel documentation you will find plenty of examples how to do that, but only for a single binding.
If you take a look a the implementation of bind method here or just the definition here, you will notice that this method accepts a string|array. This means you can provide multiple bindings as an array and register all of them in the container with their fully qualified class names. Something like this:
$this->app->bind(['\App\Acme\Service1', '\App\Acme\Service2', '\App\Acme\Service3', ...]
Having this in mind, you can easily get the classes in one namespace (directory) with a reflection, put them in array and use the above method to register them.
Revisiting this question some time later, I think the appropriate solution would be to autoload the classes using my package’s composer.json file, and then import classes using it’s FQN in controllers and other classes:
<?php
use Vendor\Package\Contexts\ContextClass;
class Laravel4Controller extends BaseController {
protected $context;
public function __construct(ContextClass $context) {
$this->context = $context;
}
}

Resources