Including View Composers in Laravel using Composer - php

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.

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();

How do I make global helper functions in laravel 5? [duplicate]

This question already has answers here:
How to create custom helper functions in Laravel
(23 answers)
Closed 7 months ago.
If I wanted to make a currentUser() function for some oauth stuff I am doing where I can use it in a view or in a controller (think rails, where you do helper_method: current_user in the application controller).
Everything I read states to create a helpers folder and add the function there and then that way you can do Helpers::functionName Is this the right way to do this?
Whats the "laravel way" of creating helper functions that can be used in blade templates and controllers?
Create a new file in your app/Helpers directory name it AnythingHelper.php
An example of my helper is :
<?php
function getDomesticCities()
{
$result = \App\Package::where('type', '=', 'domestic')
->groupBy('from_city')
->get(['from_city']);
return $result;
}
generate a service provider for your helper by following command
php artisan make:provider HelperServiceProvider
in the register function of your newly generated HelperServiceProvider.php add following code
require_once app_path('Helpers/AnythingHelper.php');
now in your config/app.php load this service provider and you are done
'App\Providers\HelperServiceProvider',
An easy and efficient way of creating a global functions file is to autoload it directly from Composer. The autoload section of composer accepts a files array that is automatically loaded.
Create a functions.php file wherever you like. In this example, we are going to create in inside app/Helpers.
Add your functions, but do not add a class or namespace.
<?php
function global_function_example($str)
{
return 'A Global Function with '. $str;
}
In composer.json inside the autoload section add the following line:
"files": ["app/Helpers/functions.php"]
Example for Laravel 5:
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"files": ["app/Helpers/functions.php"] // <-- Add this line
},
Run composer dump-autoload
Done! You may now access global_function_example('hello world') form any part of your application including Blade views.
Laravel global helpers
Often you will find your self in need of a utility function that is access globally throughout you entire application. Borrowing from how laravel writes their default helpers you're able to extend the ability with your custom functions.
Create the helper file, not class
I prefer to you a file and not a class since I dont want to bother with namespaces and I want its functions to be accessible without the class prefixes like: greeting('Brian'); instead of Helper::greeting('Brian'); just like Laravel does with their helpers.
File: app/Support/helper.php
Register helper file with Composer: composer.json
{
...
"autoload": {
"classmap": [
"database"
],
"files": [
"app/Support/helpers.php"
],
"psr-4": {
"App\\": "app/"
}
},
...
}
Create your first helper function
<?php
if (!function_exists('greet')) {
/**
* Greeting a person
*
* #param string $person Name
* #return string
*/
function greet($person)
{
return 'Hello ' . $person;
}
}
Usage:
Remember to autoload the file before trying to access its functions:
composer dump-autoload
Let's test with Tinker
$ php artisan tinker
Psy Shell v0.8.17 (PHP 7.0.6 ΓÇö cli) by Justin Hileman
>>> greet('Brian');
=> "Hello Brian"
>>> exit
Exit: Goodbye.
With Blade
<p>{{ greet('Brian') }}</p>
Advanced usage as Blade directive:
A times you will find yourself wanting to use a blade directive instead of a plain function.
Register you Blade directive in the boot method of AppServiceProvider: app/Providers/AppServiceProvider.php
public function boot()
{
// ...
Blade::directive('greet', function ($expression) {
return "<?php echo greet({$expression}); ?>";
});
}
Usage:
<p>#greet('Brian')</p>
Note: you might need to clear cache views
php artisan view:clear
The above answers are great with a slight complication, therefore this answer exists.
utils.php
if (!function_exists('printHello')) {
function printHello()
{
return "Hello world!";
}
}
in app/Providers/AppServiceProvider.php add the following in register method
public function register()
{
require_once __DIR__ . "/path/to/utils.php"
}
now printHello function is accessible anywhere in code-base just as any other laravel global functions.
Another option, if you don't want to register all your helper functions one by one and wondering how to register them each time you create a new helper function:
Again in the app/Providers/AppServiceProvider.php add the following in register method
public function register()
{
foreach (glob(app_path().'/Helpers/*.php') as $filename) {
require_once($filename);
}
}

Laravel 5 Extending core class

I'm trying to extend Laravel 5 core class. What i want to achieve is that i can have custom url generators eg. URL::test(), will generate custom link.
So far i have:
Created app/Acme/lib folder
Added app/Acme/lib path to composer.json classmap
"autoload": {
"classmap": [
....
app/Acme/lib
]
}
Created custom UrlGenerator class in Acme/lib/CustomUrlGenerator.php
<?php namespace App\Acme\lib;
use \Illuminate\Routing\UrlGenerator;
class CustomUrlGenerator extends UrlGenerator {
public function test() {
return $this->to('/test');
}
}
Created service provider app/Acme/lib/CustomUrlServiceProvider.php
<?php namespace App\Acme\lib;
use \Illuminate\Routing\RoutingServiceProvider;
class CustomUrlServiceProvider extends RoutingServiceProvider {
public function boot() {
App::bind('url', function() {
return new CustomUrlGenerator(
App::make('router')->getRoutes(),
App::make('request')
);
});
parent::boot();
}
}
Registered service provider in app/config/app.php
Run composer dump-autoload
Now when i run {!! URL::test() !!}, im getting 404 for every route
Sorry, the page you are looking for could not be found.
NotFoundHttpException in /vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php line 143:
Is there something that i'm missing?
Many thanks for any help ..
You talk about a mistake in the RouteCollection.php file, but you don't include it in your question. Furthermore, I would have written differently in the composer.json, like this:
"autoload": {
"classmap": [
// ....
"App\\Your_Namespace\\" : "app/Acme/lib",
]
}

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

Custom validation class not loading in Laravel 4

I'm trying to write my own validation class in Laravel 4. To do this, I created a new directory called app/validators. I then added this directory to the composer.json classmap and ran composer update, like so:
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/validators", <- added here
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
]
My validation class looks like this:
class LinkValidation extends Illuminate\Validation\Validator {
{
public function validateHost($field, $value, $params)
{
return $value == 'test';
}
}
and in my controller, I'm trying to extend the validator like so:
Validator::extend('awesome', 'LinkValidation#supportedHost');
However, I'm getting this error when loading a page:
{
"error":{
"type":"ReflectionException",
"message":"Class LinkValidation does not exist",
"file":"C:\\xampp\\htdocs\\laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php",
"line":301
}
}
Any ideas why Laravel won't load the class? I thought it'd do it automatically if added to composer's classmap.
Not sure why it isn't working, but I think you should try adding it in app/start/global.php.
/*
|--------------------------------------------------------------------------
| Register The Laravel Class Loader
|--------------------------------------------------------------------------
|
| In addition to using Composer, you may use the Laravel class loader to
| load your controllers and models. This is useful for keeping all of
| your classes in the "global" namespace without Composer updating.
|
*/
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/validators',
));
Always do composer dumpautoload after create new class object.

Categories