Symfony 1.0 - Extend sfRouting - php

Anyone know if the following 'class' entry in routing.yml is possible in SF1.0? I tried to add it and override some methods like getInstance() and getCurrentRouteName(), but they never get called upon, even though I am making calls to them manually.
checkout_landing:
class: CustomRoute # Can I do this in SF1.0?
url: /checkout/landing/:k/*
param: { module: sharedCheckout, action: landing }
We have implemented this 'per-route' custom class configuration in SF1.2, but it doesn't seem to be working for SF1.0. I suspect for SF1.0 I will have to add a custom class entry to the factories.yml file which will affect all routes.
Bonus question: Anyone able to emulate the 'extra_parameters_as_query_string' in SF1.0? Right now, with the above url entry, and GET params are converted to pseduo sub-dirs, for example a querystring like:
$params = array('foo' => 'bar', 'pet' => 'dog');
$url = sprintf('#checkout_landing?%s', http_build_query($params));
// Looks like:
http://example.com/checkout/landing/foo/bar/cat/dog
// I need it to look like
http://example.com/checkout/landing?foo=bar&pet=dog

As you suspect, neither of those things is possible in sf1.0 without either making the compromise you suggest for a custom extension of sfRouting (in factories.yml), or adding the functionality of sf1.2+ for the extra_parameters_as_query_string.
I would suggest the easiest option for you is to upgrade to the last stable version of sf1.3 (sf1.3.11) and using the bundled sf10CompatPlugin to help you emulate the sf1.0 features you use in the existing app, while adding the sf1.2+ features you desire from the sf1.3 core.
There are very few compatibility errors from doing this, and I have used it myself on dozens of projects without any hitches.

I browsed the compiled cached code for routes, and sure enough in SF1.0 there are no custom object references based on 'Class' entries in the yaml file. However when I view compiled cache code for routes generated in SF1.4, the custom objects are available.
As upgrading is not an option, I opted to generate the urls the old fashioned way, manually.

Related

Codeigniter HMVC asset managment

I am trying to give a shot to HMVC in Codeigniter. Here is my folder structure.
-ROOT
--APPLICATION
---MODULES
----Module_Email
-----Controllers
-----Models
-----Views
-----Assets
------JS
------CSS
------IMG
To render the Module i have to use
Module::run('Module_Email');
This method will output the rendered output, an example is given below
<script type="text/javascript" src="PATH/TO/EMAIL_MODULE/JS/JS_FILE.JS"></script>
<div data-module-name="Module_Email" class="Email_wrapper">
//RENDERED HTML CONTENT
</div>
Now here my problem start. Normally i would like to put all my resources to header. So when i call any module, its dependence need to be added in header instead of from where its get called.
I searched a lot but i couldn't find any good methods.
Please help.
Update
Currently i have a function on my header called get_assets() which will output predefined resources to header. But i cant say which modules is going to use in pages, so the system need to check which modules are used in this page, and if its used then its dependencies need to be added on header.
Seems like your main problem then is trying to figure out what modules were used.
Unfortunately as far as I can tell with the default Wiredesignz modular extension there is no way to access the module name unless you write some sort of hack to get at that data. The module being used is stored in the protected variable $module in the MX_Router class, however, there is no public method to allow you to get access to it. So your only choice would be to extend the class and create a public function.
Alternatively you could use a forked version of Wiredesignz implementation which I did which provides numerous other features including a public function to get at the $module variable. Using the forked version I wrote you could then use code such as this:
<?php $module_name = $this->router->fetch_module(); ?>
However, that will only record the last module you loaded, so you would still need to do work to store all the modules, and then have your function use this information to determine what assets to load. If I were doing something like you I would probably fork my version and then create an additional data structure to store every module that was loaded that you could then later get access to.
I don't think this is exactly what you were hoping for, but might be something to get you on the right track to finding a solution.
I added an array to the Module class to store the assets and two functions to store/retrieve the items. Here is the source (updated Modules.php)
# Register your assets
public static function register_asset( $asset )
{
if( in_array($asset,self::$assets) === FALSE )
{
self::$assets[] = $asset;
}
}
public static function assets()
{
return self::$assets;
}
and now you can register your assets like this inside your module
Modules::register_asset('myslider.js');
You can retrieve all your assets using
Modules:assets();
Which will return an array of assets that can be processed depending up on the situation.

Constants in Kohana

I've used codeigniter in the past but on my current project I'm making the switch to Kohana. What is the best practice on constants?
In codeigniter there is the actual constants.php, but going through Kohana's source I'm not seeing something similar.
Never used kohana, but after a quick googling I find that you can use the config API to create your own config that will house the constants you need.
This thread suggests that if you are storing database sensitive items, to place them in the database.php config, etc.. making them relative to the type of data they are storing.
I'm familiar with Kohana, but not CI so much, so I'm guessing a bit to what you mean by 'constants.' I believe the closest thing to this is indeed Kohana's config API. So, if you wanted to make templates aware of some site-wide constant like your site name, that's a great thing to use the config API for.
To accomplish this, you'll need to create a config file under your /config folder, probably in the /application directory. What you call it isn't very important, but since it contains site information, let's call it site.php.
To quickly get going, here is what you'll want to have in that file:
<?php defined('SYSPATH') or die('No direct script access.');
return array(
// Your site name!
'name' => 'Oh me, Oh my',
);
Now, you can bring this in to a template by doing something like:
A better way to do this (using dumb templating) would be to assign this as a template variable in your Controller. So, assuming you have some default controller set up, the code would be:
public function action_index() {
$this->template->site_name = Kohana::config('site.name');
}
And then your template would have something like this:
<title><?php echo $site_name; ?></title>
Kohana's config API is interesting because it is hierarchical, meaning you can override and merge new configuration values on top of existing config structures. When you call Kohana::config('site.name'), the engine looks through all the config files named site.php, runs all of those config files and merges the results in to an array. The application-level config files will overwrite modules, which will overwrite system, etc... Then, based on that result array, Kohana will attempt to find the 'name' key and return it.
Assuming you want global constants...the following worked well for me.
application/config/constants.php:
define('MY_COOL_CONSTANT', 'foo');
return array();
index.php:
Kohana::$config->load('constants');
MY_COOL_CONSTANT should then be available globally.

Can I have a default controller called if the called controller doesn't exist?

I'm trying to learn more about the codeigniter framework by porting an existing website to it -- something that's not too complex, or so I thought.
Currently the site is replicated for its users and presents personalized data based on the url, for example, Joe might have his site at:
www.example.com/joe
www.example.com/joe/random-page.php
And you'd replace "joe" with any given user name. The URLs need to be structured this way: /joe/ isnt FOR joe, its for joe's visitors, so I can't rely on a user login or method of this sort. I could switch to joe.example.com but would rather not.
Is there a way I can make this play nice with Code Igniter?
Currently, it would want to call the joe controller. My initial thought is trying to find a way to have a default controller called when a controller doesn't exist, but if some CI pros have advice on a different, better way to handle this, it would be great.
Upgrade to CodeIgniter 2.0 and use $route['404_override'] = 'controller'; or install Modular Extensions which does the same thing, but for now they use $route['404'] instead.
There are a number of different ways to go about this. Just be warned, both of these solutions require you to edit CI's core files. That means you can't upgrade without breaking these edits. Unfortunately hooks do not suitably address this issue.
The easy way:
line 188-195 in system/vodeigniter/CodeIgniter.php handle the logic for what happens when a controller is not found.
The harder but better way:
There is a hook (http://codeigniter.com/user_guide/general/hooks.html)
pre_controller
But this will not work! The reason is that this is called after the controller has been determined, but before anything is actually executed. In other words, it is too late. The next earlier one
pre_system
is in fact too early, because routing has not been done and anything you do the routing will get overwritten.
So I needed the first controller to look the same, yet end up calling a different controller. The reason was that the page was accessed in a hierarchical way, so that it would be the subsection of a subsection and so on.
What I did was add on line 43 of system/libraries/Controller.php
$this->_ci_initialize();
Basically I had it autoload the libraries BEFORE the controller was called, because I was finding that the libraries were not loaded before the controller was called and I needed it to be done so because I needed to check user access authentication and hook directly into the routing itself.
After I did that, I extended one of the native core libraries that were autoloaded (in this case session, for applicaiton specific reasons) and then executed the rerouting.
$RTR = & load_class( 'Router' );
$this->URI = & load_class( 'URI' );
$this->URI->_fetch_uri_string();
I called this code in the start, then put my logic afterwards. This is a sample of what my rerouting logic looks like
if ( $this->segment( 1 ) == 'institute' )
{
if ( ! in_array( $this->segment( 3 ), $course ) )
{
$RTR->set_class( 'courseClass' );
$RTR->set_method( 'index' );
if ( ! $this->segment( 4 ) )
{
$RTR->set_class( 'course' );
$RTR->set_method( 'index' );
}
else
{
$RTR->set_class( 'course' );
$RTR->set_method( $this->segment( 3 ) );
}
}
The original is much longer. I probably should consider writing some sort of plugin or superior way to handle the rewriting rather than silly spagetti logic. However, I needed extremely fine grain control of the controllers being called based on the URLs. This will literally give you god mode control over your controller based on the URLs. Is it a hack? Yes. Is it inelegant? Absolutely. But I needed it done.
Just remember since this edits the core files, you can't easily upgrade after. I think the Kohana framework has a solution to this.
I kept reading the CI docs after Alex's post and found info on the routes.php file which does exactly what I needed.
It allows you to use regular expressions to rewrite the routes (URLs), much in the same manner as mod_rewrite, so I could strip out the user name and end up passing it as a param.

Efficient way to handle multiple HTMLPurifier configs

I'm using HTMLPurifier in a current project and I'm not sure about the most efficient way to go about handling multiple configs. For the most part the only major thing changing is the allowed tags.
Currently I have a private method, in each class using HTMLPurifier, that gets called when a config is needed and it creates one from the default. I'm not really happy with this as if 2 classes are using the same config, that's duplicating code, and what if a class needs 2 configs? It just feels messy.
The one upside to it, is it's lazy in the sense that it's not creating anything until it's needed. The various classes could be used and never have to purify anything. So I don't want to be creating a bunch of config objects that might not even be used.
I just recently found out that you can create a new instance of HTMLPurifier and directly set config options like so:
$purifier = new HTMLPurifier();
$purifier->config->set('HTML.Allowed', '');
I'm not sure if that's bad form at all or not, and if it isn't I'm not really sure of a good way to put it to use.
My latest idea was to create a config handler class that would just return an HTMLPurifier config for use in subsequent purify calls. At some point it could probably be expanded to allow the setting of configs, but just from the start I figured they'd just be hardcoded and run a method parameter through a switch to grab the requested config. Perhaps I could just send the stored purifier instance as an argument and have the method directly set the config on it like shown above?
This to me seems the best of the few ways I thought of, though I'm not sure if such a task warrants me creating a class to handle it, and if so, if I'm handling it in the best way.
I'm not too familiar with the inner workings of HTMLPurifier so I'm not sure if there are any better mechanisms in place for handling multiple configs.
Thanks for any insight anyone can offer.
Configuration objects have one important invariant: after they've been used to perform a purification, they cannot be edited. You might be interested in some convenience methods that the class has, in particular, inherit, and you can load an array of values using loadArray.
I just wrote up a quick, simple config handler class.
You can view / use it # http://gist.github.com/358187/
It takes an array of configs at initialization.
$configs = array(
'HTML.Doctype' => 'HTML 4.01 Strict',
'posts' => array(
'HTML.Allowed' => 'p,a[href],img[src]'
),
'comments' => array(
'HTML.Allowed' => 'p'
),
'default' => array(
'HTML.Allowed' => ''
)
);
Directives put directly into the array are global and will be applied to all configs. If the same directive is set inside a named config, the value in the named config will be used.
Then you can grab a config like so:
$purifierConfig = new purifierConfig($configs);
$commentsConfig = $purifierConfig->getConfig('comments');
or, shorthand:
$commentsConfig = $purifierConfig['comments'];
If the requested config does not exist or no config is specified in the call, the default config will be returned.
I'll probably flesh it out at some point, but for now this works.
I was looking for how people handled such things in their projects or if there were any built in mechanisms that made something like this more steamlined, but I suppose my question was a bit too narrow in scope.

Symfony - Override sf_format when calling get_partial

I'm making an AJAX call in my symfony project, so it has an sf_format of 'js'. In the actionSuccess.js.php view, I call get_partial to update the content on the page. By default it looks for the partial in 'js' format since the sf_format is still set as 'js'. Is it possible to override the sf_format so that it uses the regular 'html' partial that I already have (so that I don't have to have two identical partials)?
I have had a similar issue.
I looked through the code, and get_partial doesn't give you any scope to change the format looked for ... guess you could modify the code to make that possible if you needed to.
I instead went for switching the request format - also not ideal in my opinion. But better than editing the symfony files.
To do this in the controller:
$request->setRequestFormat('html');
or in the view
$sf_context->getRequest()->setRequestFormat('html');
In both cases, if you want to set this back afterwards, you can retrieve the existing value using getRequestFormat().
if your looking for a more sustainable solution, you could listen to the view.configure_format and set the sfPHPView extension in your appflication configuration.
// in apps/api/config/apiConfiguration.class.php
public function configure() {
$this->dispatcher->connect('view.configure_format', array($this, 'configure_formats'));
}
public function configure_formats(sfEvent $event) {
// change extension, so our module templates and partials
// for xml do not need the .xml.php extension
$event->getSubject()->setExtension('.php');
}

Categories