Laravel - Call to undefined method TrainingFacade::save() - php

I'm building a Laravel 4.2 app and I'm using Creolab's Modules package. It's an app for managing company trainings, so my module is called Trainings. All works well except saving newly created trainings. The error I receive when I submit the Create New form is:
Call to undefined method Roche\Trainings\Facades\TrainingFacade::save()
These are my TrainingsController, Training Model, TrainingFacade, Trainings Service Provider and routes. Nothing I try seems to fix it.

You don't need to change your facade alias here, but you have other error here.
In your AdminTrainingsController you want to use Training model so you import Training before your class definition this way:
use Training;
but model Training is not in root namespace, in root namespace there is TrainingFacade because you probably define it in your app.php file this way:
'Training' => 'Roche\Trainings\Facades\TrainingFacade',
That's ok, you don't need to change this facade alias.
So now, Laravel inject into your constructor not Training model but TrainingFacade (because Training in root namespace is alias for TrainingFacade).
What you need here is importing correct namespace for your Training model.
When we look at your Training model class we see the code is:
<?php namespace Roche\Trainings\Models;
class Training extends \Eloquent {
protected $guarded = array('id');
}
so it's in Roche\Trainings\Models namespace.
So to make it work in AdminTrainingsController you need to change:
use Training;
into:
use Roche\Trainings\Models\Training;
Now Laravel will inject into constructor Training model (and not TrainingFacade as it was doing).
EDIT
You could also make some tests, for example changing in your app.php your TrainingFacade alias, for example to:
'TrainingFacade' => 'Roche\Trainings\Facades\TrainingFacade',
but if you had use Training as you had, you would get the following error:
Class Training does not exist
because there would be no Training class in global namespace now (you changed alias for facade).
And if you removed use Training; completely, you would get:
Class Roche\Trainings\Controllers\Admin\Training does not exist
because by default class is loaded from current namespace, and your AdminTrainingsController is in Roche\Trainings\Controllers\Admin namespace
I hope now everything is clear, if it's not you could also look at How to use objects from other namespaces and how to import namespaces in PHP where I explained more about namespaces

Related

Laravel upgrade broke model paths

I've performed a long-overdue update on a Laravel project from v5.7 to v9 and ran into a Target class does not exist error. I found this guide and used the first method to resolve the error (adding the namespace into the RoutesServiceProvider.php boot function). This resolved that error but now, everything is giving me Class "App\Whatever" not found.
I did notice that models are now stored in a Models directory within the app directory rather than directly in app, so have moved them to Models. I figured that might be breaking my use App\Whatever; lines at the top of my controllers, so I've tried use App\Models\Whatever and also use app\Models\Whatever (since the "a" is lowercase in the directory name) but no effect.
I should note I don't really have a good grasp of namespaces, MVC frameworks etc. so ELI5 etc :-)
Some of my controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Thing;
use App\AnotherThing;
...
public function thing_summary($id) // show the summary view of the thing
{
if(Auth::check()) {
$thing = Thing::find($id);
...
Laravel 7/8/9 sticks with strict namespacing. When you move the models to a new directory, you need to update the namespace in the models themselves (if specified at all) and any file that has a use for the model. If the models move from app/ to app/models, the namespace must be changed to App/Models

Problem with packages after Laravel namespace change to App\Models

So I used the namespace models shift to make the change from App to App\Models.
One of the packages in use (Ticketit) is calls App\User in it and I need a way to override this.
The offending file is:
\vendor\kordy\ticketit\src\Models\Agent.php
How can I override the "use App\user;" line there?
From what I am looking at in the source code, that is hardcoded, so you cannot do anything then... I am not sure if you could "fake" the App\User to point to App\Models\User using composer but that would be nasty, same if you created a class on inside app folder with name User and it only extends the model like this:
namespace App;
use App\Models\User as UserModel;
class User extends UserModel { }
That is nasty but maybe is a solution for you...
Edit: If you read carefully the documentation (please do so next time you use a package), it already says to make sure that App\User exists...
It tells you to do:
namespace App;
class User extends Models\User {
//leave this empty
}
For more info, see this github issue or create yourself a new one.

Putting Laravel and Lumen controllers inside packages

I'm developing a package which has controllers in it and I want this package to be compatible with (or useable by) both Laravel and Lumen projects. My problem is Laravel controllers extend Illuminate\Routing\Controller and Lumen controllers extend Laravel\Lumen\Routing\Controller. The controller inside my package can't extend them both.
The only solution I've come up with is to have the controllers inside the package extend App\Http\Controllers\Controller.
But I see some problems:
App\Http\Controllers\Controller should exist; which means it wouldn't work if the App namespace is named differently.
The package is now "aware" that it is being included in something.
Testability: I can't test the controller independently because of the reference to App\Http\Controllers\Controller.
Is there a better way of doing this?
Edit 1
I'm finding other classes which are affected in a similar way. For example, the namespace of the trait Authorizable is Illuminate\Foundation\Auth\Access in Laravel while it is Laravel\Lumen\Auth in Lumen. I am using a model which uses that trait. How do I make my model compatible with both Lumen and Laravel?
Well, you could simply have two different files and classes wrapped in if statements and check for the corresponding classes to extend. So:
LaravelClass.php:
if(class_exists(Illuminate\Routing\Controller:class)){
class LaravelClass extends Illuminate\Routing\Controller {
use YourCodeTrait;
// any more code that is not in your trait
}
}
LumenClass.php
if(class_exists(Laravel\Lumen\Routing\Controller:class)){
class LaravelClass extends Laravel\Lumen\Routing\Controller {
use YourCodeTrait;
// any more code that is not in your trait
}
}
Loading both files will only load one of the classes. In the code above I use a trait to load the contents of your controller, assuming the contents is the same, you could use the same trait and not have to repeat yourself.
trait YourCodeTrait{
// whatever would normally go in your controllers
}

What namespace or facade do I have to use in Laravel to have access to my models inside a namespaced class?

I'm totally new to namespaces, and Laravel in general, so their use of Facades complicates the issue a bit for me.
I have set up a class that is namespaced:
namespace Libraries;
class UploadedFile {
}
(As there is already a Symfony class uploadedFile), and now in that class I need to use one of my models, which I can only assume rests somewhere under the Eloquent facade, yet if I:
use Eloquent;
and
use \Eloquent;
in my class, I am told my model cannot be found, yet if I prepend my model with a backslash directly:
return \Object::create(...);
It works perfectly fine. What do I need to use at the top of my namespaced file to include access to my models directly without the need for a slash?
Eloquent has nothing to do with this. You have to import your actual model Object:
use Object;

Referring to an Eloquent model from package

I am trying to use an Eloquent model inside the Sentry package (this could've been any package).
I've refered to it using use App\Models\User; in the top, and User:: when I need to call it.
However, I am getting this error: Class 'App\Models\User' not found
What am I doing wrong?
The current code is here: http://paste.laravel.com/H19
I assume thath your models are in the App part of the application.
In laravel, the App namespace is the top level namespace (the default one).
So to call your models, you have to call \User (because \ refer to the top level namespace)
Alternatively you can do:
use \User as User
And then you can call it User instead of \User

Categories