composer.json contains the following
...
"autoload": {
...
"psr-0":{"Acme": "app/lib"}
},
at app/lib/Acme/Models/Product/Display.php I have the following:
<?php
namespace Acme\Models\Product;
use Eloquent;
use Db;
class Product_Display extends Eloquent
{
I'm lost on how to call that class given the underscore in the Class Name inside of a repository class:
<?php
namespace Acme\Repositories;
use Acme\Models\Product\Display as Product_Display;
...
Product_Display::where('page_id','=',$page_id)->first();
This gives me a Class 'Acme\Models\Product\Display' not found error.
I'm guessing the problem lies in the use Acme\Models\Product\Display as Product_Display, but I've tried several variations none of which seemed to cure the problem.
Did you composer dump-autoload? Do this by typing composer dump-autoload in the terminal from the root of your project.
Every time you make changes to your composer.json file you need to allow composer to reconstruct the autoload files. In the case of psr-0 this is all you need to do.
In the case of classmap autoloading, every time you add a file to a directory that is being autoloaded, you need to composer dump-autoload.
edit:
To fix: change use Acme\Models\Product\Display as Product_Display; to use Acme\Models\Product\Display. Change the class name from Product_Display to just Display.
I think I spotted the issue. You have use Acme\Models\Product\Display as Product_Display; but you need to use Acme\Models\Product\Product_Display; since the last part of the use statement is the name of the class. In this case your class actually is named Product_Display, not Display (which is the file name). You might also need to change the file name to match the class name (also for conventions sake you should do this).
You are using PSR-0 autoloading. This scheme converts every backslash and every underscore into a directory separator when building the path to the file.
So Acme\Whatever_Underscored is searched for in the path prefix/Acme/Whatever/Underscored.php.
With PSR-4, the rules have changed. First, it only works for namespaced classes, not the old Acme_Underscore_Endless_Classnames. Second, you don't have to have a set of otherwise emtpy directories if you don't want to. Third: Underscores are NOT converted to directory separators.
With PSR-4 rules, the Acme\Whatever_Underscored is searched for in the path prefix/Acme/Whatever_Underscored.php - or even prefix/Whatever_Underscored.php if configured so.
You got confused because you connected the class name in the code with the path to the file. PHP only cares about the class name in use imports. Always use the class name as it is defined in your class's file. Then the autoloader kicks in and tries to find a matching file - with the rules of either PSR-0 or PSR-4. If it cannot find the correct file (either the path does not point to the file correctly, or the file does not contain the class being searched for), you get an error.
Related
I am trying to call my model file from another folder. I have provided both of these file structure.
I am getting this error:
Uncaught Error: Class 'App\Models\Providers' not found in /Applications/XAMPP/xamppfiles/htdocs/pro/app/Scripts/Providers/1/Scrape.php:17
I am calling the model file from a script folder located :
app/Scripts/Providers/1/Scrape.php
In this class I have the below :
namespace App\Scripts\Providers\1;
use App\Models;
Model file is located :
app/Models/Providers.php
Within this file I have the below:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
I have not shared the full content that I have in both of these files. If you would like to see the full content of these files please let me know.
This is how the Scrape.php looks like
<?php
namespace App\Scripts\Providers\1;
use App\Models\Providers;
class Scrape {
public function __construct() {
$test = new \App\Models\Providers();
die(print_r($test, true));
}
}
$obj = new Scrape();
You can't have a namespace that starts with a number.
Namespaces follow the same basic rules for variable names:
A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores
(Emphasis mine).
Thus, your declaration
namespace App\Scripts\Providers\1
is basically invalid.
From that point forward, all bets are off.
First, change your namespace to a valid identifier (and I would advise choosing something more reasonable and recognizable than numbers, you can have descriptive names and there is simply no reason not to):
namespace App\Scripts\Providers\GroupWhatever
Logically, you'll have to rename the folder where this file resides. It used to be
app/Scripts/Providers/1/Scrape.php
so rename that directory to
app/Scripts/Providers/GroupWhatever/Scrape.php
(In both cases, replace GroupWhatever with something that makes sense for your application and domain).
From that point forward, if the class \App\Models\Providers exists at app/Models/Providers.php, it should work.
Important:
Another problem that there could exist, is that is not very clear what Scripts/Scrape.php is or how is it called.
This should work if you are executing Scrape.php from within Laravel, by calling a Laravel controller or console application.
If you are calling this script directly (e.g. by executing php app/Scripts/Providers/1/Scrape.php (or the corrected app/Scripts/Providers/GroupWhatever/Scrape.php) this simply won't work, since the autoloading logic is not run at all.
If you are executing your script manually, on top of the above changes you need to include composer autoload script, which is located at vendor/autoload.php.
Basically, add this line close to the top of your Scrape.php:
require_once dirname( __DIR__ ) . '/../../../vendor/autoload.php';
(I think I put the appropriate amount of go-up-one-dir path-segments, but you make sure it matches the correct path in your installation).
Once that is in place, the autoloader will be run, and classes will be found.
In your Scrape.php, change your namespace to:
<?php
namespace App\Scripts\Providers\p1;
From PHP manual comment,
namespace (even nested or sub-namespace) cannot be just a number, it
must start with a letter. For example, lets say you want to use
namespace for versioning of your packages or versioning of your API:
namespace Mynamespace\1; // Illegal
Instead use this: namespace
Mynamespace\v1; // OK
I've set up a really basic autoloader in my index.php to grab a namespaced class within hello.php. My development environment is Ubuntu 12.04.
Why am I trying to do this? I'm trying to stick to the PSR-1 and PSR-2 coding standard, that includes:
Class names MUST be declared in StudlyCaps
Namespaces are as /Vendor/Class (note: capitals)
The following is my structure and code that works before making the changes to capitals.
Folder Structure
- web
-- index.php
-- core
--- hello.php
Autoloader
Within index.php, I have my autoloader:
set_include_path(__DIR__);
spl_autoload_extensions('.php,.class.php');
spl_autoload_register();
Class File
Within the core folder, I have hello.php
namespace core;
class hello {
public function __construct() {
echo 'Constructed!';
}
}
Code that works
If I run $obj = new \core\hello(); in my index.php, I get back "Constructed!". Great!
That which doesn't work
Renaming my core folder to 'Core' - note the uppercase C, and also the namespace in hello.php to namespace Core;.
Now let's try again with $obj = new \Core\hello();
Fatal error: Class 'Core\hello' not found in ...
So please tell me, why am I not able to use capital letters to keep inline with the PSR standards? What am I doing wrong?
When you run your PHP code on a Linux platform, it's important to remember that Linux is case sensitive with filenames.
This affects autoloaders because they typically use the namespace and the class name when building the filename to load.
If the folder is named core, then the namespace must be core, with the same capitalisation. If you change it to Core in the namespace, then you must do the same to the folder name. (and as a result, all other core classes must be changed to Core at the same time).
On Windows, this doesn't happen because the Windows filesystem isn't case sensitive. This can cause confusion when code is tested and works on a local Windows-based dev system, and then breaks when it is copied to a Linux-based server.
[EDIT]
Okay, so I missed that you had changed the dirname as well. But nevertheless, I still think this is an issue of the filename/dirname case.
I note that you're calling spl_autoload_register() without any params. This means that the default spl_autoload() function will be used as the autoloader.
If you read the documentation for spl_autoload(), you'll note that it uses the lowercased version of the class and namespace.
In other words, using the default autoloader, your classes can be mixed case, but the folder structure and filenames must be all lower case.
So in fact, for you, you need to keep your filenames lower case.
I've personally experienced it the other way round, as per my original answer, where I had a fully lower case filename, and my mixed case class name was breaking when I moved from Windows dev box to Linux server. The reason my experience is different from yours is because I'm using a custom-written autoload function, which doesn't do an auto-lowercase conversion, so the case of my filenames has to match that of my classnames.
I think you have shown us some good ambiguity.Correct me if I am wrong.
According to the specification you have to use the lowercased name of the class (and namespace) being instantiated.(http://www.php.net/manual/en/function.spl-autoload.php)
But PSR tells us to use the capital letters. If you want to stick with PSR then we have to overwrite the default spl_autoload to our own.
For anyone else having issues with this, why not make use of ucfirst() or strtolower() ?
So the code below would try all lowercase and also try first letter uppercase files
e.g: somename.class.php or Somename.class.php
The is_readable() checks first as to not display the php error for file not found.
spl_autoload_register(function($name) {
if (is_readable(strtolower($name).'.class.php')) {
require_once(strtolower($name).'.class.php');
}
elseif (is_readable(ucfirst($name).'.class.php')) {
require_once(ucfirst($name).'.class.php');
}
});
I am a novice laravel developer and I am trying to understand how namespacing works in here. So I was learning about the Repository pattern and decided to go ahead and implement it in my project.
So I created a directory called archive and then loaded it using PSR4 in my composer.json file like so:
"Archive\\": "archive/"
Now I created a Repositories folder in my archive folder where I will be creating all the repositories. And I am namespacing files in it like so:
namespace Archive\Repositories;
Which seems to working fine. Then I created a Contracts folder inside the Repositories folder which will hold all the interfaces to the implementations I am going to use like UserRepositoryInterface for example. And I am namespacing files in the Contracts folder like so:
namespace Archive\Repositories\Contracts;
Which is working fine too.
Now my doubt lies in the concrete implementations I am trying to make in the Repositories folder. Like for example there is a DbUserRepository which implements The UserRepositoryInterface in the Contracts folder.
Now since I am new to this I tried:
class DbUserRepository implements Contacts\UserRepositoryInterface
And it works just fine but then I thought I should use it on top of the file like so:
use Contacts\UserRepositoryInterface;
And I could just do:
class DbUserRepository implements UserRepositoryInterface
And it should work fine according to me but it gives me a class not found exception but when I do something like:
use Archive\Repositories\Contacts\UserRepositoryInterface;
It works fine now. But this is where I am blurry. Inside the DbUserRepository I am in the nampspace of Archive\Repositories already so why doesn't it just go on to look into the Contracts folder from there? Why do I need to specify the full this as use Archive\Repositories\Contacts\UserRepositoryInterface;
Why can't I just say:
use Contacts\UserRepositoryInterface;
I hope my question is not too confusing. Although my code is working now but I am blurry how namespacing works.
The rules are pretty simple:
All namespace and use statements always use fully qualified names (FQN), meaning they always start from the global namespace and are not relative to anything else. use Foo\Bar always means \Foo\Bar, no matter what namespace you're in.
All literal mentions of names inside the rest of the code are resolved relative to the current namespace and/or aliases established with use statements. new Foo, extends Foo and such either mean __NAMESPACE__\Foo, or whatever Foo you might have aliased in some use statement.
If you want to shorten names, you need to use use statements which use the FQN of the class, not relative to the current namespace.
I have a laravel 4.1 application, and I've created a folder in my app folder to store most of the logic.
/app/Acme/Models/
/app/Acme/Repositories/
these are the two main folders.
In my composer.json I have this in the auto load, and done a dump run.
"psr-4" : {
"Acme\\" : "app/Acme"
}
However I am getting, what I think are silly issues. For example my Acme/Models/Task.php has the following
<?php
namespace Acme\Models;
class Task extends \Eloquent {
public function job()
{
return $this->belongsTo('Job');
}
}
however when I run this, I get an error
Fatal error: Class 'Task' not found in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 780
In my Job.php I have the same namespace at the top of the file....
Must I manually import/use object which are in the same name space?
use Acme/Models/Job as Job; ? it seems like such a duplicate...
And in my Repositories folder when I set a namespace of namespace Acme/Repositories;, must I use items like
use Acme\Models\Job as Job;
I is, a bit lost!
Namespaces are relative so you do not need to add use to directly reference classes within the same namespace.
The error you are getting is because you need to fully qualify relationships to namespaced models so eloquent knows where to find them eg
$this->belongsTo('\Acme\Models\Jobs');
In the case of your repository namespace, you will need to add a use statement in your file as you suggested, or reference the fully qualified namespace eg new \Acme\Models\Job();
On a side note, I know PHPStorm (and I'm sure other IDEs) will inject the namespaces for you which is super useful and saves you having to write use or the full namespace out every time you reference a class - worth checking out.
Edit: Sorry, I didn't read the question properly first time around - updated my answer.
This is what I have at hand:
//Person.php
namespace Entity;
class Person{
}
User file:
//User.php
use Entity\Person;
$person = new Person;
Here, it fails if I don't include the Person.php file. If I include it, the everything works fine. Do I absolutely require to include the file even when using namespaces? If at all we need to include/require files, then how can namespaces be effectively used? Also, can we maintain folder structure by nesting namespaces?
The answer to your question is "yes and no".
Indeed the code implementing class Person has to be included, otherwise the class is not defined and cannot be used. Where should the definition come from, when the code is not included? The php interpreter cannot guess the classes implementation. That is the same in all programming languages, by the way.
However there is something called Autoloading in php. It allows to automatically include certain files. The mechanism is based on a mapping of class names to file names. So in the end it boils down to php searching through a folder structure to find a file whos name suggests that it implements a class currently required in the code it executes.
But don't get this wrong: that still means the file has to be included. The only difference is: the including is done automatically, so without you specifying an explicit include or require statement.
Yes, you need to include every file.
A very good example can be found here on effective usage of namespaces.
With PSR-0 autoloading, the namespace has to be the same as the folder in which the class is, file the filename has to be the same as the classname. This gives you very simple and effective autoloading with composer for example.