PhileCMS / Phile

A flat file CMS with a swappable parser and template engine.
https://philecms.github.io/
Other
258 stars 48 forks source link

2.0 Proposal #299

Open james2doyle opened 8 years ago

james2doyle commented 8 years ago

Phile 2.0

Lately I have been using Laravel and Slim and have noticed some nice things we can steal. It has been a while since I used Phile, but I have been using it for the past couple of weeks and noticed some of the missing or awkward choices.

This is my pitch for 2.0. This is simply a proposal that is open for discussion, not a demand or order for a particular direction.

Use default composer dir

Right now we have a custom vendor setup as /lib/vendor. I think this should be removed and just use the default /vendor.

All things composer

Move the Phile core into a composer package, and use a composer create-project command to generate a skeleton app that has everything setup.

This would remove the need to manually set the encryptionKey or do a setupCheck. This could even be interactive like composer init.

All plugins in composer

Move all the plugins onto packagist. Plugins are installed into /vendor using composer install/require.

Then we use something like the service provider in Laravel to load plugins by their class name.

For example:

$config['plugins']['phile\\phpFastCache'] = ['active' => true];
$config['plugins']['phile\\simpleFileDataPersistence'] = ['active' => true];
$config['plugins']['phile\\filterByKey'] = ['active' => false];
$config['plugins']['warpaintmedia\\twitterPlugin'] = ['active' => true];

Would become something like:

$config['plugins'] = [
    Phile\Plugin\PhpFastCache::class,
    Phile\Plugin\SimpleFileDataPersistence::class,
    // Phile\Plugin\FilterByKey::class,
    WarpaintMedia\Phile\TwitterPlugin::class,
    // ...
];

To disable a plugin, simply remove it from the list or comment it out. I describe plugin config in the next section.

Remove default_config and config

Remove both config files. Add a /config folder and load all files inside it.

Then we can have our plugin configs in that folder, but also split up by name.

Any default Phile config stuff would be in the Phile Core package.

Plugins have routes

Add the ability to set a route for the plugin to be reached at.

This means a plugin could be used almost like a controller. Useful for AJAX/Form submission stuff.

Pages as a collection

The pages array or class should instead be a Collection.

This allows easy filtering, sorting, reducing, and searching, but as part of the Pages object. This makes manipulating the pages array in a plugin (but also in Core) much easier.

Add a /public folder

Instead of having a /protected folder, we should just have a /public folder. Everything else can be locked down.

This can be used to store uploads or arbitrary things that don't belong in /content or /themes.

Helper functions in templates

These would be really simple to add in Twig.


In the end, I think these changes would make Phile much nicer. It may be a little more advanced, but I think the benefits outweight the downsides.

Anyone have any comments on this?

kicken commented 8 years ago

Then we use something like the service provider in Laravel to load plugins by their class name.

I'd prefer the approach Symfony uses with it's bundles. Rather than a list of class names, you instantiate a new instance of the class and pass that. This would allow the end user a little more control over how a plugin is instantiated if necessary, but remain simple to use if not.

$config['plugins'] = [
    new Phile\Plugin\PhpFastCache,
    new Phile\Plugin\SimpleFileDataPersistence,
    // new Phile\Plugin\FilterByKey,
    new WarpaintMedia\Phile\TwitterPlugin,
   // ...
];

Any object or data references that need to be passed to the plugin can be done so via setter methods which would be defined on an interface that a plugin implements.

Instead of having a /protected folder, we should just have a /public folder. Everything else can be locked down.

This can be used to store uploads or arbitrary things that don't belong in /content or /themes.

I'm of the opinion that the /content folder should essentially be a public folder. I personally find it much more convenient to store any assets related to a particular page within the same directory as the page's markdown file. Having to store such assets in a separate folder would be a hassle.

My preference would be to treat /content as public, but have requests for markdown files intercepted by Phile for rendering.


Everything else sounds good to me. Having a skeleton app which has phile as a requirement for people to use with create-project is a good idea and would resolve #298. A simplified and modular configuration would certainly be helpful for plugins.

james2doyle commented 8 years ago

Rather than a list of class names, you instantiate a new instance of the class and pass that. This would allow the end user a little more control over how a plugin is instantiated

This sounds interesting. Seems a little more advanced than the class as a string. Is there a case where people would start passing things to constructors? If yes, the benefit of more control seems a little more noisy.

Is there any case where you would need access to a constructor in the config?

I'm of the opinion that the /content folder should essentially be a public folder.

Except a public folder would have things like the main index.php file, the .htaccess or webconfig file, also the favicon and maybe a robots.txt file. These would never be in the content folder since the server doesn't treat that as the root.

kicken commented 8 years ago

Is there a case where people would start passing things to constructors?

Most likely not. The only potential use case I could come up with would be to to re-use a plugin with an alternate configuration by passing in a key name or something. 99% of the time I'd expect the constructor would be unused though.

However it doesn't seem more noisy to me. From an end user perspective the only difference is using new \Example\Class vs \Example\Class::class or '\Example\Class'

From a developer perspective their plugin would just have to extend an AbstractPlugin class to gain access to Phile resources. In my experience using new \Example\Class works better with editor auto-complete and refactoring tools. \Example\Class::class should work ok, but an actual string usually fails.

Except a public folder would have things like the main index.php file, the .htaccess or webconfig file, also the favicon and maybe a robots.txt file.

I don't really see any issue with mixing those in with the content markdown files. Phile should only be concerned with requests to .md files, anything else would be served as is. Someone potentially loading a .md file directly doesn't strike me as an issue. With proper configuration, it shouldn't happen anyway.

james2doyle commented 8 years ago

I think merging a content folder with a public folder would just be messy. I screwed up the lib folder by adding cache in there. In hindsight, it makes no sense, but I thought I was just putting similar things together.

Having server-related files in the markdown content folder just seems like a code-smell. Non .md files will then need to be ignored when filtering through the folder contents. Seems like unnecessary pollution to add to the folder. I would expect that the additional files would impact performance for larger sites.

For the new up of plugins in an array, I would want to avoid "functionality" in a config file. That being said, I can imagine a case where you would want to have 2 of the same plugin, but would want them differentiated in some way. Not sure how that would work without the new up class and adding arguments to the constructor. So maybe that is a good solution!

Frodox commented 8 years ago

Remove both config files. Add a /config folder and load all files inside it.

And in which priority they will be loaded? So there should be smth like

or smth like that.

Add a /public folder Helper functions in templates +1

kicken commented 8 years ago

I put some work toward the ideas presented here, mainly splitting the project into a separate core and skeleton app. I'd like to ask for opinions before doing too much more work.

I've created two branches to work with, core-split and skeleton-split. One of these would ultimately be converted into it's own repository. I went the route of changing the core to phile-cms/phile-core and leaving the skeleton app as the current name.

I also added a composer script to handle the setup after a composer create-project call. It will ask for basic parameters and generate the config.php and also the cache directories.

Any input is welcome. If the direction looks good I can continue trying to make improvements. Otherwise it could be scrapped and a new approach tried.

Schlaefer commented 6 years ago

While way to late for the party here are my thoughts working with the code at the moment:

Right now we have a custom vendor setup as /lib/vendor. I think this should be removed and just use the default /vendor.

Don't see an issue with that. But personally I don't mind lib/vendor, it makes manual updating the core easy: "just copy lib/".

Move the Phile core into a composer package, and use a composer create-project command to generate a skeleton app that has everything setup.

Don't see an issue with that.

This would remove the need to manually set the encryptionKey or do a setupCheck. This could even be interactive like composer init.

If there's a zip download which runs without composer - which I feel strongly about - there's a need for a PHP setup implementation.

Move all the plugins onto packagist. Plugins are installed into /vendor using composer install/require.

It's a PITA to develop in that setup (dev-setup, push to all those different repositories, keep versions strings in order, …). Theoretically yes, practically not a fan.

Would become something like:

This could be done nonetheless.

Remove default_config and config

The config situation could be improved, but I don't see a benefit of having half a dozen of config one-liner files. As @Frodox mentioned other questions arise: Is the file order important? Does plugin loading need to reflect the file order? Is there a naming convention so a config matches a plugin? This could be become complicated fast without providing real world benefits.

Plugins have routes

Plugins are already able to do that? I have to see a concrete implementation for an opinion.

Add a /public folder

Sounds like the right thing to do, but I'm rather sceptical again. This would mean you can't serve assets out of plugin-ins? Are additional conventions and/or moving files on plugin de-/installation required? Not a fan if true.

Helper functions in templates

This sounds somewhat complicated to do if the core should stay template-engine agnostic. Need to see an implementation.


Here's is my 2.0 wishlist:

Maybe: