New default directory structure
- nAS
- Member | 277
Nette uses directory structure where all presenters and all templates are in separated folders. I heard that this is meant to be useful for projects where programmers and coders are in separated teams. From my experience templates and presenters are linked very strongly by parameters that are passed from presenter to template. No coder can create template without knowledge what parameters will be passed to template.
I propose to change directory structure in way that allows to have templates as close as possible to its presenter.
This structure has advantage that all presenter-related things can be in presenter's folder. If you have some component that is for one presenter only it can be in subdirectory “components” in presenter's folder. If you have system that builds stylesheets and javascripts, you can have folder “assets” in presenter's folder.
My second proposal is related to modules. They can be used with any directory structure because of RobotLoader. But in “Modules-Usage” example are used in not so good (in my opinion) way. By creating “XxxModule” in the same directory as presenters leads to having different order in every folder depends on alphabetical order.
I propose to create directory “modules” where all modules will be placed.
Suggested directory structure
|-app
| |-modules
| | |-Web
| | | |-presenters
| | | | |-Default
| | | | | |-templates
| | | | | | |-default.latte
| | | | | |-DefaultPresenter.php
| | | | |-Product
| | | | | |-templates
| | | | | | |-default.latte
| | | | | | |-edit.latte
| | | | | |-ProductPresenter.php
| | | |-templates
| | | | |-@layout.latte
| | |-Admin
| | | |-modules
| | | | |- (more modules)
| | | |-presenters
| | | | |-Default
| | | | | |-templates
| | | | | | |-default.latte
| | | | | |-DefaultPresenter.php
| | | |-templates
| | | | |-@layout.latte
| |-presenters
| | |-Base
| | | |-BasePresenter.php
| |-templates
| | |-@layout.latte
|- (www, logs, ...)
Implementation + back compatibility
This change can be done only by changing Presenter's formatTemplateFiles and formatLayoutTemplateFiles methods. Those methods should returns new and old paths, so there should be no BC break.
- Jan Tvrdík
- Nette guru | 2595
Love it!
More readable (in my opinion) ASCII art:
app
├── modules
│ ├── Web
│ │ ├── presenters
│ │ │ ├── Default
│ │ │ │ ├── templates
│ │ │ │ │ └── default.latte
│ │ │ │ └── DefaultPresenter.php
│ │ │ └── Product
│ │ │ ├── templates
│ │ │ │ ├── default.latte
│ │ │ │ └── edit.latte
│ │ │ └── ProductPresenter.php
│ │ └── templates
│ │ └── @layout.latte
│ └── Admin
│ ├── modules
│ │ └── (more modules)
│ ├── presenters
│ │ └── Default
│ │ ├── templates
│ │ │ └── default.latte
│ │ └── DefaultPresenter.php
│ └── templates
│ └── @layout.latte
├── presenters
│ └── Base
│ └── BasePresenter.php
└── templates
└── @layout.latte
- Šaman
- Member | 2661
I allready use this structure for presenters and components and it is IMHO far more well-arranged. I wait just for TemplateFactory to use same code both for components and presenters.
In case components and simple presenters i try this structure without /template dir. (One .php and few .latte files in same directory).
- romiix.org
- Member | 343
Šaman wrote:
In case components and simple presenters i try this structure without /template dir. (One .php and few .latte files in same directory).
I vote for this. Is it simplier and clearer.
- Vojtěch Dobeš
- Gold Partner | 1316
I am not big fan of this:
- more clicking through dirs
- duplication of presenter's name in dir & filename
But if this becomes new default with keeping the old structure working, I have no problem with it. But the current one seems to me consisting of less steps.
- castamir
- Member | 629
But if you want to join presenter and its templates, why not this way?
app
├── modules
│ ├── Web
│ │ ├── presenters
│ │ │ ├── Default
│ │ │ │ └── Presenter.php
│ │ │ │ └── default.latte
│ │ │ │ └── view.latte
│ │ │ └── Product
│ │ │ | └── Presenter.php
│ │ │ │ └── default.latte
│ │ │ │ └── edit.latte
│ │ └── templates
│ │ └── @layout.latte
│ └── Admin
│ ├── modules
│ │ └── (more modules)
│ ├── presenters
│ │ └── Default
│ │ ├── Presenter.php
│ │ └── default.latte
│ └── templates
│ └── @layout.latte
├── presenters
│ └── Base
│ └── BasePresenter.php
└── templates
└── @layout.latte
Last edited by castamir (2014-02-13 20:18)
- Šaman
- Member | 2661
vojtech.dobes wrote:
I am not big fan of this:
- more clicking through dirs
- duplication of presenter's name in dir & filename
But if this becomes new default with keeping the old structure working, I have no problem with it. But the current one seems to me consisting of less steps.
There are same count of clicking if you need find a latte file. And
presenter's name is duplicated too, in template dir.
But good on Nette is fact, that this can be changed very easy. Everyone get what
he can.
- David Grudl
- Nette Core | 8227
I like it!
Only I have a big problem with the name of the folder for layout. It should
be layouts/@layout.latte
(or whatever), but not
templates/@layout.latte
. When a new user, or especially experienced
user, will see folders presenters/
and templates/
in
app/
or module, he will expect, that templates are in
templates/
, but in fact they are in presenter/
.
Thousands of erroneous clicks on templates
folder! Thousands of
confused people! You will have blood on your hands! :-))
- nanuqcz
- Member | 822
What about ability to configure this in config.neon?
nette:
templatePathMask: %presenterDir%/<action>.latte
layoutTemplatePathMask: %presenterDir%/../../layouts/@<layout='layout'>.latte
Old (actual) behaviour can be configure like this:
nette:
templatePathMask: %presenterDir%/../../<presenter>/<action>.latte
layoutTemplatePathMask: %presenterDir%/../../templates/@<layout='layout'>.latte
But I still don't like presenters and templates in one folder :-)
Last edited by nanuqcz (2014-02-14 07:38)
- Honza Marek
- Member | 1664
I use this directory structure which I am really satisfied with:
app
|-- presenters
|-- FrontModule
| |-- Homepage
| | |-- HomepagePresenter.php
| | |-- default.latte
| |
| |-- Other
| | |-- OtherPresenter.php
| | |-- default.latte
| | |-- other.latte
| |
| |-- FrontPresenter.php
| |-- layout.latte
|
|-- AdminModule
|-- BasePresenter.php
- Honza Marek
- Member | 1664
nanuqcz wrote:
- What happens, when I want to have more themes in my application? Directory structure becomes messy.
There is always ability to change the defaults.
- Pavel Kouřil
- Member | 128
I like it, but I like Honza Marek's suggestion even more, because the folder “templates” seems a little bit useless. :)
- Filip Procházka
- Moderator | 4668
Honza Marek +1
@dg yesterday, you were talking about defaults, and that the default should be simple. Honza's proposal is the simplest and it could have fallback for searching in template directories that would be optional if you had more templates and wanned to organize them
- Jan Tvrdík
- Nette guru | 2595
The reason for having dedicated templates
directory for each
presenter is that it is expected that there will be other directories such as
components
or assets
.
@Filip Procházka: Did you notice that
@Honza Marek's suggestion is completely missing the
modules
directory?
- David Grudl
- Nette Core | 8227
nAS's solution has important benefit: there is no mess with modules names mixed with other directories, templates with presenter etc.
I tried yesterday to adapt some project to nAS's structure and discovered,
that sometimes is very nice to omit direcories presenters
and
templates/layouts
and put its content directly to module, as Honza
Marek suggests.
- nAS
- Member | 277
I don't like inconsistency in Honza Marek's solution. Once presenter is in its own folder (Homepage, Other) and once not (Front, Base). Additionally I don't see how to use nested modules. And last thing is that folder “presenters” contains modules. I see that very confusing.
I agree that sometimes it can be useful to have templates directly within presenter's folder so we can add that option. But solution with “template” folder is generally better because it allows to have other content (components, assets, …) so I'd like to see it as default.
- Filip Procházka
- Moderator | 4668
app/
|-- presenters/ # application controllers
|-- FrontModule/ # namespace
| |-- Homepage/ # namespace
| | |-- HomepagePresenter.php # class
| | |-- default.latte #related file
| |
| |-- Other/
| | |-- OtherPresenter.php
| | |-- templates/ # optional directory
| | | |-- default.latte
| | | |-- other.latte
| |
| |-- FrontPresenter.php # class i namespace
| |-- layout.latte
|
|-- AdminModule/
|-- BasePresenter.php # class in namespace
This is quite reasonable default structure and I would go slightly further for my personal usage becase I like to use namespaces
app/
|-- presenters/ # application controllers
|-- FilipBlog/ # namespace
| |-- FrontModule/ # namespace
| | |-- Homepage/ # namespace
| | | |-- HomepagePresenter.php # class
| | | |-- default.latte #related file
and why not just drop the clutter right away?
app/
|-- FilipBlog/ # namespace
| |-- FrontModule/ # namespace
| | |-- Homepage/ # namespace
| | | |-- HomepagePresenter.php # class
| | | |-- default.latte #related file
Neverless honza's proposal is the best for default structure (least overhead).
- Honza Marek
- Member | 1664
I don't like inconsistency in Honza Marek's solution.
I don't think it's inconsistent. BasePresenter and FrontPresenter are abstract classes and other presenters inherits them. So these classes are placed directly into module root folder.
Additionally I don't see how to use nested modules.
You can just put SomethingModule
folder into module root.
And last thing is that folder “presenters” contains modules.
This folder contains all presenter of all modules.
IMO it's better than your solution where “root module” presenters and templates are placed in different folders.
But solution with “template” folder is generally better because it allows to have other content (components, assets, …)
There is no problem with adding “controls” folder in my directory structure.
app
|-- presenters // or modules? or something else?
|-- FrontModule
| |-- controls
| | |-- Blabla
| | |-- BlablaControl.php
| | |-- BlablaControl.latte
| |
| |-- ForumModule
| | |-- ForumHomepage // presenters
| | |-- ...
| |
| |-- Homepage
| | |-- HomepagePresenter.php
| | |-- default.latte
| |
| |-- Other
| | |-- OtherPresenter.php
| | |-- default.latte
| | |-- other.latte
| |
| |-- FrontPresenter.php
| |-- layout.latte
|
|-- AdminModule
|-- BasePresenter.php
- danik
- Member | 56
Hi everybody,
I might be called a purist (occasionally even fascist) when it comes to nomenclature, but I'd venture to disagree with most suggestions presented here. Let's start with naming the requirements:
- Presenters and their associated templates should be as close to each other as possible, while maintaining readability and orientation in directory structure.
- Modules should be nestable.
- A reasonable amount of namespacing won't hurt.
- We also don't want to add any clutter; to the contrary, where possible we'd like to do away with unnecessary directories and/or naming repetition.
So the first question is: what is the “app” directory for? From my point of view it contains the application. I'm stating the obvious on purpose: it contains the whole application, which may consist of modules and/or presenters. Additionally we could think “module-specific components”. But there is another way of looking at the “app” folder: it may also be seen as the highest module in application hierarchy – it has all the signs of a module (can contain presenters and/or other modules).
Second: what does a presenter consist of? As I see it (and as is undoubtedly the point of this whole RFC) a presenter consists of its defining class and its associated templates. The presenter doesn't make any sense without them, nor do they without it.
So bearing all this in mind, I'd propose a structure along the following lines:
/App
/Web
/Home
/presenter.php
/templates
/default.latte
/About
/presenter.php
/templates
/default.latte
/templates
/@layout.latte
/Base.php
/Admin
/Dashboard
/presenter.php
/templates
/default.latte
/Settings
/presenter.php
/templates
/default.latte
/templates
/@layout.latte
/Base.php
/User
/presenter.php
/templates
/login.latte
/registration.latte
/Base.php
Now before you all start throwing stones ;-) my point is: how different a module really is from a namespace? How different is a module from an actual presenter? A module is basically just a named container for a section of the application which forms a logical unit and fulfills a specific purpose. A presenter might be seen as basically a named container for functionality (either provided by the presenter itself or by a component) which, again, forms a logical unit fulfilling a given purpose.
A presenter and its associated templates form an inseparable package. Now, if folders in the filesystem could somehow “be” scripts and at the same time still act as folders (containing other files) the presenter's folder wouldn't need to contain a “presenter.php” file; but since this is not possible on any filesystem that I'm aware of there is no other way to keep the presenter and its templates next to each other and still avoid repeating the presenter's name in file names. An abstract presenter, on the other hand, has no associated templates and therefore can be defined directly by a file bearing it's name (as is the case with Base.php throughout the example).
If we take the leap and proclaim the root level a namespace, then getting from the root to the home page presenter is the shortest possible path we can think of: App\Web\Home. Wait, no WebModule? No HomePresenter? But why, really? From the application's point of view only one thing is vital: that whatever it finds at the end of the chain is a non-abstract class implementing the IPresenter interface. If that is indeed the case, it is already a presenter, even without us stating it in it's name and again in it's defining file's name and again in the containing folder's name. A module's folder can contain templates, same as a presenter's folder: these could be any templates applicable to the whole module which would mostly mean layout templates, but not necessarily only them.
But how do I know what is a module and what is a presenter? I hear you ask. Well from the outside you don't, and that's precisely the point: from the outside, you don't care, it's just a logical block of functionality and unless I care about it's innards I simply don't care. As soon as I need to look into it, it is immediately clear from the presence (or absence) of the “presenter.php” file whether I'm looking at a module or a presenter.
It has the added bonus of beauty, when you imagine a very nested structure, like App\WebModule\ForumModule\CategoryModule\ManagementPresenter, shortened all the way down to App\Web\Forum\Category\Management. And that was just the namespace we cut down. I shudder to think how the original file path to the presenter would look.
Last edited by danik (2014-02-22 04:51)
- nanuqcz
- Member | 822
Danik: So, what will be the class name of this
App\Web\Forum\Category\Management
presenter (with namespace)? And
what about BasePresenter
of parent module (when I want it)?
Somethink like this?
namespace App\Web\Forum\Category\Management;
class Presenter extends \App\Web\Forum\Category\Base
{
...
}
- hacafrakus
- Member | 14
I like danik's suggestion, since I don't like the “Module” word in namespace or path. But the presenter file name should not be “presenter.php”, cause I can imagine how long I would search for the right “presenter.php” while having 3 presenter files opened. :)
I don't really think that structure suggested by Honza Marek is good (just my opinion) for 2 reasons:
- I wouldn't expect the directory of a module under “presenters” folder, IMHO that is confusing (we are trying to call a directory by it's content, aren't we?).
- I don't like the templates directly near the presenter files, it should be separated at least by subfolder (“templates”).
Anyone discovered any problems while covering the presenter class name by a namespace? I'm talking about this:
namespace App\Web;
class Articles { ... }
...
namespace App\Web\Articles;
class Comments { ... }
Last edited by hacafrakus (2014-02-22 19:39)
- ujovlado
- Member | 12
I'm big fan of modular directory structure.
Application without modules looks like module (app module):
app
|- presenters
|- templates
|- @layout.latte
|- components
Application with modules looks the same, but with modules directory. Each module has same structure as app module:
app
|- presenters
|- templates
|- @layout.latte
|- components
|- modules
|- Admin
|- presenters
|- templates
|- @layout.latte
|- components
- danik
- Member | 56
nanuqcz: no, not really. That's why the “presenter.php” file's name starts with a lowercase “p” – to indicate that the class it defines isn't called the same as the file, as is the convention. The actual presenter class would be what you took to be a namespace – App\Web\Forum\Category\Management. The file that defines this class should then obviously be app/Web/Forum/Category/Management.php – but since it then could not contain a subfolder like “templates”, you would need to create a folder of the same name next to it to hold such subfolders (as in app/Web/Forum/Category/Management/templates), which would mean the need to repeat the name of your presenter – and I'd like to avoid that. That's why the presenter class itself is defined in the (arguably artificial) “presenter.php” file. “Base” presenters (or any abstract presenters, for that matter) usually don't need other files than the one which defines them, so in their case the containing folder is redundant and the presenter can be defined in a file of the same name, such as app/Web/Forum/Category/Base.php.
I'm thinking of a presenter as a “package”, of sorts; not unlike apps on Mac OS – the apps in the /Applications folder are actually just more folders, only they happen to have the *.app extension and they have a standardized, “artificial” entry point (might be an executable with a specific name, or some kind of a manifest file, I'm not sure right now and I don't have an actual mac to check this on) – in the case of my proposed “presenter packages” that's “presenter.php”.
hacafrakus: that's a valid point… although some IDEs might solve this for us. I'm a huge fan and an ardent user of PhpStorm and if I have multiple files with the same name open at any point, PhpStorm will actually show the names of their containing folders in the tabs along with the file names, so I can differentiate between them quite easily (for instance Category/Base.php, Management/Base.php etc.). I don't know if that is the case with other IDEs (it must be years now since I last uninstalled Eclipse and NetBeans and finally switched over to PhpStorm). Anyone..?
I second both of the other two points you made – having a “modules” directory under a “presenters” directory is totally confusing and templates should definitely be in a subfolder imho.
ujovlado: I'm a big fan of modular directory structure too, I just don't like repeating myself ;-) and creating a module's directory structure following the pattern you propose means repeatedly creating a “presenters” and/or “modules” folder which imho is not necessary..
Last edited by danik (2014-02-23 04:17)
- David Grudl
- Nette Core | 8227
What about flatten-nested modules?
app
├── modules
│ ├── Web
│ │ ├── modules
│ │ └── Order
│ └── Admin
│ ├── modules
│ │ └── Order
as
app
├── modules
│ ├── Web
│ ├── Web.Order
│ ├── Admin
│ └── Admin.Order
- danik
- Member | 56
Šaman: I'm no expert on either PSR-0 or PSR-4, but from a quick glance at some articles I'd say that using either of these would necessarily lead to name duplication as both of these standards use the last part of the class name for the filename which defines the class. Therefore any additional data the class needs (templates, …) would need an additional subdirectory named after the class – and there you go, name duplication.
David Grudl: Flatten-nested modules the way you proposed them would be a direct contradiction to most of the requirements I personally have for the directory structure :-) They include the redundant “modules” directory and they require name repetition on quite a grand scale.. imagine one day needing to rename the “Admin” module to something else…
- danik
- Member | 56
Hi, checking back here. I've started using the structure I proposed here on a couple of projects I'm currently working on and long story short – it is a blessing. I'm now in the middle of rewriting all of my components to this very same folder / namespace structure. So I thought I'd share some first-hand experience :-)
1. Moving stuff around, importing presenters / components from older projects or refactoring names has never been easier. Ever. When I used the vanilla nette folder structure, usually I'd first move the presenter class, then I'd get a BadRequestException telling me Nette couldn't find the correct template file and only then I'd notice I forgot to move the appropriate templates/… directory to reflect the change. The way it is now the presenter package is truly a package in the fullest sense of the word – every file directly related to it is contained in the package. I cannot stress enough how much of a time- and nerve-saver this is.
2. There is no confusion whatsoever. Navigating the folder structure is totally intuitive, and PHPStorm rocks even more than I thought – if I have, say, two “default.latte” template files open at the same time, PHPStorm always finds a way to help me distinguish between them. For instance, the tab names could be “Home/…/default.latte” and “Products/…/default.latte” – it doesn't work just one level up the directory structure as I thought previously.
3. The depth of the structure is limitless and highly modular. Any module can contain other modules AND presenters; they can even share a name if that's needed (App\User can be both a presenter and a namespace in which the App\User\Account presenter resides). This allows for a “namespace default” presenter pattern if you do a little magic with the routes. (I'm sure that could be done with the current vanilla structure too, but this way the whole package stays always together in the same place, which is a huge plus..) (for me, anyway ;-) )
If anyone would like to try this pattern out, you'll need to do the following:
1. Instruct PresenterFactory to honor your namespacing convention. This is done in the application's config.neon by setting the following options:
nette:
application:
mapping:
*: App\*\*
Nette: NetteModule\*\*Presenter
2. Instruct your presenters to look for templates where they
should. This can be done for instance in an application-wide base
presenter by overriding the formatLayoutTemplateFiles()
and
formatTemplateFiles()
methods; my implementation is as follows:
<?php
/**
* Formats layout template file names.
* @return array
*/
public function formatLayoutTemplateFiles() {
$name = $this->getName();
$layout = $this->layout ? $this->layout : 'layout';
$dir = dirname($this->getReflection()->getFileName());
$dir = is_dir("$dir/templates") ? $dir : dirname($dir);
$list = array(
"$dir/templates/@$layout.latte",
"$dir/templates/@$layout.phtml",
);
do {
$dir = dirname($dir);
$list[] = "$dir/templates/@$layout.latte";
$list[] = "$dir/templates/@$layout.phtml";
} while ($dir && ($name = substr($name, 0, strrpos($name, ':'))));
return $list;
}
/**
* Formats view template file names.
* @return array
*/
public function formatTemplateFiles() {
$dir = dirname($this->getReflection()->getFileName());
$dir = is_dir("$dir/templates") ? $dir : dirname($dir);
return array(
"$dir/templates/$this->view.latte",
"$dir/templates/$this->view.phtml",
);
}
?>
Hope someone finds this useful :-)
- castamir
- Member | 629
Just for an inspiration… my current directory structure is as follows:
app/
├── config/
└── AppName/ ← serves as an application root namespace
├── Application/ ← only presenters and templates are inside
| ├── Admin/
| | ├── Homepage/ ← templates for :Admin:Homepage:*
| | | ├── @layout.latte
| | | └── default.latte
| | ├── Users/ ← submodule - in the same level as templates dirs
| | ├── @layout.latte
| | ├── BasePresenter.php
| | └── HomepagePresenter.php
| ├── Front/
| ├── @layout.latte ← layout for whole application
| └── BasePresenter.php ← base presenter for whole application
├── Auth/ ← components and services are completelly separated
├── Routing/ including namespaces
├── Storage/
...