Phoenix Criminal Lawyer

I’ve spent a bit of time at work this year bringing all of our servers onto the puppet configuration management system which, incidentally, I’ve been really impressed with – we now have a consistent hosting platform and a structured way of managing it. I came across munin whilst working with puppet – no idea if they are linked, but the two seem to be used together a lot. Anyhow, installing and configuring stuff like munin is so much easier now, so munin went onto the puppet manifests.

There’s a load of info available using the standard munin plugins, plus I added a few more from around the web. But I still found myself wanting a bit more info about what apache was up to though (you can never have too many graphs!). Specifically, some of the servers host several websites, so the server wide stats that the munin apache plugin collects from mod_status weren’t detailed enough. So I’ve written a couple of munin plugins to report apache stats by virtual host.

Read the rest of this entry »

A really quick one, partly as a reference for myself:

FCKEditor includes a load of file manager stuff, so I figured I may as well use it than roll my own – its got a load of features I can’t justify writing too.

The project in question uses symfony (1.2).

Googled, and found that to get it working, I just have to enable/configure it in:

fckeditor/editor/filemanager/connectors/php/config.php

All enabled, worked fine, but I was a bit bothered by this warning:

SECURITY: You must explicitly enable this “connector”. (Set it to “true”).
WARNING: don’t just set “$Config['Enabled'] = true ;”, you must be sure that only
authenticated users can access this file or use some kind of session checking.

So I hooked it up to the symfony permissions system, as below:

In place of:

$Config['Enabled'] = true ;

Use:

require_once($_SERVER['DOCUMENT_ROOT'].'/../config/ProjectConfiguration.class.php');

$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
$context = sfContext::createInstance($configuration);

if ($context->getUser()->isSuperAdmin()) {
$Config['Enabled'] = true ;
} else {
$Config['Enabled'] = false ;
}

It loads your symfony projects config, gets a context object and then uses that to get the user and check whether we are a super admin. You could alternatively create a credential and check for it with hasCredential().

Hope to help someone!

Disclaimer: I imagine if you are reading this that you know the difference between the adjacency list and nested set methods for storing hierachical data. If not, you should read this first: http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

I’ve been working on a symfony project with a hierarchical category structure, fairly standard sort of a thing. At the start I tried to use nested set and gave up due to problems getting fixtures to load – something thats crucial in order to run the project’s test suite, but also to retain the ability to easily rebuild the model and reload the data.

I went on my merry way, using the adjacency list model instead (parent_id style), and all was fine. Until the system went into production – it started to slow down. Upon looking, the number of categories now in the system and the depth of the tree meant that my methods for getting all children of a category were generating massive numbers of sql queries or, with a few changes, were generating huge queries with many joins. Neither performed that well, and whilst I could see ways to improve the situation, it felt too complicated and not ideal, plus I knew nested set would be much better and simpler.

So, some might say stupidly, I decided I had to throw a couple of hours at getting nested set fixtures to load under propel. The forum posts etc I had looked at last time still didn’t have a solution and I couldn’t find another solution either – so I went down my own path.

And, I did kind of get it to work. Sure, I cheated a bit (as you’ll see) but it gets the job done, and the cheat only impacts on data load – functionally the nested set is untouched.

Here’s what I came up with:

schema.yml for the table:

category:
  _attributes:
    treeMode: NestedSet
  id: ~
  parent_id:   {type: integer, foreignTable: category, foreignReference: id, default: null, onDelete: setnull }
  name:        { type: varchar(255), required: true, index: index }
  lft:         { type: integer, index: true, nestedSetLeftKey: true }
  rght:        { type: integer, index: true, nestedSetRightKey: true }
  scope:       { type: integer, required: true , default: 1, index: true }
  created_at:  ~
  updated_at:  ~

And a couple of examples from the fixtures:

Category:
  root:
    name: root
    root: 1
    scope: 1

  level1-1:
    name: Level 1 category 1
    parent_id: root
    scope: 1

  level2-1:
    name: level 2 category
    parent_id: level1-1
    scope: 1

  level3-1:
    name: Level 3-1
    parent_id: level2-1
    scope: 1

  level1-2:
    name: Level 1 category 2
    scope: 1
    parent_id: root

You may have noticed what I’m up to. I’ve got an adjacency list style parent_id column in the model, as well as the scope/lft/rght fields for nested set, and am using the former to store the tree structure. The only exception is the root category, which has root: 1 specified – this causes it to be the nested set root. When this data is loaded, all of the other categories get added as a child of root it according to the nested set fields (but we still have correct info using the parent_id column).

(NOTE: I’ve found that loading a lot of data into the category table using this mechanism is slow – thousands of records take 10 minutes plus. Assume the nested set stuff is adding some overhead. Not good for a dev environment where you quickly need to load data. Acceptable to me as I have a separate set of data for testing/dev that only has a small number of categories.)

What we have now is still useless – we have a data model that contains two mechanisms for representing the hierachy, one we want to use and one we don’t, and our data is in the one we don’t want to use. However, we can write a quick function to use the adjacency list data to populate the nested set data.

I added the following to my CategoryPeer:

static $treei = 1;

public static function rebuildNSTree() {
  $c = new Criteria;
  $c->add(CategoryPeer::PARENT_ID, $id);
  $starts = self::doSelect($c);
  foreach ($starts as $cat) {
    self::$treei = 1;
    self::doRebuildNSTree($cat);
  }
}

private static function doRebuildNSTree($category) {
  $category->setLft(self::$treei++);
  foreach ($category->getCategorysRelatedByParentId() as $child) {
    self::doRebuildNSTree($child);
  }
  $category->setRght(self::$treei++);
  $category->save();
}

This recurses down the tree as per the adjacency model and sets the nested set fields. Once done, we can use the nested set methods to manage and query the data – this method only needs to be run when the data is loaded. This means that from then onwards we can forget this hack and use nested set normally.

I already had a symfony task I had to run post data load to do several things, rebuilding a lucene index and clearing a cache – so I’ve made this task now also call CategoryPeer::rebuildNSTree().

To get back to my reason for doing this – I was able to get the complicated/many query operations to find all children down to a single simple query using WHERE lft>x AND rght < y – which is much much faster/cleaner etc.

Hope this helps – hopefully this issue will get resolved in the future and we’ll be able to load the fixtures properly.

(Tested against symfony 1.2.2)

I can’t be the only person who has ever googled to try and find a way to have propel automatically choose which database to connect to, based on some criteria or other.

In my case, I have dev versions of sites on the same server as live versions, so they need to look at a database with a different name. I do this all the time, so expected to find the answer quickly on google.

I didn’t! I then tried to guess/look at propel and work out how to give it multiple database configs, but I couldn’t. It can have multiple configs, but not for use instead of each other, it tries to use them all I think.

I did find a solution after a bit though, and since I can’t find it written up, I thought I would!

When you run propel-gen, propel creates a file called <projectname>-conf.php in the build/conf directory of your project.

If you open this, you can easily see where it’s put the details in from your runtime-conf.xml file.

To work with multiple databases:

  1. Create a copy of this file for each environement – i go with <project name>-conf-dev.php and <project name>-conf-live.php.
  2. Edit these files to suit (replace the db username/password with the relevant ones for that environement.
  3. When you set up propel, you will have somewhere placed a call to Propel::init – and guess what? You pass this an argument to tell it where to load the config file from. So you need to create whatever logic you need to ensure that it loads either the dev or the live version of the file.

EG:

If (strpos($_SERVER['SERVER_NAME'], “somepieceofdevurl”)) {
    $propelconf = ‘/path/to/project-conf-dev.php’;
} else {
    $propelconf = ‘/path/to/project-conf-live.php’;
}

Propel::init($propelconf);

Thats all there is to it. You don’t need to worry about the config in build.properties, as thats for the propel-gen command and isn’t needed at runtime.

Hopefully you have Propel::init callled from some common include file! Otherwise it’ll be a lot of edits.

Remember too that propel won’t update these copies of the files if you ever edit the runtime-conf.xml file – you’ll have to do that yourself.