Namespace Alias in Laravel - php

I apologize if this is duplicate; please guide me to the right directions.
I know we can create class aliases in Laravel from /config/app.php. However trying to create namespace aliases using the same method fails.
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'aliases' => [
...
/*
* My custom namespace aliases
*/
'MyNamespace' => 'App\Models\MyNamespace',
],
Testing this in thinker returns the following results:
>> new \MyNamespace\MyClass();
PHP Fatal error: Class 'MyNamespace/MyClass' not found in Psy Shell code on line 1
Do you know a way to create namespace alias in Laravel?

Make your code PSR-4 compatible and put it in composer.json
"autoload": {
"psr-4": {
"MyNamespace\\": "src/MyNameSpace",
}
},
Then run composer dumpautoload. So long as you stick to the convention of subfolders being namespaces, your classes will autoload.
src/MyNamespace/SomeClass.php would have namespace MyNamespace; and class SomeClass.
src/MyNamespace/Something/SomethingElse.php would have namespace MyNamespace\Something; and class SomethingElse.

Related

Import library of php to laravel project

I had a problem importing libraries into the Laravel project. I want to use the image_QRCode-0.1.3 library coded in php used in Project Laravel.
https://pear.php.net/package/Image_QRCode/download
but when I use the require command in class QRCodeController
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
require_once "../../../Library/Image_QRCode-0.1.3/Image_QRCode-0.1.3/Image/QRCode.php";
class QRCodeController extends Controller {
public function genQRCode()
{
$QR = new \Image_QRCode();
$option = array(
'module_size' => 4,
'image_type' => 'png',
'output_type' => 'display',
'error_correct' => 'H',
);
$qrcode = $QR->makeCode(htmlspecialchars("https://blog.shnr.net/?p=526", ENT_QUOTES), $option);
}
}
The program did not run and reported an error.
Please help me, thanks you so much !
To use external classes or any other PHP library into your Laravel project, you have to do the following steps:
1. Create a folder somewhere in your Laravel app that will contain the PHP files you're going to use:
For example you have a custom class, create a folder in the directory app/libraries. Inside app/libraries, paste the PHP files you'll be using (the library files you've downloaded).
2. In your composer.json file, add the folder/directory into your autoload classmap:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/libraries", <------------------ YOUR CUSTOM DIRECTORY
"app/database/migrations",
"app/database/seeds",
]
}
3. Once you're done, just run composer dump-autoload and you should be able to call your class as follows:
Assuming your class name is SomeClass.php and it's inside the app/libraries directory and you're properly namespaced the class you've just copied over, you can now use SomeClass.php anywhere you need it.
$class = new \some_class_namespace\SomeClass();
You can also give it an alias in your config/app.php file:
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'aliases' => [
....
'SomeAlias' => 'app\libraries\SomeClass',
....
],
After then you can instantiate the class from anywhere in your application just like any other classes:
$class = new SomeAlias();

Laravel 5 Fatal Error: class not found exception cannot access the model classes when it is inside a folder

Here is my application structure,
my-first-app
|
|-app
|
| -Commands
| -Console
| -Events
| -Http
| -models(custom define folder)
|
|-Base(folder)
| |
| | -StuDetails.php
| | -StuDetailsQuery.php
|
|-Map(foder)
|-StuDetails.php
|-StuDetailsQuery.php
Actually I'm using propel ORM to retrieve data from the database.
I created my model classes inside the folder models.
Then I tried to access StudetailsQuery class inside my pageController class which is inside http folder extended as Controller.
Here it is :
<?php
namespace App\models\propel;
namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Base\StuDetailsQuery;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\View;
class pagesController extends Controller
{
public function index()
{
$stu= StuDetailsQuery::create()->find();
return view('pages.index', compact('stu'));
}
But I get error :
PHP Fatal error: Class 'Base\StuDetailsQuery' not
found in
/var/www/my-first-app/app/Http/Controllers/pagesController.php
I tried;
composer dump-autoload
adding following lines to composer.json file
"autoload": {
"psr-4":{
"propel\": "app/models/propel/"
}}
but nothing goes fine for me.. Any suggestions please ??
"autoload": {
"classmap": [
"database",
"app/models/propel"
]
this solved my problem... :)
I keep getting similar missing class errors. Although I follow the laracast autoloading examples in You Must Use Composer laracast completely (including the modification of composer.json), I get stuck with a missing class error.
In watching the videos I notices jeffery way uses a \ occasionally before the object name..... I don't know why but in frustration I added it, and it worked for me.
In summary I find I have to use a "\" before the object, like this:
new \Bar;
I hope this helps, and if someone can help me understand what is going on please let us know.

Laravel model directory and namespace

I am starting out with Laravel 5 and as first order of business I want to move all my models into a folder called Models.
But how can I access those without specifying the namespace like in the following?:
...
class UserRolesTableSeeder extends Seeder {
public function run()
{
DB::table('user_roles')->delete();
App\Models\UserRoles::create(['name' => 'CREATE_USER']);
}
}
Go into your composer.json and add at the end of "autoload": "classmap" this line "app/models". This way you are telling laravel to autoload those clases. After that, run a composer update and it should work.
You can also create a service provider to access models without namespaces.
To create a service provider, here is what you have to do :
1) Create a file in your models directory and name it ModelsServiceProvider.php
2) Inside of it write this code
<?php
namespace App\Models;
use Illuminate\Support\ServiceProvider;
class ModelsServiceProvider extends ServiceProvider {
public function register()
{
$this->app->booting(function()
{
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('UserRoles', 'App\Models\UserRoles');
});
}
3) Go into app/config/app.php and under providers array add this line 'App\Models\ModelsServiceProvider'
You can also add directly your aliases for classes under the aliases array inside app/config/app.php.
Alternatively, you can just load your models into the global namespace like you were doing before! It's a bit scary to go against the docs but so far we haven't had any issues with it.
To make sure your models are still loaded, you just need to add the reference to your composer.json:
(assumes your namespace is App\Models)
"autoload": {
"classmap": [
...
"app/Models/"
],
...
"": [
"app/Models/"
]
be sure to run composer dump-autoload

Including View Composers in Laravel using Composer

I have made the below composer view for my app. I've placed it in separate file at app/composers.php.
<?php
// namespace App\Modules\Manager\Composer;
// use Illuminate\Support\Facades\View as View ;
/*
|--------------------------------------------------------------------------
| Composers
|--------------------------------------------------------------------------
|
|
*/
View::composer('tshop.includes.header', function($view)
{
$categories = Categories::getWithChilds();
$view->withCategories( $categories);
});
My composer.php file is
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
],
"files": [
"app/composers.php"
]
},
Unfortunately I get this error
Fatal error: Class 'View' not found in C:\xampp\htdocs\eshop\app\composers.php on line 15
Update
I also tried this. I wrote inside app/start/global.php
require app_path().'/composers.php';
and
use Illuminate\Support\Facades\View as View ;
at app/composers.php, getting this error
Fatal error: Call to a member function composer() on a non-object in
C:\xampp\htdocs\eshop\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php
on line 211
I don't think your app/composers.php should be autoloaded within composer. Composer's responsibility is to resolve packages and install them for you, which has nothing to do with your application logic, let alone your application's views.
At the point of running composer, it would not have any knowledge of your Laravel app. That means your Laravel facades like View, Input, DB, Auth, etc. are not loaded yet. Thus your code throws Call to a member function composer() on a non-object.
Approach 1:
Laravel does not strictly specify where you put your laravel view composers, so requiring it by adding:
require app_path() . '/composers.php';
at the bottom of app/start/global.php like edi9999 said would be fine.
Don't forget to remove in this case:
"files": [
"app/composers.php"
]
Approach 2: there is a way to autoload your view composers in composer.json!
From example in Laravel docs on view composers, you can do something like...
app/viewcomposers/HeaderViewComposer.php:
class HeaderViewComposer
{
public function compose($view)
{
$categories = Categories::getWithChilds();
$view->withCategories( $categories);
}
}
composer.json:
"classmap": [
...
"app/viewcomposers"
]
app/composers.php:
View::composer('tshop.includes.header', 'HeaderViewComposer');
bottom of app/start/global.php:
require app_path() . '/composers.php';
Unfortunately you still need to add the line above to app/start/global.php so Laravel knows what view composers are defined.
Approach 3: Do autoload class in composer.json + register a custom ServiceProvider
Learning from Using View Composers in Laravel 4 by Philip Brown, we could also add our own custom service provider and not having to edit our app/start/global.php file.
app/viewcomposers/HeaderViewComposer.php:
<?php namespace App\Modules\Manager\Composer;
class HeaderViewComposer
{
public function compose($view)
{
$categories = Categories::getWithChilds();
$view->withCategories( $categories);
}
}
composer.json:
"classmap": [
...
"app/viewcomposers"
]
app/viewcomposers/ViewComposerServiceProvider.php:
<?php namespace App\Modules\Manager\Composer;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function register()
{
$this->app->view->composer('tshop.includes.header', 'App\Modules\Manager\Composer\HeaderViewComposer');
}
}
app/config/app.php:
'providers' => array(
...
'App\Modules\Manager\Composer\ViewComposerServiceProvider',
),
As #TheShiftExchange found out, one problem is that you used the "files" options.
As you can see in composer's code, the autoload section corresponds to this:
class ComposerAutoloaderInitf8489489s7f894ds98f47d
{
....
....
public static function getLoader()
{
....
....
$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $file) {
composerRequiref4s65f4556sd4f564fsdfd($file);
}
return $loader;
}
}
function composerRequire5894s89f4sd98498489f7b37d($file)
{
require $file;
}
So the files array you specify is required during composer's autoload process, way before the View Facade is loaded.
The providers to the facades are loaded in vendor/laravel/framework/illuminate/foundation/start.php
/*
|--------------------------------------------------------------------------
| Register The Core Service Providers
|--------------------------------------------------------------------------
|
| The Illuminate core service providers register all of the core pieces
| of the Illuminate framework including session, caching, encryption
| and more. It's simply a convenient wrapper for the registration.
|
*/
$providers = $config['providers'];
$app->getProviderRepository()->load($app, $providers);
Actually, the problem with classmaps is an other one: It is that they is no class in your file, so the file will never be loaded so it doesn't do anything.
To make it work, you should add into app/start/global.php at the end of the file:
Instead of
require app_path() . '/filters.php';
Write
require app_path() . '/composers.php';
require app_path() . '/filters.php';
That's the best way I can think of to include files at each load of your application that are not classes.

Laravel: Hooking up a service

So I've implemented a service structure that a stackoverflow user suggested to me in this post. I've got it mostly working but I'm running into the error:
Class 'App\Services\Mailer\Facades\Mailer' not found
My service folder structure looks like this:
app
| App
| | Services
| | | Mailer
| | | | Mailer.php
| | | | MailerFacade.php
| | | | MailerServiceProvider.php
Each of the files in the Mailer directory are namespaced as:
<?php namespace App\Services\Mailer;
Except for the Facade which is namespaced as the following per the example in this blog:
<?php namespace App\Services\Mailer\Facades;
I put a test method in my Mailer.php file's Mailer class:
<?php namespace App\Services\Mailer;
//base service class
class Mailer {
public function sayHi(){
return "hello!";
}
}
I then created the facade:
<?php namespace App\Services\Mailer\Facades;
// Facade for Mailer
use Illuminate\Support\Facades\Facade;
class Mailer extends Facade {
protected static function getFacadeAccessor(){ return 'mailer'; }
}
Then I created the Service Provider to hook them all together:
<?php namespace App\Services\Mailer;
// Mailer's service provider
use Illuminate\Support\ServiceProvider;
class MailerServiceProvider extends ServiceProvider {
public function register(){
$this->app['mailer'] = $this->app->share( function ($app){
return new App\Services\Mailer\Mailer;
});
$this->app->booting( function (){
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Mailer', 'App\Services\Mailer\Facades\Mailer');
});
}
}
THe loader for the facade is pointing to the correct namespace, 'App\Services\Mailer\Facades\Mailer', but when I try calling the method in one of my controllers like so:
public function showMe(){
return Mailer::sayHi();
}
I get the message I noted at the top.
I tried putting the facade into a subfolder of the Mailer directory called Facade so that the namespace and folder structure matched exactly, but I got the same error.
I read and re-read the example, the original stackoverflow post, the composer documentation on psr-4 to make sure I wasn't referencing anything incorrectly, and I can't seem to figure it out.
Can anyone point me in the right direction?
EDIT:
So I took a step back and created a vanilla laravel project and tried to add in a service the same way I'm trying in my main project. It's running into a similar error.
Here's a screen shot of every file involved:
Process:
I created my new laravel project
I created my App/Services/Greetings directory structure
I added my psr-4 load path to my composer.json file
I created my underlying class Greetings
I Created a GreetingsFacade class that returns the string 'greetings' for the `getFacadeAccessor method
I created a Greetings Service Provider class GreetingsServiceProvider and added
the register method with it's commands
I added my service provider to the app/config/app.php file in the providers array
I added a route that returns a closure that uses my new Greetings service
I then ran composer dump-autoload and loaded my route
When I load my page I get the error "Class 'App\Services\Greetings\App\Services\Greetings\Greetings' not found" :(
psr-4 expects your directory structure to reflect the namespace structure.
In order to autoload a class App\Services\Mailer\Facades\Mailer, it will look for the file App/Services/Mailer/Facades/Mailer.php.
Additionally, the facade accessor mailer (thus also the IoC-Container slug mailer) is already used by Illuminate\Support\Facades\Mail.
Try something different like my_mailer:
<?php namespace App\Services\Mailer\Facades;
// Facade for Mailer
use Illuminate\Support\Facades\Facade;
class Mailer extends Facade {
protected static function getFacadeAccessor(){ return 'my_mailer'; }
}
and
<?php namespace App\Services\Mailer;
// Mailer's service provider
use Illuminate\Support\ServiceProvider;
class MailerServiceProvider extends ServiceProvider {
public function register(){
$this->app['my_mailer'] = $this->app->share( function ($app){
return new App\Services\Mailer\Mailer;
});
$this->app->booting( function (){
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Mailer', 'App\Services\Mailer\Facades\Mailer');
});
}
}
According to your directory structure:
app
| App
| | Services
| | | Mailer
| | | | Mailer.php
| | | | MailerFacade.php
| | | | MailerServiceProvider.php
Your classes namespaces must be:
Service
<?php namespace App\Services\Mailer;
class Mailer {}
Service Provider
<?php namespace App\Services\Mailer;
class MailerServiceProvider {}
Facade
<?php namespace App\Services\Mailer;
class MailerFacade {}
And you autoloader:
"autoload": {
"psr-4": {
"App\\": "app/App"
},
},
For it to work the way you are trying to do, your directory structure would have to be
app
| App
| | Services
| | | Mailer
| | | ├── Facades
| | | | └── Facade.php
| | | | Mailer.php
| | | | MailerServiceProvider.php
EDIT:
In your Greetings namespace, change from:
return new App\Services\Greetings\Greetings;
to
return new Greetings;
And it should work because they are in the same namespace. For an easy reading of the code, add
use App\Services\Greetings\Greetings;
In the top of your .php file.

Categories