The problem:
class PostRepostioryInterface not found for line 4 in PostController.php
or in tinkering with the namespace I've even got class
App\Models\Interfaces\PostRepositoryInterface not found
The questions: How to register a namespace in laravel 4? What do I need to do to get L4 to recognise the classes/interfaces at this namespace?
Larave 3 had a $namespaces static object in ClassLoader where you could add namespaces by
Autoloader::namespaces(array(
'App\Models\Interfaces' => path('app').'models/interfaces',
));
I'm not sure if I have that right for laravel 3 but either way, AutoLoader doesn't exist in Laravel 4 and ClassLoader exists but the method namespaces doesn't exist in ClassLoader in Laravel 4.
I've looked at this but it doesn't seem to work without registering the namespace somehow.
Using namespaces in Laravel 4
Example structure:
app/models/interfaces
PostRepostitoryInterface.php
app/models/repositories
EloquentPostRepository.php
namespaces:
App\Models\Repositories;
App\Models\Interfaces;
the files:
PostRepositoryInterface.php
<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface {
public function all();
public function find($id);
public function store($data);
}
EloquentPostRepository.php
<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
class EloquentPostRepository implements PostRepositoryInterface {
public function all()
{
return Post::all();
}
public function find($id)
{
return Post::find($id);
}
public function store($data)
{
return Post::save($data);
}
}
PostController.php
<?php
use App\Models\Interfaces\PostRepositoryInterface;
class PostsController extends BaseController {
public function __construct( PostRepositoryInterface $posts )
{
$this->posts = $posts;
}
Thanks
You probably forgot to do composer dump-autoload. This updates the list of classes Laravel autoloads.
You can read more on composer documentation.
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.
Related
I am new to Laravel and would appreciate any help on describing how a Laravel package residing in vendor folder can be extended and wont get affected if I update the package.
I'll try to create a brief guide, and we'll expand if need be.
I suggest putting all of your files inside a separate directory / namespace. You'll benefit from this should you decide to create your own composer package afterwards.
As an example I'll extend bumbummen99/shoppingcart package which forks the great gloudemans/shoppingcart, adding support for Laravel 5.8 and some minor functionality. You will of course first need to install that package:
composer require bumbummen99/shoppingcart
Start by making a couple of folders. You can use any name for folders / classes, this is what I used, relative to the project root:
app/Repositories/ExtendedCart
app/Repositories/ExtendedCart/Facades
Create the file
app/Repositories/ExtendedCart/ExtendedCart.php
This class will extend the package's main class:
namespace App\Repositories\ExtendedCart;
use Gloudemans\Shoppingcart\Cart;
class ExtendedCart extends Cart
{
public function myMethod(){
return 'myMethod';
}
}
Then make your Service Provider. Create the file:
app/Repositories/ExtendedCart/ExtendedCartServiceProvider.php
(I'm not using artisan as generating / moving the provider will produce wrong namespace)
This is your Service Provider content, here you reference the class that extends the package's class. Note you overwrite the binding from the original package.
namespace App\Repositories\ExtendedCart;
use Gloudemans\Shoppingcart\ShoppingcartServiceProvider;
class ExtendedCartServiceProvider extends ShoppingcartServiceProvider
{
public function register()
{
$this->app->bind('cart', 'App\Repositories\ExtendedCart\ExtendedCart');
}
}
Then register your service provider in config/app.php
'providers' => [
...
//Add this line to the end of providers array
App\Repositories\ExtendedCart\ExtendedCartServiceProvider::class,
]
Lastly create a Facade, which will instantiate the class (otherwise you will get non-static method exceptions). Create this file:
app/Repositories/ExtendedCart/Facades/ExtendedCart.php
This is the contents of the file:
namespace App\Repositories\ExtendedCart\Facades;
use Illuminate\Support\Facades\Facade;
class ExtendedCart extends Facade {
protected static function getFacadeAccessor() { return 'cart'; }
}
You're all set to use your extended methods. You can safely upgrade the original package, and you can even use the default facade:
namespace App\Http\Controllers;
use Cart;
class SomeController extends Controller{
public function someFunction(){
Cart::instance('default')->myMethod();
//This should return 'myMethod'
}
}
I hope this helps, good luck!
My helper root
app\http\myHelpers\customClass.php
customClass.php
<?php
namespace App\Http\myHelper;
class CustomClass {
public static function customFunction(){
return 'Custom class working......';
}
}
Controller function
public function test(){
CustomClass::customFunction();
}
routes
Route::get('/test', 'HomeController#test');
There is no need composer command. It is work properly but I am not sure to is it correct system or wrong system. Please help me.
How you organize your code is honestly a personal choice. So there is nothing wrong with your code. You don’t need any composer command because in Laravel everything in the app folder is auto loaded by composer: The App Directory
This is perfectly fine, what you can do additionally is to organize function inside traits and place them e.g. in the /app folder.
<?php
namespace App;
trait HasRoles
{
public function hasPermission(Permission $permission)
{
return $this->hasRole($permission->roles);
}
}
and use this trait inside your controller like
use Authenticatable, Authorizable, CanResetPassword, HasRoles;
just another way of bundling helper functions!
I have a new installation of Laravel 5. The problem is that it's not recognizing my model classes. I will keep it very simple for solution purposes.
Route::get('test', function() {
$test = boxstyle::all();
....
}
My model is in the app directory
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Boxstyle extends Model {
protected $table = 'boxstyle';
protected $primaryKey = 'key1';
}
I am getting:
class boxstyle not found error
I've been searching all over the internet and can't find a solution. This installation is fresh. This isn't magic and I suspect a configuration issue but I can't find a solution. This works fine in Laravel 4.2 so I know it should work but not working in L5.
Your model is defined inside the App namespace. If the code accessing the model is not in the same namespace as the model, you need to qualify it.
Route::get('test', function() {
$test = \App\Boxstyle::all();
}
Laravel 4 did not define the models and controllers inside namespaces. Your models would have been defined inside the global namespace, so any code also in the global namespace (like your controller) would not need to qualify the model. However, Laravel 5 has made the push to put most everything inside namespaces.
To create a model in Laravel 5 try this,create a folder name "Models" folder under your App folder, now for instance you want to create a Model class for Boxstyle ...under your Models folder create a file name
"BoxstyleModel.php" inside your BoxstyleModel.php should look like this and make sure your inside the folder to namespace your model under the App\Models
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class BoxstyleModel extends Model {
public static function say_hello(){
return "Hello";
}
}
in your Boxstyle Controller to be able to use your BoxstyleModel added this code at the top of your BoxstyleController use App\Models\BoxstyleModel;
now everything should be the same like Laravel 4.X.
Current Paginator is using ?page=N, but I want to use something else. How can I change so it's ?sida=N instead?
I've looked at Illuminate\Pagination\Environment and there is a method (setPageName()) there to change it (I assume), but how do you use it?
In the Paginator class there is a method the change the base url (setBaseUrl()) in the Environment class, but there is no method for setting a page name. Do I really need to extend the Paginator class just to be able to change the page name?
Just came across this same issue for 5.1 and you can pass the page name like this:
Post::paginate(1, ['*'], 'new-page-name');
Just like you said you can use the setPageName method:
Paginator::setPageName('sida');
You can place that in app/start/global.php.
Well that didnt work for me in laravel 5 , in laravel 5 you will need to do more extra work by overriding the PaginationServiceProvider because the queryName "page" was hardcoded in there , so first create your new PaginationServiceProvider in /app/providers ,This was mine
<?php
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider as ServiceProvider;
class PaginationServiceProvider extends ServiceProvider {
//boot
public function boot()
{
Paginator::currentPageResolver(function()
{
return $this->app['request']->input('p');
});
}//end boot
public function register()
{
//
}
}
Then in your controllers you can do this
$users = User::where("status","=",1)
->paginate(5)
->setPageName("p");
i want to use the alias classes on laravel 4 "facades" like App::method , Config::method.
Well the thing is that i create a custom class and i have to import the namespaces like
<?php
namespace Face\SocialHandlers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
public function registrar($perfil) {
Config::get('facebook');
}
}
is there any way to use those classes like in controllers or routes files of the framework ?
like
<?php
namespace Face\SocialHandlers;
//use Illuminate\Support\Facades\App;
//use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
public function registrar($perfil) {
Config::get('facebook');
}
}
Cya
ps: sry for my english
You can use use Config; instead of the more verbose use Illuminate\Support\Facades\Config; and the autoloader should handle it correctly.
Just as a tip, you shouldn't hardcode dependencies in your code. Instead of using the facades, you could create an "ConfigInterface" to get the common dependencies you need. Then create a "LaravelConfig class" (Or Laravel4Config.php) and implement those methods.
For a Quick Fix Answer, "catch the underliying facade instance":
namespace Face\SocialHandlers;
//use Illuminate\Support\Facades\App;
//use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
protected $config;
protected $app;
public function __construct()
{
$this->config = \Illuminate\Support\Facades\Config::getFacadeRoot();
$this->app = \Illuminate\Support\Facades\App::getFacadeRoot();
}
public function registrar($perfil) {
$this->config->get('facebook');
}
}
For a Real Answer, maybe tedious, but good in the long run, instead of using the facades use an interface.
interface SocialConfigInterface
{
public function getConfigurationByKey($key)
}
Then
class Laravel4Config implements SocialConfigInterface
{
protected $config;
public function __construct()
{
$this->config = \Illuminate\Support\Facades\Config::getFacadeRoot(); //<-- hard coded, but as expected since it's a class to be used with Laravel 4
}
public function getConfigurationByKey($key)
{
return $this->config->get($key);
}
}
And Your Code
namespace Face\SocialHandlers;
//use Illuminate\Support\Facades\App;
//use Illuminate\Support\Facades\Config;
class FacebookHandler implements SocialHandlerInterface {
protected $config;
public function __construct(SocialConfigInterface $config)
{
$this->config = $config;
}
public function registrar($perfil) {
$this->config->get('facebook');
}
}
This way, if you want to change between frameworks you just need to create a SocialConfigInterface Implementation, or imagine the scenario where Laravel 5 wont use Facades, you want your code to be independent of "outsider changes" this is inversion of control IoC
First run,
php artisan dump-autoload
This will add your class namespace to vendor/composer/autoload_classmap.php. Now locate the entry for your class in this classmap array and get the proper namespace from there.
For example, you will get something like,
'Illuminate\\Support\\Facades\\App' => $vendorDir . '/laravel/framework/src/Illuminate/Support/Facades/App.php',
For this particular entry you have an alias in app/config/app.php
'App' => 'Illuminate\Support\Facades\App',
At the same way, locate your entry and use an alias in app/config/app.php.
You just have to create a folder, or place a class wherever already is listed for autoload. Me, for exemple, have this class PDFMaker, that uses a DomPDF Laravel implementation. I created a folder named libraries and put the path to it (under the app folder) in the autoload:classmap key on composer.json
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/libraries",
"app/models",
"app/helpers",
"app/database/migrations"
]
I did the same with commands for artisan commands! When you do that, you only have to declare a new object for any class under that folder, or call it in a static way, if the class has defined static methods. Something like Class::method.
Hope it helps you, have a nice day! :D
EDIT: After that, don't forget the dump-autoload for placing the new class in autoload scope.
EDIT 2: Remember that once you've put the class on autoload, it will be in same scope the others, so you won't have to import it to other, neither others to it!
You can also prefix the class names with a backslash, to use the global namespace: \Config::get('facebook') and \App::someMethod() will work without the need to add a use statement, regardless of the file's namespace.