I want to add Accessors and Mutators to a model. In Laravel 4 it worked all fine, but with Laravel 5 I have some trouble.
I have a "lib" folder in my App directory which contains the "db_transformers.php" file. This file holds classes like "dbDate" with a set and get function to transform dates stored in the database to a user-friendly format.
The "db_transformers.php" file is namespaced:
<?php namespace App\lib;
I also rerfer to the folder in my model:
use App\lib;
But my methodes still throw errors:
public function getDateTimeAttribute($value)
{
return dbDate::get($value);
}
This will return a "Class 'App\dbDate' not found" error.
What could be my problem?
You're confusing autoloading (PHP including/requiring a class definition file) with namespaces (a system that allows hierarchical naming of PHP classes/functions to help prevent code conflicts).
It's an easy thing to do. Covering the changes to autoloading in Laravel 5 is beyond the scope of a Stack Overflow question, but if you're interested I've written a multiple article series on how autoloading works with composer/Laravel 4/Laravel 5.
To your specific question, you say you've defined a class named dbDate in a file named db_transformers.php, and db_transformers.php has a namespace of App\lib.
#File: lib/db_transformers.php
namespace App\lib;
//other code
class dbDate
{
//other code
}
//other code
This mean your class's full name is App\lib\dbDate. The entire thing is the class's name. That's probably the biggest thing to get used to with namespaces in PHP.
This means if you wanted to use the class in other code, you'd need to refer to the full class name, including a leading backslash.
return \App\lib\DbDate::get($value);
You could also import the class using the use keyword
use App\lib\DbDate;
//other code
public function getDateTimeAttribute($value)
{
//since we imported the class with `use`, we don't need to type the full name
return DbDate::get($value);
}
The use keywords imports a specific class into the current namespace. When you said
use App\lib;
you were telling PHP
You know that global classApp\lib? I'm going to refer to it below as lib
Since you don't have a class named lib, this is meaningless, and it's why your use didn't help.
So that's namespaces. The other problem you need to solve is autoloading. Autoloading is what lets you skip the require or include statement/function when you want a class definition files in your project.
Laravel 4 used a bunch of different autoloaders, including something called a classmap autoloader. The classmap autoloader automatically parses all the files in your project looking for classes, and creates a giant map of which class is where (that's over simplifying it a bit, see the article series I linked earlier for the full details).
In Laravel 4, the classmap autoloader probably read the file in lib for you. Laravel 5 reduced the number of autoloaders, which included getting rid of the classmap autoloader for most folders.
The simplest thing you can do in Laravel 5 is to configure your project to use the classmap autoloader again. Open up composer.json and find this section
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
}
},
And add lib to the classmap autoloader section
"autoload": {
"classmap": [
"database",
"lib"
],
"psr-4": {
"App\\": "app/"
}
},
This tells composer to include the lib folders when it creates its autoloader files. You'll need to run the dumpautoload command
composer dump-autoload
after doing that, and you should be able to use the classes defined in lib/db_transformers.php as you wish.
You need to use the complete class name: use App\lib\dbDate;
You might also look into using view decorators for this purpose, as doing it in your model is really not appropriate.
Several packages exist to help with this, e.g. https://github.com/ShawnMcCool/laravel-auto-presenter
Related
So subject is the question. Yes, I've searched this forum and googled too. All I've got - useless Symfony docs and casts, some general advises, cli-s and nothing case specific. Maybe yahoo or duckduck could help better?
Everyone is talking about bundles, about how it is important to create them, probably because under the hood Symfony is pushing users away from custom libraries, but no one is actually explains how to start using a bundle - how to start calling its methods.
No, my library is not a composer or whatever package. No, library methods do not return Response objects. No, I am not dealing with composer or recompilations or cli (I use Composercat). No, I will not put library to github or packagist to load it via composer or whatever because it is private library.
Sorry about emotional off-topic.
About the case: I've put my library into the folder
src/lib/MyLibrary.php
I suspect that library class is autoloaded, because if I do not extend Controller with it (if I declare class MyLibrary instead of class MyLibrary extends Controller) - Symfony spits "class name in use" error.
So question: in my controller how to call library method?
$this->get('MyLibrary') doesn't work.
echo print_r($this) doesn't show MyLibrary in this registry too.
Looks like library file is loaded but not registered and/or instantiated. If it is so, then where to point Symfony to register it?
So most of this question is really about how php manages classes. Not so much about Symfony. But that's okay.
To start with it would be best to move project/src/lib to just project/lib. Symfony has some scanning stuff going on in the src directory and you really don't want to have your library mixed up in it.
So:
# lib/MyLibrary.php
namespace Roman;
class MyLibrary
{
public function hello()
{
return 'hello';
}
}
Notice that I added a namespace (Roman) just to distinguish your code from Symfony's.
Now you need to tweak composer.json in order to allow php to autoload your classes:
"autoload": {
"psr-4": {
"App\\": "src/",
"Roman\\": "lib/"
}
},
After adding the Roman line, run "composer dump-autoload" to regenerate the autoload files.
After that, it's just a question of using regular php inside of your application:
# src/Controller/DefaultController.php
namespace App\Controller;
use Roman\MyLibrary;
use Symfony\Component\HttpFoundation\Response;
class DefaultController
{
public function index()
{
$myLibrary = new MyLibrary();
$hello = $myLibrary->hello();
return new Response($hello);
}
}
And that should get your started.
I am trying to change an autoloading system that I've written before.
I'm using composer and at the moment I'm autoloading just one library with class map.
"autoload": {
"classmap": ["libs/"]
}
I want to add a psr-4 loader for the rest of the files and to be able to call the files under libs without namespaces and without "use" them' kind of like aliases in laravel. This is what I'm trying to do:
"autoload": {
"classmap": ["libs/"],
"psr-4": {
"App\\": ""
}
}
So eventually if in "libs" I have the Session class I'm calling it as:
Session::get('anything')
but now after trying to add the psr-4 and calling it from within a namespaced class
namespace App\models;
Class User{
function get(){
return Session::get('anything');
}
}
It won't work anymore because it looks for session within the user's namespace.
I know there are many frameworks which implements it out of the box with aliases.., it's just that this project is kinda old and I'm trying to organize it a bit and get rid of all the requires anywhere - at the moment each model has to be required.
I want to add a psr-4 loader for the rest of the files and to be able to call the files under libs without namespaces and without "use" them' kind of like aliases in laravel.
You can't use the classes without either adding use or adding the fully qualified namespace path starting with the backslash \. This has nothing to do with the way you load these classes, but is a basic requirement of PHP itself - so there is no way around it no matter how you'd like to design your autoloading.
As was commented, adding a backslash works, but this is the required minimum:
namespace App\models;
Class User{
function get(){
return \Session::get('anything');
}
}
I've ended up writing another class that aliasing any classses that i want so i will be able to call them out of the box.
you can see it here:
https://github.com/shahafan/SAmvc-App/blob/master/Config/Aliases.php
basically i'm just using the php class_alias function so i can load all the classes that i want before using them.
i think laravel does it the same way.
I would like to call statics methods in a helpers folders.
I have tried many tutos but it's always for just one file.
My config
/app/Helpers/Languages.php -> my static class
composer.json
"autoload": {
"classmap": [
"database",
"app/Helpers/" <- I understand, L5 add in own autoload
app.php
'aliases' => [ ...., 'Languages' => 'App\Helpers\Languages',
What I tried :
Add autoload classmap, HelpersServiceProviders class, namespace (work just in blade template, not in a Controller)
Add autoload psr-4 with and without classmap, namespace
For all the method, I need to put the use 'app/Helpers/Languages' but I would like call just Languages::myFunction() without 'use' . Is it possible ?
I already the 'app/' folder in psr-4 so it will be load folder and my file, isn't it ?
If it's can help when in load a page without I've :
FatalErrorException Class 'App\Http\Controllers\Languages' not found
When I updated composer.json, I did't forgot composer dump-autoload
I don't think the problem you have is because the class is not being autoloaded, but rather because you try to use it the wrong way. Even with the alias you added, when using the class from within a namespace (like App\Http\Controllers) you have to either add an import statement:
use App\Helpers\Languages;
// or with the alias
use Languages;
Or specify the FQN when using it:
\App\Helpers\Languages::myFunction();
// or with the alias
\Languages::myFunction();
You can't really avoid this. What you could do, so you don't have to worry about namespaces: use helper functions without a class. Just like Laravel's helper functions. (route(), 'trans()', etc)
Okay so I have an project folder inside my Laravel app. named TLGD (the name if my site). Inside i created a form validation helper which is being used to take away unnecessary code form the controller.
here is the folder structure:
TGLD\Validation\Forms
and inside here I have my form helper classes
now in the controller just to test it out I was calling the classes by the use methd from php like so:
use TGLD\Validation\Forms\Login;
login being the class for the login validation
now thus works great so I tried to autoload the TGLD folder so I don't need to add the use line in every controller. Here is my composer.json file
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
],
"psr-4": {
"TGLD\\": "app/TGLD"
}
},
but when I autoload it it gives me the error that my login class doesn't exist which means the autoloader is not working. Is there a syntax error or am I missing something? I ran
composer dump-autoload -o
well any advice is helpful thank you in advance
What you want to do cannot be done.
You have to use the complete namespace somewhere to identify the class you want to use. You have several options to do this
Using the fully qualified name of the class with namespace like this: new \TGLD\Validation\Forms\Login().
Using a use clause that imports the named class into the current namespace for this file with use TGLD\Validation\Forms\Login; ... new Login();
Using a part of the namespace in the use, and use the rest in the class name: use TGLD\Validation\Forms; ... new Forms\Login();
After you have chosen the class name in one way or the other, PHP knows which class it needs, and then triggers the autoloading if the class is still unknown to PHP.
So you cannot affect the naming of classes with autoloading.
I'm running PHPUnit using a bootstrap file for autoloading classes (generated by composer).
All my tests load up classes just fine, but for two of my tests, I made a "base" test class which extends \PHPUnit\Framework\TestCase (similar to PHPUnit_Framework_TestCase before PHPUnit7), and then two test classes that extend the base class, similar structure to the following example code:
abstract class BaseTest extends \PHPUnit\Framework\TestCase
{
abstract function setUp();
protected function getCommonTestVariables()
{
// ...
}
protected function runCommonTests()
{
// ...
}
}
class BlahBlahTest extends BaseTest
{
public function setUp()
{
$variables=$this->getCommonTestVariables();
//etc...
}
public function testThings()
{
$this->runCommonTests();
}
}
Whenever I run this, PHPUnit gives an error:
Fatal error: Class 'BaseTest' not found in BlahBlahTest.php on line 13
I've checked filenames, locations, namespaces and everything seems to be in order. Any help would be appreciated to get to the bottom of this
I ran into the same problem and if you are not too familiar with the inner workings of both PHPUnit and Composer this can indeed seem perplexing.
PHPunit does not use use the Composer autoloader to find any of your test classes. It just scans any directory you give it and operates on one file at a time.
Hence it does not know about any other class than the one in the file it is currently operating on. That is where the bootstrap file comes into play.
If you want to use the Composer Autoloader to load other test classes, you need to tell it where it can find these test classes (and, optionally, in which namespace).
There are two ways to do this:
Add an autoload-dev section to your composer.json or
Add the test directory to the Composer Autoloader
Use autoload-dev
The autoload-dev sections allows you to define autoload rules for development purposes.
Quoting directly from the manual:
Classes needed to run the test suite should not be included in the
main autoload rules to avoid polluting the autoloader in production
and when other people use your package as a dependency.
Therefore, it is a good idea to rely on a dedicated path for your unit
tests and to add it within the autoload-dev section.
Example:
{
"autoload": {
"psr-4": { "MyLibrary\\": "src/" }
},
"autoload-dev": {
"psr-4": { "MyLibrary\\Tests\\": "tests/" }
}
}
Add to the Composer Autoloader
An alternative would be to get the Composer Autoloader and add your testing namespace (if you have any) and the directory where your tests live. How to do this, as described in the manual (at the bottom of the autoloading section in "Basic Usage") is :
$loader = require('/path/to/vendor/autoload.php');
$loader->add('Test\\', __DIR__ . '/Tests');
If your tests use namespaces that mirror the test directory and you still run into trouble, you can try omitting the prefix by replacing the first parameter ('Test\\') with ''.
If you want further insight into how all of this works you should take a look at the Composer ClassLoader class, especially the add() and findFile() methods.
For me the solution was much simpler.
I changed the capital letter of Test to test at the end of the file and the class name
BaseSomethingtest.php
<?php
namespace Something\Tests\Sub1\Sub2;
class BaseSomethingtest
{
}
I just put a word at the end of my base class. As far as it
didn't finish with Test, phpunit didn't call it
BaseSomethingTestCase.php
<?php
namespace Something\Tests\Sub1\Sub2;
class BaseSomethingTestCase
{
}
I'm not sure if you still need a solution, but this worked for me:
Non-testable base class extending PHPUnit_Framework_TestCase
In PHP 7.0+ extends PHPUnit_Framework_TestCasechanged to extends \PHPUnit\Framework\TestCase, try this one.