I am currently trying to develop a custom Laravel Package, but is having some issues with getting started.
This is my file structure:
-packages
- oliverbusk
-invoiceconverter
-src
-controllers
- InvoiceconverterController.php
-resources
- views
- home.blade.php
-routes
- web.php
- InvoiceConverterServiceProvider.php
So as you can see, I have my files inside the src/ folder.
First of all, this is my composer.json, inside my package folder:
"extra": {
"laravel": {
"providers": [
"Oliverbusk\\Invoiceconverter\\InvoiceConverterServiceProvider"
]
}
}
I have then autoloaded this in my projects main composer.json file:
"require": {
//....
"oliverbusk/invoiceconverter": "dev-feature-package"
},
"autoload": {
[...]
"psr-4": {
"App\\": "app/",
"Oliverbusk\\Invoiceconverter\\": "packages/oliverbusk/invoiceconverter"
}
},
This is my serviceprovider file:
namespace Oliverbusk\Invoiceconverter;
use Illuminate\Support\ServiceProvider;
class InvoiceConverterServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//Load our routes
$this->loadRoutesFrom(__DIR__ . '/routes/web.php');
//Load our views
$this->loadViewsFrom(__DIR__ . '/resources/views', 'invoiceconverter');
}
/**
* Register services.
*
* #return void
*/
public function register()
{
//
}
}
And my controller file, located in controllers/:
namespace Oliverbusk\Invoiceconverter\Controllers;
use App\Http\Controllers\Controller;
class InvoiceconverterController extends Controller
{
public function index()
{
return view('invoiceconverter::home');
}
}
Last, my routes/web.php file:
Route::group(['namespace' => 'Oliverbusk\InvoiceConverter\Controllers'], function () {
Route::get('invoiceconverter', 'InvoiceconverterController#index');
});
Error :
Class Oliverbusk\InvoiceConverter\Controllers\InvoiceconverterController does not exist
Bonus info:
Composer dump autoload shows the following:
Discovered Package: oliverbusk/invoiceconverter
I have already tried to clear the cache with php artisan:cache:clear.
I have also tried composer update
The namespace in your route does not match the namespacing your have actually used.
Route::group(['namespace' => 'Oliverbusk\InvoiceConverter\Controllers'], function () {
Route::get('invoiceconverter', 'InvoiceconverterController#index');
});
Change to
Route::group(['namespace' => 'Oliverbusk\Invoiceconverter\Controllers'], function ()
{
Route::get('invoiceconverter', 'InvoiceconverterController#index');
});
And see if that helps.
I would also recommend you refactor all your code to be capitalised InvoiceConverter as they are two separate words.
Related
I can't find out why my classes won't load. I am using Composer for psr-4 autoloading and have been using it successfully. Here's how I have my classes setup:
/project
/classes
/feeds
/pull
/factory
composer.json
testMyFactory.php
feeds/factory/FeedFactory.php
namespace MyClasses\Feeds\Factory;
interface FeedFactory
{
public function build($provider);
}
feeds/factory/PullFeedFactory.php
namespace MyClasses\Feeds\Factory;
use MyClasses\Feeds\Factory\FeedFactory;
use MyClasses\Feeds\Pull\Providers\One;
/**
* Class FeedFactory
*/
class PullFeedFactory implements FeedFactory
{
public function __construct(){}
/**
* Build provider object for factory
* #param string $provider Type of feed provider to return
* #return Object Provider object
*/
public function build($provider) {
switch ($provider) {
case 'one':
$provider = new One();
break;
default:
$provider = new One`();
break;
}
return $provider;
}
}
project/feeds/pull/One.php
namespace MyClasses\Feeds\Pull\Providers;
class One
{
public function pull() {
echo 'Pull One';
}
}
project/testMyFactory.php
require __DIR__ . '/vendor/autoload.php';
use MyClasses\Feeds\Factory\PullFeedFactory;
$feed = new PullFeedFactory();
$feed->build('one');
$feed->pull();
project/composer.json
{
"require": {
//Remove for example
},
"config": {
"preferred-install": "dist"
},
"require-dev": {
},
"autoload": {
"psr-4": {
"MyClasses\\": "./classes",
}
}
}
This is the error I keep getting Class 'MyClasses\Feeds\Factory\PullFeedFactory' not found in /var/www/html/testPullFactory.php on line xx
I have other classes that work in the Classes directory with autoload but for some reason cannot get this to work. I feel like it's something glaringly obvious but have been stuck on this for hours now.
UPDATE:
Updated to include my vendor/autoload.php file. Stil getting an error, although it's different now Class 'MyClasses\Feeds\Pull\Providers\One' not found in /var/www/html/classes/Feeds/Factory/PullFeedFactory.php
in your composer.json, change to
"autoload": {
"psr-4": {
"MyClasses\\": "classes/",
}
}
Then, execute composer dump-autoload.
I registering a controller with the container, but it seems not working because it doesn't match to the correct location.
\slim\src\routes.php
<?php
// Routes
$app->get('/dd', 'App\controllers\HomeController:home');
\slim\App\controllers\HomeController.php
<?php
class HomeController
{
protected $container;
// constructor receives container instance
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
public function home($request, $response, $args) {
// your code
// to access items in the container... $this->container->get('');
return $response;
}
public function contact($request, $response, $args) {
// your code
// to access items in the container... $this->container->get('');
return $response;
}
}
My project folder structure:
\slim
\public
index.php
.htaccess
\App
\controllers
HomeController.php
\src
dependencies.php
middleware.php
routes.php
settings.php
\templates
index.phtml
\vendor
\slim
Maybe I should to setting \slim\src\settings.php?
Because it show Slim Application Error:
Type: RuntimeException Message: Callable
App\controllers\HomeController does not exist File:
D:\htdocs\slim\vendor\slim\slim\Slim\CallableResolver.php Line: 90
Last, I also refer to these articles:
https://www.slimframework.com/docs/objects/router.html#container-resolution
PHP Slim Framework Create Controller
PHP Slim Framework Create Controller
How can i create middleware on Slim Framework 3?
How can i create middleware on Slim Framework 3?
Add psr-4 to your composer file so that you're able to call your namespaces.
{
"require": {
"slim/slim": "^3.12
},
"autoload": {
"psr-4": {
"App\\": "app"
}
}
}
This PSR describes a specification for autoloading classes from file paths. Then in your routes.php file add this at the top :
<?php
use app\controllers\HomeController;
// Routes
$app->get('/dd', 'App\controllers\HomeController:home');
and finally in your HomeController.php file add :
<?php
namespace app\controllers;
class HomeController
{
//.. your code
}
hope this helps...:)
I am creating a laravel 5.2 package, following are my files:
packages/
-Shreeji/
--Ring/
---composer.json
---src/
----Ring.php
----RingModel.php
----RingServiceProvider
----Views/
-----ringslist.blade.php
composer.json
{
"name": "shreeji/ring",
"description": "Simple",
"license": "MIT",
"authors": [
{
"name": "author",
"email": "email#gmail.com"
}
],
"autoload": {
"psr-4": {
"Shreeji\\Ring\\": "src/"
}
},
"minimum-stability": "dev",
"require": {
"Illuminate/support": "~5"
}
}
Ring.php
namespace Shreeji\Ring;
use Illuminate\Http\Response;
Class Ring {
function __construct() {
}
public function get_all()
{
return view("ring::ringlist");
}
}
RingServiceProvider.php
namespace Shreeji\Ring;
use Illuminate\Support\ServiceProvider;
Class RingServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('ring', function($app){
return new Ring;
});
}
public function boot()
{
$this->loadViewsFrom(__DIR__ . '/Views', 'ring');
}
}
ringlist.blade.php
<!DOCTYPE html>
<html>
<body>
<h1>Welcome</h1>
</body>
</html>
And in app/Http/Controllers I have created a test file like this:
Ringcontroller.php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Shreeji\Ring\Ring;
class RingController extends Controller
{
public function index()
{
$ring = New Ring();
$ring->get_all();
}
}
When I call the controller, browser keeps loading and crashed systematically. I don't know if I can use view outside any controller class like such.
Let me know if I did any mistake in calling view from Ring.php file.
Couple issues I see:
You want to use views, but your package does not require the illuminate/view package. You need to update your composer.json file to require "illuminate/view": "~5".
The view() function is a helper method included at Illuminate\Foundation\helpers.php. Unless you want to depend on the entire Laravel framework just for this function, you will need to create your own view() function. The code is below, where you put it is up to you.
if (! function_exists('view')) {
/**
* Get the evaluated view contents for the given view.
*
* #param string $view
* #param array $data
* #param array $mergeData
* #return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
function view($view = null, $data = [], $mergeData = [])
{
$factory = app(ViewFactory::class);
if (func_num_args() === 0) {
return $factory;
}
return $factory->make($view, $data, $mergeData);
}
}
Once you get the view stuff working, you can make views all day long, but if you don't return anything from your controller, you're not going to see anything. Make sure you return something from your controller methods.
You can use somethin like view composer Docs
In your RingServiceProvider register a composer
use Illuminate\Contracts\View\Factory as ViewFactory;
public function boot(ViewFactory $view)
{
$view->composer('*', 'App\Http\ViewComposers\SomeComposer');
}
And in App\Http\ViewComposers\SomeComposer
use Illuminate\Contracts\View\View;
public function compose(View $view)
{
$view->with('count', '1');
}
Play around with it, basically I am using it share $variables on particular views but maybe this can help you achieve what you want.
Or u can just use Illuminate\Contracts\View\View; to load your view that you need!
Looked up a few tutorials on facades and laravel 4... tried some... not liked the way they work.
For instance, they don't all provide a way of defining where to store the facade files and service providers... and i tried to step away from that and got my head bumped into a few walls until i decided to do this thread.
So: Let's say i have an app called Laracms (laravel cms).
I'd like to store everything i create - facades, service providers, etc in a folder under app named laracms.
So i'd have /app/laracms/facades, /app/laracms/serviceproviders and so on. I don't want to mix the facades with the database models, i want to keep things as separate as possible.
Let's take now, in my case, the Settings name for the facade (i want to implement a settings class to use in views and admin to set up misc. stuff).
Settings::get(), Settings::set() as methods.
Can anyone explain how to set facades up correctly? I don't know what i'm doing wrong and i need a fresh start.
Thanks,
Chris
Looking for a step by step with simple explanations of how and why.
First you need to go to app/config/app.php and in providers section add:
'Laracms\Providers\SettingsServiceProvider',
In the same file in aliases section you should add:
'Settings' => 'Laracms\Facades\Settings',
In your app/Laracms/Providers you should create file SettingsServiceProvider.php
<?php
namespace Laracms\Providers;
use Illuminate\Support\ServiceProvider;
class SettingsServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('settings', function()
{
return new \Laracms\Settings();
});
}
}
In your app/Laracms/Facades/ you should create file Settings.php:
<?php
namespace Laracms\Facades;
use Illuminate\Support\Facades\Facade;
class Settings extends Facade {
protected static function getFacadeAccessor() { return 'settings'; }
}
Now in your app/Laracms directory you should create file Settings.php:
<?php
namespace Laracms;
class Settings {
public function get() {echo "get"; }
public function set() {echo "set"; }
}
As you wanted to have your files in custom folder Laracms you need to add this folder to your composer.json (If you used standard app/models folder you wouldn't need to add anything to this file). So now open composer.json file and in section autoload -> classmap you should add app/Laracms so this section of composer.json could look like this:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/Laracms"
]
},
Now you need to run in your console inside your project foler:
composer dump-autoload
to create class map
If everything is fine, you should now be able to use in your applications Settings::get() and Settings:set()
You need to notice that I used folders with uppercases because namespaces by convention starts with upper letters.
There are three components to making a Facade:
The wanna be Facade Class, that class that needs to become a facade.
The Facade required Class, which tells Laravel which registered class it pertains to
A Service Provider, which registers the Facade class in the App container
1. the wanna be Facade Class:
<?php namespace Moubarmij\Services\ModelsServices;
class AuthenticationService extends MoubarmijService implements AuthenticationServiceInterface{
/**
* #param $email
* #param $password
*
* #return mixed
*/
public function login($email, $password)
{
return Sentry::authenticate([
'email' => $email,
'password' => $password,
]);
}
/**
* #return mixed
*/
public function logout()
{
return Sentry::logout();
}
}
2. the required class for the facade to work:
<?php namespace Moubarmij\Facades;
use Illuminate\Support\Facades\Facade;
/**
* Class AuthenticationServiceFacade
* #package Moubarmij\Services\ModelsServices
*/
class AuthenticationServiceFacade extends Facade{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'authentication_service'; }
}
note: authentication_service can be anything you want (its the name of the component registered in the IOC)
3. the service provider
<?php namespace Moubarmij\Providers;
use Illuminate\Support\ServiceProvider;
/**
* A service provider for the Authentication Service
*
* Class AuthenticationServiceSP
* #package Moubarmij\Providers
*/
class AuthenticationServiceSP extends ServiceProvider {
/**
* bind interfaces
*
* #return void
*/
public function register()
{
// Register 'authentication_service' instance container to our AuthenticationService object
$this->app['authentication_service'] = $this->app->share(function($app)
{
return $app->make('Moubarmij\Services\ModelsServices\AuthenticationService');
});
// Shortcut to auto add the Alias in app/config/app.php
$this->app->booting(function()
{
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('AuthenticationService', 'Moubarmij\Facades\AuthenticationServiceFacade');
});
}
}
In using the laravel framework, how can I call a function defined in base_controller, in a view. For exacmple:
class Base_Controller extends Controller {
public static function format_something()
{
return something;
}
}
How can i call format_something() in a view file?
Usually the error I get looks something like this:
Method [link_to_action] is not defined on the View class.
Probably a silly question, but thanks in advance!
Edit
Okay! First the correct place to do something like this is in the libraries folder.
Second, problem is that your class cannot have underscores.
So in application/libraries I made file AppHelper.php with class
class AppHelper {
public static function format_something()
{
return something;
}
}
And can call it like:
$formated = AppHelper::format_something;
Thanks for the help and the good forum find Boofus McGoofus.
For me is working:
Create directory "helpers" or whatever and file:
// app/helpers/AppHelper.php
class AppHelper {
public static function format_something()
{
return something;
}
}
Add path to composer.json
// composer.json
"autoload": {
"classmap": [
"app/helpers" // <-------- add this line
]
},
Run: (reload the autoload)
composer dump-autoload
Now you can call:
$formated = AppHelper::format_something();
This answer was written for Laravel 3. For Laravel 4 and after, Lajdák Marek's answer using Composer's autoloader is better.
Functions like format_something() don't belong in the controller. The controller should just be about collecting data from various sources and passing it to the view. It's job is mostly just routing.
I've created a folder called "helpers" in the application folder for all my little helpery functions. To make sure all my controllers, views, and models have access to them, I've included the following in my start.php file:
foreach(glob(path('app').'helpers/*.php') as $filename) {
include $filename;
}
I suspect that there's a better way to do that, but so far it has worked for me.
You can inspire yourself from Laravel framework itself.
I will take your example of a formatter and refer to url helper in Laravel Framework.
Start by creating your own helpers.php file:
<?php
if (! function_exists('format_that')) {
/**
* Generate something
*
* #param string $text
* #return string
*/
function format_that($text)
{
return app('formatter')->format_that($text);
}
}
And add it to your composer.json file:
"autoload": {
"files": [
"app/helpers/helpers.php"
]
}
Run this command to recreate the autoload php file:
$ composer dumpautoload
Create your service provider app/Providers/FormatterServiceProvider.php:
<?php
namespace Illuminate\Routing;
use Illuminate\Support\ServiceProvider;
use App\Helpers\FormatGenerator;
class FormatterServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app['formatter'] = $this->app->share(function ($app) {
return new FormatGenerator($app['request']);
});
}
}
Register your service provider. Laravel framework invokes register method but you only need to add it to your app config file config/app.php:
'providers' => [
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
// other providers...
App\Providers\FormatterServiceProvider::class,
]
Finally, create your actual generator class app/Helpers/FormatGenerator.php
<?php
namespace App\Helpers;
use Illuminate\Http\Request;
class FormatGenerator
{
protected $request;
/**
* Create a new URL Generator instance.
*
* #param \Illuminate\Routing\RouteCollection $routes
* #param \Illuminate\Http\Request $request
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
public function format_that($text){
if ($request->path() == "home"){
return mb_strtoupper($text);
}
else{
return $text;
}
}
}
You can optionally create a Facade app/Facade/Formatter.php, to be able to do Formatter::format_that($text):
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
/**
* #see \App\Helpers\FormatGenerator
*/
class Formatter extends Facade
{
protected static function getFacadeAccessor() { return 'formatter'; }
}
You could ask yourself:
Why the facade? You can reuse the component somewhere else by simply calling Formatter::format_that($text) instead of app('formatter')->format_that($text). Sugar syntax really.
Why the Service provider? Dependence injections. If you need to use Request or want to build a complex object, the Service provider will take care of that for you and make it available in your $app object.