Google

Kategorie

Reprezentacja Wiedzy

Kalendarz

December 2007
M T W T F S S
« Sep   Jan »
 12
3456789
10111213141516
17181920212223
24252627282930
31  

CakePHP MySQL CollationBehavior

December 28th, 2007 by prond

Aplikacje wielojęzykowe przyspażają wielu problemów. Jednym z nich jest sortowanie wyników zapytania.
W MySQL mamy wiele opcji porównywania napisów. Ja najczęściej stosuję utf8_general_ci, ale przy tej opcji “ogonki” lądują na końcu zwracanych wyników (po znakach ASCII). Można jednak w zależości od wybranego języka używać innych COLLATION, np.:

SELECT *
FROM products
ORDER BY name COLLATE utf8_polish_ci
LIMIT 10;

Tutaj “ą” wystąpi przed “b” i tak dalej.
Jako, że najczęściej piszę aplikacje w CakePHP zrobiłem dla tego frameworka mały behavior, który ułatwia mi życie dostosowując COLLATION do aktualnie ustawionego języka.

CollationBehavior

        /**
         * MySQL collation Behavior class file.
         *
         * Model Behavior to support Polish typography.
         *
         * @filesource
         * @package     app
         * @subpackage  models.behaviors
         */
 
        /**
         * Add MySQL collation behavior
         *
         * @author      Pawel Gasiorowski
<p.gasiorowski@axent.pl>
         * @package     app
         * @subpackage  models.behaviors
        */
        class CollationBehavior extends ModelBehavior {
 
                /**
                 * Initiate behaviour for the model using specified settings.
                 *
                 * @param object $model         Model using the behaviour
                 * @param array $settings       Settings to override for model.
                 *
                 * @access public
                 */
                function setup(&amp;$model, $settings) {
                        #
                        #       get current language
                        #
                        $i18n = &amp;I18n::getInstance();
                        $language = $i18n->l10n->map($i18n->l10n->lang);
 
                        #
                        #       get collation by language
                        #
                        switch ($language) {
                            case 'pl':
                                $collation = 'utf8_polish_ci';
                            default:
                                $collation = 'utf8_general_ci';
                                break;
                        }
 
                        #
                        #       read settings
                        #
                        if (!isset($this->settings[$model->name]['fields'])) {
                                $this->settings[$model->name]['fields'] = array();
                        }
                        $this->settings[$model->name]['fields'] = array_unique(array_merge($this->settings[$model->name]['fields'], ife(is_array($settings), $settings, array())));
                        $this->settings[$model->name]['search'] = array();
                        $this->settings[$model->name]['replace'] = array();
 
                        #
                        #       setup replacements for columns
                        #
                        foreach ($this->settings[$model->name]['fields'] as &amp;$field) {
                                if (strpos($field,".") === false) {
                                        $this->settings[$model->name]['search'][] = "/({$model->name}.{$field})/";
                                } else {
                                        $this->settings[$model->name]['search'][] = "/({$field})/";
                                }
                                $this->settings[$model->name]['replace'][] = '$1'." COLLATE {$collation}";
                        }
                }
 
                /**
                 * Run before model is queried
                 *
                 * @param object $model         Model
                 * @param array $query          Model query data
                 *
                 * @access public
                 * @since 1.0
                 */
                function beforeFind (&amp;$model, &amp;$query) {
                        if (!empty($query['order'])) {
                                if (is_string($query['order'])) {
                                        $query['order'] = preg_replace($this->settings[$model->name]['search'],$this->settings[$model->name]['replace'],$query['order']);
                                } else if (is_array($query['order'])) {
                                        foreach ($query['order'] as $i => $order) {
                                            if (is_array($order)) {
                                               $_order = "";
                                               foreach ($order as $field => $direction) {
                                                   $_order .= " {$field} {$direction}";
                           }
                           $order = trim ($_order);
                        }
                                                $order = preg_replace($this->settings[$model->name]['search'],$this->settings[$model->name]['replace'],$order);
                                                $query['order'][$i] = $order;
                                        }
                                        $query['order'] = implode(" ",$query['order']);
                                }
                        }
 
                        return $query;
                }
        }
?>
</p.gasiorowski@axent.pl>

Użycie

Wystarczy dodać w modelu następującą linijkę. W miejscu gdzie jest name i description podajemy nazwy kolumn, dla których sortowanie ma uwzględniać aktualnie wybrany język.

	var $actsAs = array('Collation'=>array('name','description'));

Posted in CakePHP |

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.