I have an application in PHP that is a simplified MVC type structure. This application will be used in over a dozen sites run by my company and others. The structure consists of a controller file, a folder called application which contains the app classes, and a folder called site that contains site specific code such as templates. Periodically, we distribute a patcher that updates the controller and the application folder when we are distributing changes. As a result, clients can't really alter the core code in the application folder without losing those changes when the code is updated.
I tell you that so I can explain what the clients want - they want the ability to extend existing classes. Is there a design pattern that would allow this? Right now, I have given users the ability to replace entire classes:
spl_autoload_register('loadSiteClass');
spl_autoload_register('loadCoreClass');
This uses an autoloader that checks the site folder for a class before looking in the application folder for the class. I am hoping to find an alternative that would allow me to autodetect, load and use classes that extend existing classes instead of forcing the class to be completely replaced. Any suggestions would be greatly welcomed. Thanks in advance.
If it helps, there is also a site specific config file in the site folder, where the site admin can add config settings telling me that a class is being extended, but I'm still not sure how to use that information if it were provided.
The way codeigniter does it is have a mirror directory structure in the "client" / "application" folder of the system classes. Then you can make a file in the same place as the system class, then simply extend the system class and their loading class will look for the override first and then fallback.
Check here for some code examples: https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php#L277
Their documentation may be more help to understand their pattern.
I'm sure there are more ways to do this ... but generally convention over directory structure and simple PHP "extends" keyword are what makes sense to me.
Related
I have created a set of class files that helps to create the route configuration array. I, however, do not know where to put the source files. I browsed around a little and found some answers that suggested I put up the code in packagist and install it via composer, but my classes are relatively small. So, I wanted to ask if there is another way to do it. The files must be accessible in all the modules.
Your application code is organised into modules and lives in module/<Modulename>/src/. If the code is something you might want to reuse in other applications, then it might make more sense to have it as a standalone library that you install via. Composer.
You're code is accessibly through all the application if it is configured in the composer.json's autoload section.
Code structure in ZF is quite simple. You have your modules and in every module you have an src directory. This src directory should have its own namespace. And there you can place your custom route configurator under this namespace, like 'ModuleName\RouteConfigurator'.
But if you use this logic through multiple modules, I suggest you to create a separate module for it. In this case, after a long road, you may consider creating a separate composer package from it. But it's not necessary.
If you're not familiar with defining modules, please read the zend-modulemanager's documentation (https://docs.zendframework.com/zend-modulemanager/intro/)
Essentially, I'm looking to have a PHP development workflow that needs to be modular, but using a Single Page Application technology.
I understand it is recommended to separate the back-end from the front-end. Develop them separately. But is there a way to group all related code into one module (or folder), meaning all backend code with its own views presentation inside the same folder?
It's like MVC, but the "V" contains fragments of vuejs (or angular) files, which extends from a master file somewhere in your project.
For example
Assume we are building a modular CMS, where you can upload "plugins" (really, PHP modules), extending the CMS' functionality:
-project[root-folder]
----core[folder] # contains all infrastracture code, api routes, master view file, magic, etc.
----modules[folder] # uploadable modules goes here
--------User[folder] # sample module; follows the MVC pattern
------------Controllers[folder] # contains files, e.g. UserController.php
------------Models[folder] # contains User.php
------------views[folder] # where vue components is housed
----------------users/index.php # contains vue code
----------------users/create.php # etc...
----------------users/js/user.js
----------------users/css/user.css
--------Blog[folder] # another module
----index.php # the master view or just the bootstrap file
----gulpfile.js
Then inside the core/ folder, there is a master layout that binds all views together.
Will a folder structure like this be viable?
Obvious problem there is you can't use .vue files (as that would mean, every time you upload a new module, you need to run gulp or re-compile).
Hoping for your feedback. Thanks.
This question will strike a lot of folk as bizarre and twisted. That's the reaction I got when I asked it in the context of .net mvc. I'm with you 100%.
I'm too new to js frontend development (and too ignorant of PHP) to have much advice. It's going to be tricky. Ajax calls to PHP code will need to go to paths below the src directory. But then you want to stop your frontend resources being served from these same paths. Both PHP and gulp will want to use file paths for urls, but at least for Gulp this can be controlled.
I'll follow this with interest. My ambition is to keep in the same folder things you're likely to want to delete together, and for those things to be able to call each other with short, relative paths. The ideal would be to be able to specify the module route independently of the path on disk, and to have this route work for both frontend bundled resources and services. Good luck !
I came across this question whilst searching for an approach for exactly the same problem. I'm building a "platform" rather than an application with a plugin system along the lines of Wordpress. I have the additional issue of the platform itself being a 'multitenancy' environment, too - so any plugins cannot interfere with the core "Dashboard" that holds these things together.
So; posting for a few reasons, two years on...
Did you get anywhere and would you care to share any thoughts?
I came across a quite extensive article for PHP Phalcon that has certainly given me a few ideas. Sharing incase it helps you/others:
https://blog.antsand.com/singlepost/index/5619/How-to-integrate-php-(Phalcon)-and-Vue.js-components
There's a line buried in the series that says "As a rule of thumb. Structure your code, based on the application and NOT on the programming language and frameworks." I'm not sure how wise or not this is, but it certainly gave me something to crack on with.
So right now, I have a module folder a bit like:
/mymodule
/Controller
/Model/
/Template
thing.vue
/Assets
/js
/css
MyModule.php
Assets are handled via a framework route (i.e, /assets/{path:.*} )
Templates are handled via the (PHP) module install script to make sure webpack knows where they live.
Still at proof-of-concept stage but rightly or wrongly, it seems to work well enough!
What is the best way to create a single page module for Yii2?
For example using Ember, I will have index.html and assets folder to publish.
I see two ways, one would be to just put the application under web accessible folder, it will work fine.
But what if i want to check access to the application using existing RBAC?
Another way would be to create a module and in default controller have something like
return $this->renderFile('#path/to/index.html');
And load all assets with Asset Bundle.
The problem with this approach is that i will not know the folder where assets will be loaded (it can be solved with afterCopy callback or something, but all this doesn't look nice at all).
Please advise.
Certainly it is a personal choice technique, since control RBAC is manageable level action and does not pose any problem. Once the controller is easy applicarre your organization's access control using a suitable configuration of the Access Control filter.
Alternatively, the fact of creating a module appropriately for these purposes makes it all the better organized and, precisely, modular, beyond the greater complexity in the creation of the various parts in play (module, asset, cofig / main.php) yii2 handles very well and automatically the assets and necessariio not know a priori in the name of the folder where I finish the specific assets (Yii2 find what they need).
However if this is not a 'module' with reusable application characteristics I would opt for the first solution
In every large application there is an ADMIN section.
In such cases, when not using ZF, I usually put all the admin stuff in a separate directory with extra security measures (like adding .htaccess based authentication and/or a second login etc). This also makes it pretty obvious in the file tree what file is what.
How can I achieve the same design in ZF? Or are there any best practices to create an admin section?
Should I do it in the router level (if there is "admin" in the url, then I use a different index.php/ bootstrap file....)
I guess the simplest was just using a controller for all the admin stuff, but I have too much of that. So I have several admin controllers side by side with the regular app controllers. It makes a mess in my controllers directory - which controller is admin and which is not?
I've done it as a module. In addition to the module link provided by Brett Bender see section 12.3.2.2 in the link I provided.
I generally create a separate "application" folder - complete with its own controller and view directory as well as a public directory for static content - for the entire administration system. The Administration usually has different requirements for key things such as access management, and might differ from the actual application in numerous other ways. Therefore I think it's a good idea to separate the source code entirely. Some of the source code can still be common, though. Examples include library folders and database models.
This approach also gives you larger flexibility when deciding where the admin utility should be available. You could use the apache alias directice to put it in a sub directory on the same domain, or put it on a separate vhost. It's all up to you.
You should check out using modules with ZF. You can have a default module to contain non-admin stuff, and an admin module to contain everything administrative. Using a default module will not change your current URLs and the admin module URLs will look like server.com/admin/controllername/actionname/params. This will solve your controllers all being in the same place and getting cluttered. Also, you can subclass Zend_Controller_Action and make a Master_Controller in your models to keep shared functionality. Then just make an Admin_Controller that extends the master controller for shared administrative functionality and have every controller in your admin module subclass that. You can use a similar structure to organize shared non-admin functionality in your other module(s).
Zend Framework - modular directory structure
What is the best way to integrate an external script into the Zend Framework? Let me explain because I may be asking this the wrong way. I have a script that downloads and parses an XML file. This script, which runs as a daily cron job, needs to dump its data into the database.
I am using Zend Framework for the site which uses this script and it seems to me that it would be best to use my subclassed model of Zend_Db_Abstract to do the adding and updating of the database. How does one go about doing this? Does my script go in the library next to the Zend Components (i.e. library/Mine/Xmlparse.php) and thus have access to the various ZF components? Do I simply need to include the correct model files and the Zend DB component in the file itself? What is the best way to handle this sort of integration?
Yes, you should put your own classes that maybe inherit Zend Framework classes or add further classes into your own folder next to the Zend Framework folder in library.
When you have Zend_Loader s auto-loading enabled, the class names will automatically map to the class you created, e.g.:
My_Db_Abstract will map to My/Db/Abstract.php .
In your library directory you should have your own library next to the Zend library folder. Whatever you call it (Mylib, Project, ...) you should include it into the Zend Autoloader and that's done as follows:
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Project_');
$loader->setFallbackAutoloader(true);
if ($configSection == 'development')
{
$loader->suppressNotFoundWarnings(false);
}
In order for you library to integrate nicely with ZF and the Autoloader you should stick to the ZF naming conventions. This means two things:
if you extend an existing ZF class, replicate the ZF folder structure so that your file has the same path and name except for the library name. E.g. /library/Zend/Db/Abstract.php => /library/Project/Db/Abstract.php.
if you write your own classes, still stick to the ZF naming conventions for the autoloader to find them.
I just came across something that may be germane to this question. This IBM developerWorks article.
The author recommends simply creating a scripts folder in the ZF hierarchy and the using it as one normally would within ZF (though he does set the ini path and call autoload). Is it that simple? Does simply being in the hierarchy of the framework and including the path and autoloader grant your script access to all of the goodies?
I'm not 100% sure what you're trying to ask but I will try to help. If at any point you add a reference to "/path/to/zend/framework" into your php include path then you have in essence enabled the Zend Framework. From there if you do:
require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();
Then at any point in your script you can pretty much just create new Zend Framework objects and Zend_Loader will handle the rest.
One of the big things about the Zend Framework though is not forcing you to do things a certain way. That's why sometimes there are several ways to accomplish the same thing. So, if you feel you need to make your script use the Zend Framework just for the sake of doing so this is not really necessary. But if you think it may improve your script in some way then go for it.
I usually put custom stuff that I think could be used across projects in a custom folder in the library. So I have a library/Ak33m folder that has scripts that may be outside of the framework.
As a ZF noob myself, I think I understand some of what the OP is trying to figure out. So, I'll just explain a bit of what I understand in the hope that it is helpful either to the OP (or more likely, to a future reader, since the original question is so old and I imagine that OP is now a ZF guru).
I understand that ZF claims to be largely "use at will", so that you need no buy into an entire structure, like the Zend_Application, the Zend_Bootstrap class, the entire MVC approach, etc.
Further, I understand conventions for class naming and file locations that enable easy autoloading. Ex: class App_Model_User resides in a folder App/Model/User.php
I think what can be potentially confusing is that in the script context, where you have not yet
done the .htaccess magic that pushes all request to public/index.php
set your APPLICATION_PATH and include paths in public/index.php
created your Application or Bootstrap object tied to a config file
it can be a little bit unclear how best to avail yourself of most of the ZF goodness we get in that context and want in another context.
I guess my answer to the original question would be that the usual entry point sequence of
http request -> .htaccess -> index.php -> config
sets up much of our environment for us, we would need to duplicate some of that for different entry path.
So, for your script, my first instinct would be to create a common include file that mirrors much of what happens in index.php - set the include paths, the APPLICATION_PATH, instantiates and calls a bootstrap, and then does your script-specific processing.
Even better, it might be desirable to create a single entry point for all your scripts, like we do in the http/web context. Extend Zend_Application for your own script purposes so that $application->run(); no longer starts up the MVC router-controller-dispatch processing, but rather does your own stuff. In that way, this single script entry point would look almost identical to the web entry point, the only difference being which application object gets instantiated. Then pass the name of your desired Application class as a command line parameter to the script.
But here I confess to being less confident and just throwing out ideas.
Hope all this helps someone. It actually helped me to write it all down. Thanks and cheers!
Update 2009-09-29: Just ran across this article: Using Zend Framework from the Command Line
Update 2009-11-20: And another article: Cron jobs in Zend Framework | GS Design
Update 2010-02-25: Easy command line scripts with Zend Application - David Caunt