Change laravel directory structure - php

atm i'm beginning to develop a big application and the current structure of laravel just doesn't fit what i had in thought. The controllers, models and views are all in seperate folders just bunched up and things could get messy when there's loads of them.
So I was hoping I could change the default way laravel loads it's controllers views and models. My approach would be something like this:
-App
--Content
---Login
----Controller
----Model
----View
----Js
---Home
----Controller
----Model
----View
----Js
--BaseContent
---BaseLayout
---BaseController
---BaseJS
So when the route is home the controller model view and javascript all get bundled in a folder instead of having all of it in one controller directory, model directory, view directory etc.
So my question is does someone know how I could change the way laravel load's it's dependency's? I'm kinda hoping for a configuration file I just can't seem to find.

I understand your thoughts. You want to group by feature.
It's possible. All you need are namespaces conform PSR-4. In composer.json you can link/specify the namespaces and paths, for example, you have in your controller this line:
namespace App\Http\Controllers;
In composer.json see the following fragment in autoload:
"psr-4": {
"App\\": "app/"
}
The namespace App refers to the directory app, and all classes with the namespace beginning with App\ will be autoloaded. So it's simple for your to change the directory structure.

Related

symfony4.3 adding custom folder with classes

In my default symfony4 structure I want to add lib folder, where I have additional classes. So something like this:
-bin
-config
-lib
- Importer.php
...(other files with classes)
-public
-src
- Controller
- TestController.php
- Entity
- Form
...
...
But I cannot figure out how to later use my files (i.e.: Importer.php).
Let's say Importer.php has a single class Importer() inside. If I try to use it from TestController.php I get:
Attempted to load class "Importer" from namespace "lib". Did you
forget a "use" statement for another namespace?
TestController.php has
use Importer;
specified on top (autodetected by PhpStorm). I also tried adding namespace in my Importer.php file, for example:
namespace lib;
and then in TestController:
use lib\Importer;
But it produces the same result.
Lastly after reading about services, I tried adding the file to config/services.yaml
lib\:
resource: '../lib/Importer.php'
Which gives the same result...
What to do, how to live?
First of all read about php namespaces.
Next read about the psr-4 standart.
Select a prefix for your folder, let's say Lib. Make sure that all files in the lib folder has a properly namespace. E.g. Importer class must be stored in the lib\Importer.php and must have the namespace Lib;, Items\Item class must be stored in the lib\Items\Item.php and must have the namespace Lib\Items\Item; and so on.
Your files are ready. Just need to inform Symfony about them.
Symfony uses composer's autoloader, so check composer's autoload section. Than add new folder for autoloading in composer.json:
"autoload": {
"psr-4": {
"App\\": "src/",
"Lib\\": "lib/"
}
},
It says that all classes in lib folder have their own separate files and Lib prefix in their namespace and other part of namespace is similar to directories structure.
Next you need to clear autoloader's cache. Run in console:
composer dump-autoload
And finally you can use your class:
use Lib\Importer;
$importer = new Importer;
Also you can add your files to autowire.

override symfony 3rd party bundle resource

Symfony 2.7.5
Problem
I'm trying to override a class file in a 3rd party vendor file so that I can extend the functionality a little. This file isn't part of a service, or a controller.
Rather confusingly (I'm not sure why this worked), I've over-ridden part of FOSUserBundle by creating the directory structure as follows:
src
│
│
└───FOS
│
│
├───Model
│ User.php
│ Group.php
│ ...
This has allowed me to change the visibility of some of the FOS user class members. And it allowed me to do with this without any other config. Not even a child-class set-up.
Tried so far
I've read this, but it only talks about basic resources.
I've also read this, but it seems to only work for controllers or anything in the Resources folder.
Ive tried setting up a child bundle, similar to the above link but to no avail.
I cant think of a way of successfully using inheritance in this instance to accomplish what I need to do. As the file in question isn't referred to outside of the vendor bundle itself.
Question(edited)
Is there a way that I could extend/override a bundle class file that lays in a directory structure such as this? I don't need to touch much of the bundle, but I really need to get at this file. This is an extract from APYDataGridBundle.
vendor
│
│
└───APY
│
│
├───datagrid-bundle
│
│
├───Grid
|
| .. grid.php <-- this file
You can do this by using Composer’s autoload feature.
Composer, as you might already know, will automatically load the PHP file containing a class whenever you first call that class. So you don’t have to use require statements all the time.
To achieve what you’re looking for, you can “trick” the autoloader into loading a different file whenever APY\DataGridBundle\Grid\Grid is called.
How to do that
In your composer.json there should be a section like this:
"autoload": {
"psr-4": {
"": "src/"
}
},
This will tell Composer that your classes are in the src/ directory. But since APYDataGridBundle already defined a more specific namespace path in their composer.json, the autoloader will never look at your files.
If you change the block like this:
"autoload": {
"psr-4": {
"": "src/"
},
"classmap": ["src/APY/DataGridBundle/Grid/Grid.php"]
},
Composer will analyze the file Grid.php and look for classes inside it. It will then create a class map so that whenever the class inside it is called, it will know which file to load before even checking the PSR-0 or PSR-4 namespace paths.
So basically, you’re telling it the path to the file at a higher priority so it gets loaded first.
Of course, you don’t even have to match the namespace with your directory structure, you could also do something like src/replacements/grid.php if that’s better for you. Just make sure that the namespace declaration inside the file is the right one.
Edit: After changing composer.json you have to execute composer dump-autoload so the new autoload files get generated based on the new config.
In general, you will only be able to override a class in a bundle in one of two cases:
If symfony has defined a generalized way to look for these classes so that you can override them just by putting a new class in a directory. This happens with controllers, for example.
If the bundle loads this class by using a parameter in its service definition. In this case you can override it by setting this parameter in your config file
In your case you are lucky and this bundle loads this class through a parameter defined in its services.xml file, so you can provide your own class by overriding this parameter in your config.yml file:
# app/config/config.yml
parameters:
grid.class: your own class, for example AppBundle/Grid/Grid
If in the future you find that you need to override a class and it cannot be done through one of these methods, you can always create your own fork of the bundle, though this is a pain and hard to maintain, so I would only recommend it if you find no other alternative

Laravel custom directory structure

I am attempting to create a sort of custom directory structure, my proposed structure is as follows
App/ - Contains all Laravel core code
Repo/ - Contains packages, each package contains Controllers, Views, Modals, Seeds and Migrations specific to that package
Is it possible via Composer or would it take a lot of core modification?
Controller routing in routes.php
Route::resource('account', '\Repo\Accounts\Accounts');
The first occurrence of accounts is the folder and the second being the class. I know I could write each directory seperetly then dump composer autoload, however when you have 30 seperate packages per app, it is a little time consuming. Am I missing something super straight forward?
This is possible with composer. Add inside of your composer.json:
"autoload": {
"classmap": [
// ...
],
"psr-4": {
"Repo\\" : "Repo"
}
},
Then you can use classes inside of the /Repo directory, and classes in there will reside in the \Repo namespace.

How to load my own code into Laravel? Differences between those ways?

I'm kind of confused on how to load my own code (classes or just regular functions) into a Laravel app. I've seen this done in several ways:
Creating a folder inside the app directory (for example: app/libs) and add app_path().'/libs' to start/global.php
Add it into composer.json's "require"
Add "psr-0" into composer.json's "autoload" and add there the files
Add a My\Custom\Service\Provider into app/config/app.php's 'providers' and the alias for the facade
What's the difference between them? Why and when should I use any of those ways? Should I load a class, several .php files or simply the folder? Maybe reference those 3 things at the same time?
EDIT:
These are my guesses:
Option 2 is just for packages
Option 3 if you want to load every class inside a custom namespace declared within the new created folder (don't get why the "psr-0" instead of just adding it to "classmap")
Option 1 is the same as option 3, just handled by Laravel instead of Composer
You can reference a folder and it will load every class found inside, or you can reference a certain file and it will load the class found inside
About option 4:
If you want to use the facade anywhere on your code, and that will need the namespace added into composer.json
EDIT 2:
If you add them to "classmap":
"classmap": [
"app/libs"
]
every class from any namespace within files inside the app/libs folder, will be loaded
If you add them to "psr-0":
"psr-0": {
"Libs": "app/"
}
it will load every class within the Libs namespace inside the app/libs folder
Still not sure why/when to use service providers and aliases.
EDIT 3:
"psr-0" if I want to load a namespace that follows a folder structure (it won't load a class within a subnamespace if it doesn't match the folder structure)
"classmap" for "random" classes, functions... sort of "the rest"
you can load your own code 2 (maybe 3) ways in laravel.
use composer
use ClassLoader
Manual include or require anywhere
Option 2 is just for packages
yes, you're right.
Option 1 is the same as option 3, just handled by Laravel instead of
Composer
yes, you're right.
Option 3 if you want to load every class inside a custom namespace
declared within the new created folder (don't get why the "psr-0"
instead of just adding it to "classmap")
some packages or classes adhere psr-0 standard, the rest is not. psr-0 option is mapping namespace to directory. the classmap is mapping
the namespace to certain directory or file and used for the class that is not adhere psr-0 standard.
You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4.
If you want to use the facade anywhere on your code, and that will
need the namespace added into composer.json
nope, instead, you have to add class alias for the facade in app/config/app.php
if your code is just file, not a class, then use composer autoload files
if your code is class but not adhere psr-0/4 standard, use composer autoload classmap or just add the containing directory to app/start/global.php.
otherwise, use composer autoload psr-0 or psr-4.
in Laravel 4,I add all of my class in "mylibrary" folder.
Then at app/start/global.php , I add app_path().'/mylibrary',
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/mylibrary',
));
Within mylibrary there is MyClass.php , within MyClass.php there is test_myfunction()
and at app/view/home.blade.php I add these code :
<?php
$FMyClass11 = new MyClass;
$just_test=($FMyClass1->test_myfunction());
?>
Hope it works for you. :)

Organizing Laravel and autoloading sub directories

I am wanting to structure my laravel app in a way that all of my code is under the src directory. My project structure would look something like the below. How would I do this where I can still call Route::get('accounting/item/{id}','AccountingItemController#getId')
I am wanting to avoid adding every module under src to the ClassLoader. Is there a way to tell the class loader to load all sub-directories under the parent directory src?
app
app/src
app/src/accounting
app/src/accounting/controllers
app/src/accounting/models
app/src/accounting/repos
app/src/accounting/interfaces
app/src/job
app/src/job/controllers
app/src/job/models
app/src/job/repos
app/src/job/interfaces
Yes, it's called PSR-0.
You should namespace all of your code. Typically you'll have a vendor name that you'll use a the top level namespace. Your application structure should then look something like this.
app/src/Vendor/Accounting/Controllers
app/src/Vendor/Job/Controllers
Your controllers will then be namespaced accordingly.
namespace Vendor\Accounting\Controllers;
And when using them in routes.
Route::get('accounting/item/{id}','Vendor\Accounting\Controllers\ItemController#getId');
Lastly, you can register your namespace with Composer in your composer.json.
"autoload": {
"psr-0": {
"Vendor": "app/src"
}
}
Of course, if you don't want that top level Vendor namespace you can remove it, but you'll need to register each component as PSR-0.
"autoload": {
"psr-0": {
"Accounting": "app/src",
"Job": "app/src",
}
}
Once done, run composer dump-autoload once and you should be able to add new controllers, models, libraries, etc. Just make sure the directory structure aligns with the namespacing of each file.
Do you have composer installed? You should use this:
composer dump-autoload
But you can could add directories to the Laravel's classloader. Check the reference here: http://laravel.com/api/class-Illuminate.Support.ClassLoader.html

Categories