Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Multiple sites utilizing the same application, loading configurations from the database.
  • Hey guys, good work on everything thus far. I'm curious as the recommended route about doing the following: I need to execute a model query right after bootstrapping time (always_loaded, and extremely early on). This query would hit a configuration table and extract the configurations for that site. In CodeIgniter, I've done the following:
    Added an autoloaded model
    Within that model, execute the required queries during __construct. Basically, multiple sites will be pulled from either the same, or seperate indexes, but all will utilize the same application folder. So configurations are unique based on the URL of the site, and executed accordingly. Thanks much.
  • I read over this, and some of the technical talk confuses me. But I think I want something similar. I want to host multiple sites with the same code. Both Fuel and the App would be the same, and used for all sites. The only thing different between sites would be the database and theme (images, css, layout). Right now, the only way I can think of to do this is have one Fuel, and a carbon copy of my App for each site, with the only change being database, and messing with view files to change the theme. That seems redundant, and a pain to update everyone's App to a new version after customizing each App differently. Basically what I want is to host something where people can get their own website (subdomain or domain), choose a theme so their site is unique, and pull the relevant database content. Imagine something like, yourname.wordpress.com. When I update the version of my App, I would like to replace one App folder, and have those updates apply to every site without interfering with which database the site uses, and what theme it's using. If anyone can give a general, newbie friendly outline, I'd be much appreciated.
  • If it's that simple, maybe do the following: Setup a global database containing all your config stuff, and a database per subdomain. Define these two profiles in your database config. Add some logic to it to determine the database name of the subdomain profile at runtime. Use a template class that deals with loading the correct page template from the selected theme (using info from your global database) including all css, and have your app controllers add views without markup to sections of that template.
  • When you say a global database for my config stuff, are you talking about Fuel's config variables, or my App specific config (like Bob's site uses 3 column theme and his database is abc123, John's site uses 2 column theme and his content database is xyz321)? And then in db.php, add logic to get the current hostname, and query the global database for it so we know which content (Bob's or John's) database/password we're gonna use, and then fill up Fuel:: PRODUCTION with the results? For template class, are you talking about Controller_Template? Like, public $template = 'template_bob_frontpage'; // or 'template_john_blogpost'? (I would get 'john' or 'bob' from before in db.php in a global variable, and it'd be like 'template_'.$tplname.'_blogpost') If that's what you mean, could I move these templates outside of APPPATH/views/, so they each have their own template folder? Maybe in their own public folder along with their css, img, js, etc? Thanks a lot for your guidance. I'm am kind of timid about this.
  • You're not limited to the databases pre-defined in the config file. I would use the fixed production database config for your app's system administration (indeed, including stuff about your customers and their configuration). Connect to that database and pull the info needed based on the detected hostname. Using that info, you can create a db config array in realtime, and create a second database instance for that client with it's own database. All code that needs to access customer data then uses that instance. You can do that setup in the _init() method of a specific class that you 'always load', or in a base controller that is extended by all of your controllers. When you're talking about theming in a customer website setup, you'll need separation between your theme template code (which generates the page layout for that page, the theme css, etc) and your module views, that are unique for each of your functions, and should not contain any markup other then classes and id's. It depends on your plans on how complex this is going to be. Are your customers allows to alter the layout? Can they move widgets around, or does the theme dictate fixed locations? How I've done it: My themes are modules, with a controller that deals with generating the page based on views (templates) in the module. I have a public/themes/themename structure for all theme public files, like images, css, etc. Every theme has a config controller dealing with the types of templates available, widget sections (header, body, sidebar, footer, etc) per template, etc, I have a Theme class that loads the theme controllers as drivers (so it acts like a generic frontend to the application controllers). All application code generate widgets (blocks of HTML), and use this class to store the output (either HTML, or a view object to be rendered later). This gets passed on the display controller in the selected theme. The class also contains a render method that calls the display controller to render the final page.
    // to get an idea (simplified!)
    
    \Theme::setup('themename'); // themename is the name of the theme module, from the site config
    
    \Theme::template('homepage'); // page template to use, from the site or page config
    
    // generate widget data from whatever code you all. In my case, 'data' can be a string, a view object, a
    // viewmodel object, or a request object (depending on what's defined in my page definition table)
    \Theme::widget('header', 'data'); 
    \Theme::widget('sidebar', 'data');
    \Theme::widget('content', 'data');
    \Theme::widget('footer', 'data');
    
    \Theme::render(); // output the page using the template and the stored widgets
    
    A page template then looks like this (extremely simplified):
    <html>
        <head>
           <!-- something here -->
        </head>
        <body>
            <div id="header">
                <?php echo $header; ?>
            </div>
            <div id="body">
                <div id="sidebar">
                    <?php echo $sidebar; ?>
                </div>
                <div id="content">
                    <?php echo $content; ?>
                </div>
            </div>
            <div id="footer">
                <?php echo $footer; ?>
            </div>
        </body>
    </html>
    
  • Have you tried it?
  • I'm asking what the best way to do it, to follow fuels specs. Basically, the "easiest" way that I would accomplish this, would be to call the model's function directly at the bottom of the app/bootstrap.php. However, that would be breaking the MVC, to my understanding. Another thought, is to make an application specific base controller that the entire application utilizes, and have the controller handle it. So, i'm asking what the recommended route of going about doing this?
  • Pre-loading happens in Fuel::init(), just after the environment has been setup. Add your class to the "always_load, classes" section of app/config/config.php, and put any initialisation code in a static method called _init(). This is because altough the class is loaded, no object is instantiated at that time, so __construct() will not be called. However, you don't have to make it this complicated, as you would have to with CodeIgniter. Unlike CodeIgniter, Fuel is fully HMVC capable, so controllers can call other controllers without problems. Simply create an app controller that takes care of your custom routing, and define a route in app/config/routes.php that routes all URI requests to this controller (basically only the root and 404 route). In the controller use the URI to determine what you load, and fire a new Request to load it. I do something similar in my ExiteCMS project. My bootstrap controller loads the theme to use, the theme template, the template section list, and the list of widgets per section from the database, and generates the page. My widgets are all module controllers returning a View object, which makes it a highly modular setup.
  • This is the code I've used within CI: http://pastie.org/2047580 - this was just added to the autoload configuration. So making an application controller that does the same thing as the code shown above is your recommended route? What about in scenerios that I would use Template and Rest as well? I would have to have 3 wrappers for it? Maybe a quick example of this with a bit more details would help me understand your method. Thanks again
  • Also, another reason the controller option seems like a bad decision in this scenerio, is that I will most likely have some tasks (cron jobs) that are going to use some of these configurations variables. So it would need to take place so that any class, model, task, etc, could all utilize these variables.
  • Hi Guys, The above is exactly what I have been looking for, and fuel is the framework I want to work with. The questions I wanted to ask were relating to the folder structure. If I want to run several sites from one core, where does that core sit relative to the sites files. Also, if I want to restrict certain modules use on specific sites, how is that managed? as from codeigniter I see that every controller is accessible from the address bar. Sorry if this is a bit late, but I hopefully look forward to your response.
  • In default installations, the core sites one level up from the website's docroot. On my servers, I have a structure that has all docroots in /data/www/virtual (and then a folder per virtual host). I have a folder called /data/fuel, in which I have folders for the different Fuel versions (like fuel_1_0, fuel_dev, etc). I use Fuel's recommended setup, so the docroot for fuel sites is actually configured in the virtualhost as /data/www/virtual/<sitename>/public. I just modify the index.php in public to point to the desired versions of 'core' and 'packages'. 'app' remains where it is, as it is website specific. This setup also allows me to quickly test a site with a different version of Fuel, I only have to change the path and the site is using a different core version. For URI access to modules, there are two options available. Either make sure in your routes that a URI request can not route to the module (either by a catch-all route, or by explictly routing the module to your 404 controller), or use the router() method in your module controllers, and redirect to your 404 page if it's a main request, .e. Request::active() == Request::main(). If you have modules in a shared location, and you want to make this decision on a per-website basis, routes are the only option.
  • So? It's a class, you can call it from anywhere. Same for configuration variables, if they're static, store them in a config file. If they're dynamic, use a static class. You can even put code in a config file if you so desire, as long as it returns an array, you'll be fine. As for your CI model, in Fuel you pre-load models using the always-load section of the config. Don't use defines, use static class methods or properties. Since you also include methods in here, just create a class called 'Core' in app/classes, copy your methods in, apply the above remarks, put your session/user init code in the static method Core::_init(), and add this to always load. And make everything static so you don't need in instance to call your methods or access the properties. You can then see this class as a sort of (I'll use the CI term) helper. But i suggest you forget all the bad habits, dirty tricks and workarounds you've gotten used when when using CodeIgniter, and start thinking the Fuel way, outside the box. You'll quickly find out that your apps will be simpler, more straitforward, more logical, less complicated, and faster.
  • I agree with you on old habits, but I'm having trouble figuring out a better method of doing this. The biggest problem, is that views will be determined based on your current site. A great example, would be that you have 15 sites that all share the same backend, however, things that are happening on the site are specific to the site (such as which views to render), as well as a lot of the models need to have information specific to which site is currently being viewed (such as the sites id, etc.) before they submit a query. Having this stored within the database is ideal, as everything can be edited by non-programmers through CRUD operations. If you have an approach you can highly recommend, I'll definitely look into it. For now, I'm doing the auto loaded class::_init(), which seems to do the job. But I'm always open to suggestions of better ways.
  • This is how my project, ExiteCMS works. It serves multiple sites from a single backend. All requests are routed to the bootstrap controller. It does a lookup in the sites table using the hostname. If found, it uses the URI segments to locate the page definition to load. Pages are defined in a tree structure, mimicking a real folder structure. Every page has some parameters (like title, keywords, etc) and is linked to a theme template which determines the page layout. A template defines sections in which widgets can be placed using drag-n-drop. Widgets in turn are produced by module controllers, and return a view (either as a view object, or as HTML resulting from a request object). The bootstrap then loads the template, passes all widgets to it, and renders the page.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion