I'm building a PHP web application with Laravel and am trying to pass a name and email from a form to my database, but it displays this error:
Fatal error: Uncaught Error: Class 'user' not found in
C:\xampp\htdocs\MVC\app\controller\home.php:20 Stack trace: #0
C:\xampp\htdocs\MVC\app\core\app.php(43): home->create('hala',
'hala#yahoo') #1 C:\xampp\htdocs\MVC\public\index.php(4):
app->__construct() #2 {main} thrown in
C:\xampp\htdocs\MVC\app\controller\home.php on line 20
This is the code I'm using for the home page:
class home extends controller
{
public function index($name = '')
{
$this->view('home/index', ['name'=>$user->name]);
}
public function create($username = '', $email = '')
{
user::create([
'username' => $username,
'email'=> $email
]);
}
}
and the model:
use Illuminate\Database\Eloquent\Model as Eloquent;
class user extends Eloquent
{
public $name;
protected $fillable = ['username','email'];
}
What am I doing wrong and how can I fix it?
In your controller code, you need to include the user class:
require_once("user.class.php"); /* or whatever the file is named */
If this is done automatically and the class is in a different namespace, you need to declare your intent to use it in the controller:
use \my\namespace\user;
Or just use the fully qualified class name in your code:
\my\namespace\user::create();
If you use illuminate/database then chances are you are using composer. Why not add a PSR-4 auto load rule and structure your code accordingly. Eg. composer.json might look like this:
{
"name": "acme/acme",
"description": "Acme is this and that",
"type": "project",
"require": {
"php": "^7.2",
"illuminate/database": "^5.7"
},
"autoload": {
"psr-4": {
"Acme\\": "src"
}
},
"license": "proprietary"
}
Runing composer install makes you an vendor/autoloader.php and it is the only file you need to require. You put your own code un the Acme (or whatever you chose) namespace. Eg. You put your user model under src/Model/User.php and add your namespace:
<?php
namespace Acme\Model;
use Illuminate\Database\Eloquent\Model as Eloquent;
class User extends Eloquent
{
public $name;
protected $fillable = ['username','email'];
}
Your main file might look like this..
<?php
// entry point file
require_once('vendor/autoload.php');
use Acme\Model\User;
$user = new User();
// ...
Obviously you would make most logic in some class so this should be quite short.
This might seem obvious to people working on recent projects, but I have seen too many projects that still have a static file including all the classes like we did in the olden days. Move your projects to the 2010s now!
Related
I just figured out how to install and use PHP composer and used it to instal php-sql-query-builder to my project. The system created the vendor folder, etc. however I am having issues using classes within the package. It gives me the following error, any suggestions on how I can fix this?
Fatal error: Uncaught Error: Class 'NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder' not found in D:\Documents\CadetPortal\php\lib\login.class.php on line 15
Login.class.php
require_once ("core.class.php");
require_once ("../../vendor/autoload.php");
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
class LoginSystem {
private $core;
private $builder;
private $config;
function __construct(){
$this->core = new coreFunctions();
$this->builder = new GenericBuilder();
$this->config = require('core.config.php');
}
//....
}
EDIT
fncregister.php
require_once "../../vendor/autoload.php";
$LoginManager = new \ThomasSmyth\LoginSystem();
echo $LoginManager->Register($_POST["StrSurname"], $_POST["StrForename"], $_POST["StrEmail"], $_POST["StrPassword"], $_POST["DteDoB"], $_POST["StrGender"], $_POST["StrToken"]);
composer.json
{
"require": {
"nilportugues/sql-query-builder": "^1.5"
},
"autoload": {
"psr-4": {
"ThomasSmyth\\": "php/lib/"
}
}
}
Your class source files shouldn't have any require_once statements at all in them. Follow the PSR-4 spec for naming. Put your classes in a namespace to avoid collision with other classes you might include via composer. Then put one class in one file, named the same as the class. For example, the LoginSystem class should be in a file named LoginSystem.php.
namespace MyNamespace;
class LoginSystem
{
...
}
Then set your composer.json to point your namespace to your source directory:
"autoload": {
"psr-4": {
"MyNamespace\\": "src/"
}
},
Now, your main app invoker or front controller should be the only place that includes the autoloader:
require_once 'vendor/autoload.php';
$login = new \MyNamespace\LoginSystem();
...
I have a Duck Interface (abstract class in this case) and Class MallardDuck is implementing it. I'm trying to autoload files from the Duck name space but gets a fatal error.
PHP Fatal error: Interface 'Duck\Duck' not found in /var/www/HeadFirstDesignPattern/MallardDuck.php on line 11
I'm used to of working in Laravel which loads files for me, but I want to do it myself using composer. I know it's not a very big issue but when you don't know something then it's considered as a really big problem. Anyways here is the code of my classes and composer.json
Duck class code:
<?php namespace Duck;
//Duck.php
/**
* Description of Duck
*
* #author me
*/
abstract class Duck {
public abstract function display();
public function quack() {
echo 'quack';
}
public function swim() {
echo 'swim';
}
}
Mallard Duck Code
//MallardDuck.php
use Duck\Duck;
/**
* Description of MallardDuck
*
* #author mkhuram
*/
class MallardDuck implements \Duck{
public function display() {
echo __NAMESPACE__;
echo "\n".__CLASS__;
}
}
$md = new MallardDuck();
$md->display();
Compser.json File
{
"name": "vendor/head-first-design-pattern",
"description": "Description of project HeadFirstDesignPattern.",
"authors": [
{
"name": "me",
"email": "my#email.com"
}
],
"require": {},
"autoload": {
"psr-4":{
"Duck\\": ""
}
}
}
"Duck\\": "" is pointing to root of my app. Here is my app directory structure:
vendor
autoload.php
app
Duck.php
MallardDuck.php
You cannot implement an abstract class, you can only extend it.
I am trying to implement a Billing interface which uses Stripe.
I have created the Billing interface, Stripe class and binded the interface using a Service Provider.
I receive a Class not found error when trying to run the code:
ReflectionException in Container.php line 737: Class
Acme\Billing\StripeBilling does not exist
I can't figure out what the issue is, I've double checked for small issues like correct case etc.
Here is the code I've used:
app/Acme/Billing/BillingInterface.php
<?php
namespace Acme\Billing;
interface BillingInterface {
public function charge(array $data);
}
app/Acme/Billing/StripeBilling.php
<?php
namespace Acme\Billing;
use Stripe;
use Stripe_Charge;
use Stripe_Customer;
use Stripe_InvalidRequestError;
use Stripe_CardError;
use Exception;
class StripeBilling implements BillingInterface {
public function __construct()
{
Stripe::setApiKey(env('STRIPE_SECRET_KEY'))
}
public function charge(array $data)
{
try
{
return Stripe_Charge::create([
'amount' => 1000, // £10
'currency' => 'gbp',
'description' => $data['email'],
'card' => $data['token']
]);
}
catch(Stripe_CardError $e)
{
dd('card was declined');
}
}
}
app/Providers/BillingServiceProvider.php (UPDATED)
class BillingServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Billing\BillingInterface', 'Billing\StripeBilling');
}
}
BasketController.php (ADDED)
public function store(Request $request)
{
$billing = \App::make('Billing\BillingInterface');
return $billing->charge([
'email' => $request->email,
'stripe-token' => $request->token,
]);
I have added App\Providers\BillingServiceProvider::class to my app.php file, and updated my composer.json to include Acme folder "Acme\\": "app/"
Your problem looks two-fold:
The PSR-4 autoload definition in your composer.json file is incorrect.
If your Acme folder lives inside the app folder, e.g. /dir/project_root/app/Acme/Billing/BillingInterface.php, then your composer.json definition should look like this:
"psr-4": {
"Acme\\": "app/Acme"
}
This is the root cause of the error you are receiving, which is not a Laravel-specific error. The autoloader simply cannot find the class you are asking for, even though the requested fully qualified class name is correct.
Your interface and class are not bound to the container properly (missing the Acme portion of the namespace).
Because you've defined both of them in the Acme namespace, you need to ensure Acme is present in your service provider definitions. So your service provider should look like this:
class BillingServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Acme\Billing\BillingInterface', 'Acme\Billing\StripeBilling');
}
}
(Or, better yet, use the ::class syntax for improved IDE support.)
You will also need to make sure the fully qualified classname is correct when requesting the class in your controller: App::make('Acme\Billing\BillingInterface'). (I would recommend using dependency injection instead of this syntax, anyway.)
I used the following tutorial to get an idea about interfaces:
http://vegibit.com/what-is-a-laravel-interface/
But I wanted to change the directory of where I am putting my interfaces to "App/Models/Interfaces". And so I did. But now I cannot get it to work anymore. Here is my code:
Routes.php
App::bind('CarInterface', 'Subaru');
Route::get('subaru', function()
{
$car = App::make('CarInterface');
$car->start();
$car->gas();
$car->brake();
});
Model Subaru.php
<?php
use App\Models\Interfaces\CarInterface;
class Subaru implements CarInterface {
..etc
Interface CarInterface
<?php namespace App\Models\Interfaces;
interface CarInterface {
public function start();
public function gas();
public function brake();
}
I added this in my composer.json:
"psr-0": {
"Interfaces": "app/models/interfaces"
}
And I even added this in my start/global.php file:
ClassLoader::addDirectories(array(
app_path().'/models/interfaces',
In my recent laravel 5 project, I'm used to prepare my logics as Repository method.
So here's my current directory structure. For example we have 'Car'.
So first I just create directory call it libs under app directory and loaded it to composer.json
"autoload": {
"classmap": [
"database",
"app/libs" //this is the new changes (remove this comment)
]
}
after that I create a subfolder call it Car . Under the Car folder create two file 'CarEloquent.php' for eloquent implementation and CarInterface.php as interface.
CarInterface
namespace App\libs\Car;
interface CarInterface {
public function getAll();
public function create(array $data);
public function delete($id);
public function getByID($id);
public function update($id,array $data);
}
CarEloquent
namespace App\lib\Car;
use App\lib\Car\CarInterface;
use App\Car; //car model
class CarEloquent implements CarInterface {
protected $car;
function __construct(Car $a) {
$this->car = $a;
}
public function getAll(){
return $this->car->all();
}
}
Then create Car Service Provider to bind ioc controller.
For create Car service provider you can also use php artisan command by laravel.
php artisan make:provider CarServiceProvider
ServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class CarServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind('App\lib\Car\CarInterface', 'App\lib\Car\CarEloquent');
}
}
And final step would be add these service provider to config/app.php provider array.
'providers' => [
'App\Providers\CatServiceProvider',
]
And finally we are ready to use our repository method in our controller.
Example Controller
namespace App\Http\Controllers;
use App\lib\Car\CarInterface as Car;
class CarController extends Controller {
protected $carObject;
public function __construct(Car $c) {
$this->carObject = $c;
}
public function getIndex(){
$cars = $this->carObject->getAll();
return view('cars.index')->with('cars',$cars);
}
}
Main purpose to achieve here call repository method to controller, however you need use them as per your requirement.
Update
CarEloqent basically help us to improve database implementation, for example in future if you want to implement same functionality for other database like redis you just add another class CarRedis and change implementation file path from server provider.
Update 1: Good Resource
http://programmingarehard.com/2014/03/12/what-to-return-from-repositories.html
[book] From Apprentice to Artisan by Taylor Otwell
Very good explanation about repository method and software design principle commonly called separation of concerns. You should read this book.
If you still have any confusion to achieve these behaviors let me know and however I will keep eye on this question to update this answer, if I find some things to change or update or as per requirement.
I have a User eloquent model that takes in an instance of the UserMailer class in its constructor but I get this error
Argument 1 passed to User::__construct() must be an instance of TrainerCompare\Mailers\UserMailer, none given, called in /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 631 and defined
I understand the error but can't figure out what I have done wrong but I don't udnerstanding namespacing and composer class map vs psr0 autoloading very well. I have remembered to use composer dump-autoload so it is not that
relevant folder structure
composer.json
app/
models/
User.php
TrainerCompare/
Mailers/
Mailer.php
UserMailer.php
Services/
Validation/
composer.json autoload section. psr-0 section is there from when I added the validation service you can see in TrainerCompare/ and these classes work great. I added app/TrainerCompare/Mailers to the classmap per the tutorial I am following to get the mailer classes loaded
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/tests/helpers",
"app/TrainerCompare/Mailers"
],
"psr-0":{
"TrainerCompare": "app/"
}
}
User.php
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
use TrainerCompare\Mailers\UserMailer as Mailer;
class User extends BaseModel implements UserInterface, RemindableInterface
{
protected $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
}
Mailer.php
<?php namespace TrainerCompare\Mailers;
use Mail;
/**
* Email mailing class
*/
abstract class Mailer
{
public function __construct()
{
# code...
}
public function sendTo($user, $subject, $view, $data = [])
{
Maill::send($view, $data, function ($message) use ($user, $subject) {
$message->to($user->email)
->subject($subject);
});
}
}
UserMailer.php
<?php namespace TrainerCompare\Mailers;
use User;
/**
* User Mailer Class
*/
class UserMailer extends Mailer
{
public function __construct()
{
# code...
}
public function welcome($user)
{
$view = 'emails.users.welcome';
$data = [];
$subject = 'Welcome to Laracsts';
return $this->sendTo($user, $subject, $view, $data);
}
}
Eloquent (re)creates itself internally by calling:
new static
An example is in creating a new query:
return with(new static)->newQuery();
I'm not sure if automatic dependency resolution would work in this case, it should always work inside laravel, but as it also has it's own constructor method, you must at least forward a call to it and support the $attribute parameter:
public function __construct(array $attributes = array(), Mailer $mailer)
{
$this->mailer = $mailer;
parent::__construct($attributes);
}
EDIT
Opened an issue to understand it: https://github.com/laravel/framework/issues/3862
EDIT 2
As I've said in comment, you better create a service, as pointed by yourself, is a better application design. You should not be using your model to send e-mails. A service that receives a user model (or just name and e-mail) and send the message to that user would be a better way to go.
Answer given by Taylor Otwell about it in the issue:
Models aren't really meant to have dependencies injected into them that way.
Kind of just the style of ActiveRecord style ORMs I guess.
I would suggest passing the User to a Mailer class or something similar.
Or if you're comfortable with it you could use App::make to grab an instance of
Mail from the model instance, especially if you only need that dependency
from a single method.