Question

I use Redbeanphp ( http://redbeanphp.com/ ) in my php project. And i want to use a table prefix for my tables.

Redbeanphp can't support table prefix since the version 3.0. But i want to extend Redbeanphp to support table prefix in my project.

I don't want to modify the redbeanphp code. But if there's no solution, i'll do that.

I have already tried to replace the QueryWriter of Redbeanphp but the QueryWriter class is not always the same (it depends of the type of my database).

What is the best way to do that ?

Was it helpful?

Solution

I now got the response so i answer to myself.

Once redbean is initialized, you can configure a new toolbox. The toolbox in redbean handle 3 important objects : The query writer, the Redbean OODB and the database adapter. You can access the current redbean toolbox with R::$toolbox

You can do this code :

R::configureFacadeWithToolbox(new RedBean_ToolBox(R::$redbean, R::$adapter, R::$writer));

This code does nothing. Because you configure Redbean with a new toolbox but with the same OODB, the same database adapter and the same query writer. But in this code, you can replace one of these object by your own object.

Example, replacing the writer by a dummy writer :

$writer = new MyQueryWriter();
R::configureFacadeWithToolbox(new RedBean_ToolBox(R::$redbean, R::$adapter, $writer));

The probem is the following :

  • You want to replace the query writer by your own query writer to handle a table prefix
  • The query writer class is not always the same. Redbean use 5 classes for the query writer. The class depends of the database type. For instance, if you use a Mysql database, the query writer class is RedBean_QueryWriter_MySQL
  • You don't want to write an entire query writer.

Redbean query writer possible classes are :

  • RedBean_QueryWriter_CUBRID
  • RedBean_QueryWriter_MySQL
  • RedBean_QueryWriter_Oracle
  • RedBean_QueryWriter_PostgreSQL
  • RedBean_QueryWriter_SQLiteT

So, this is my solution. I wrote 5 littles classes.

class MyCubridQueryWriter extends RedBean_QueryWriter_CUBRID {

   public function safeTable($name, $noQuotes = false) {
      $name = prefix($name);
      return parent::safeTable($name, $noQuotes);
   }

} 

class MyMysqlQueryWriter extends RedBean_QueryWriter_MySQL {

   public function safeTable($name, $noQuotes = false) {
      $name = prefix($name)
      return parent::safeTable($name, $noQuotes);
   }

}

class MyOracleQueryWriter extends RedBean_QueryWriter_Oracle {

   public function safeTable($name, $noQuotes = false) {
      $name = prefix($name)
      return parent::safeTable($name, $noQuotes);
   }

} 

class MyPostgreSqlQueryWriter extends RedBean_QueryWriter_PostgreSQL {

   public function safeTable($name, $noQuotes = false) {
      $name = prefix($name)
      return parent::safeTable($name, $noQuotes);
   }

}

class MySQLiteTQueryWriter extends RedBean_QueryWriter_SQLiteT {

   public function safeTable($name, $noQuotes = false) {
      $name = prefix($name)
      return parent::safeTable($name, $noQuotes);
   }

} 

As you can see, each class extend a Redbean query writer class. We override the safeTable method. Redbean always use safeTable on a table name. The prefix function is simple :

function prefix($table) {
    return "my_prefix_$table";
}

So now, in our code. We can use an array to map a Redbean query writer class to our own classes and replace it. Here we are :

$writerMapping = array(
    'RedBean_QueryWriter_CUBRID' => 'MyCubridQueryWriter',
    'RedBean_QueryWriter_MySQL' => 'MyMysqlQueryWriter',
    'RedBean_QueryWriter_Oracle' => 'MyOracleQueryWriter',
    'RedBean_QueryWriter_PostgreSQL' => 'MyPostgreSqlQueryWriter',
    'RedBean_QueryWriter_SQLiteT' => 'MySQLiteTQueryWriter'
);

$class = $writerMapping[get_class(R::$writer)];
$writer = new $class(R::$adapter);

R::configureFacadeWithToolbox(new RedBean_ToolBox(R::$redbean, R::$adapter, $writer));

Et voila. Now Redbean will use your own writer and you can do what you want ! With our safeTable method, we add a prefix to every table name in the database.

OTHER TIPS

I ran into this problem when wanting to use RedBean with Wordpress. My solution was to create another class (WPR for "wordpress redbean"), like so:

class WPR {

    public static function __callStatic($method, $params)
    {
        global $wpdb;
        $prefix = $wpdb->base_prefix;

        foreach ($params as &$param)
            $param = preg_replace('/\{([a-zA-Z0-9_]+)\}/', $prefix . '$1', $param);

        // switch to wordpress database
        R::selectDatabase('WPR');

        // do the dang thing
        $res = call_user_func_array(array('R',$method),$params);

        // go back
        R::selectDatabase('default');

        // send it
        return $res;
    }
};

R::addDatabase('WPR', "mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASSWORD);

I also wanted this class to use a different database than my 'regular' redbean class, so I have the selectDatabase() calls in there. Comment them out if you don't need them.

What it does is it acts as a proxy to redbean, but with each input it checks for some substring like {this} and it expands it out into the full database name, with prefix. Here's an example of your usage: $my_blog = WPR::find('{blogs}', 'domain=?', array('mydomain.com')); or $allowed_hosts = WPR::getCol('SELECT domain FROM {blogs}');

In those two cases, {blogs} gets converted to wp_blogs

Magus,

I have the same problem as you. I tried your solution but could not get it working. I wrote a couple of functions for prefixing and my object names into table names and back, which I think will work in my case, but I'd still like to get your way working since it'll be more transparent. I have unprefixed table names working for reading and writing.

I noticed was that Oracle support isn't available out-of-the-box in RedBean, so I added checks for each classname to avoid errors:

if (class_exists('RedBean_QueryWriter_MySQL', false)) {
    class MyMysqlQueryWriter extends RedBean_QueryWriter_MySQL {
    ...
}

The checks should work, I got output to my log within my MySQL (which I'm using) block while loading the prefixing code.

Also, at the end there you wrote:

$class = $writerMapping(get_class(R::$writer));

but you probably meant:

$class = $writerMapping[get_class(R::$writer)];

Based on some debugging, my R::$writer has been changed after configureFacadeWithToolbox, but, for some reason the table names aren't being converted, and nothing within my custom safeTable function is being executed.

If you could give any more info on how you tested your method or what I could be missing, I'd be glad to hear it.

(I'm sorry this message isn't an answer to your question, but I really couldn't find any other way to send you a message or comment on your answer. Damn Stack Overflow! (Just kidding, I love it.))

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top