Problems, need help? Have a tip or advice? Post it here.
8 posts Page 1 of 1
This is the current code in page.php

Code: Select all
 if( $name=='' && $title!='' ){
                $name = $FUNCS->get_clean_url( $title );
                // verify the name does not already exist
                $unique = false;
                $unique_id = 1;
                $orig_name = $name;
                while( !$unique ){
                    $rs = $DB->select( K_TBL_PAGES, array('id'), "page_name='" . $DB->sanitize( $name ). "' and NOT id=" . $DB->sanitize( $this->id ) . " and template_id='" . $DB->sanitize( $this->tpl_id ). "'" );
                    if( !count($rs) ){
                        $unique = true;
                    }
                    else{
                        $name = $orig_name . '-' . $unique_id++;
                    }
                }
                $this->_fields['k_page_name']->store_posted_changes( $name );
            }


We are having problems with it since we use Couch to log data and so we end up having 100+ queries as the page name is e.g keakie-visited-the-homepage-101. The current code iterates from 1 to 100 until it matches a unique number, meaning there are 100 extra queries to the database. A better solution could be

Code: Select all
if( $name=='' && $title!='' ){
                $name = $FUNCS->get_clean_url( $title );
                // verify the name does not already exist
                $unique = false;
                $unique_id = 1;
                $orig_name = $name;
                while( !$unique ){
               $rs = $DB->select( K_TBL_PAGES, array('id'), "page_name='" . $DB->sanitize( $name ). "' and NOT id=" . $DB->sanitize( $this->id ) . " and template_id='" . $DB->sanitize( $this->tpl_id ). "'" );
                    if( !count($rs) ){
                        $unique = true;
                    }
                    else {
                       $rs = $DB->raw_select( 'SELECT MAX(page_name) as max FROM ' . K_TBL_PAGES . ' WHERE page_name LIKE "' . $DB->sanitize( $name ) . '%"' );
                        $largest_id = $rs[0]['max'];
                        $exploded_largest_id = explode("-", $largest_id);
                        $last_id = end($exploded_largest_id);
                        $last_id++;
                        if (is_numeric($last_id)) {
                          $name = $orig_name . '-' . $last_id;
                       } else {
                          $name = $orig_name . '-' . $unique_id;
                       }
                    }
                }
               
            $this->_fields['k_page_name']->store_posted_changes( $name );
        }


Is there anything wrong with this? I'm not that experienced with PHP
1. Use 'cms:random_name' for a new cloned page's k_page_name. Then there is a high chance such situation wouldn't happen.
1.1. Alternatively, use a timestamp for the k_page_name or a combination of k_page_title and a timestamp.
2. With your solution, which is not bad if it works for you, the number part will skip the 'holes' in sequence if some page happens to be deleted. I.e. if 'keakie-visited-the-homepage-99' was deleted a new page still would end up to become 'keakie-visited-the-homepage-102'. It is a minor consequence, perhaps worth mentioning.
Thanks trendoman

I think the code is keeping pages in a loop, site has significantly slowed down as a result of it
keakie wrote: Thanks trendoman

I think the code is keeping pages in a loop, site has significantly slowed down as a result of it

Do you mean your mod slowed it down?
Could you post how long does the query 'SELECT MAX ... LIKE ...' takes to complete?
It was taking a while because the MAX function cannot sort the mixed string which contains numbers and letters. It therefore sorts 100 as higher than 200 !!

Will sort instead by publish_date

Code: Select all
 // If name empty, we create it from title field if set
            $title = trim( $this->_fields['k_page_title']->get_data() );
            $name = trim( $this->_fields['k_page_name']->get_data() );
            if( $this->tpl_nested_pages || $this->_fields['k_page_name']->modified || ($name=='' && $title!='') ){
                $this->_lock_template(); // serialize access.. lock template
            }

         if( $name=='' && $title!='' ){
                $name = $FUNCS->get_clean_url( $title );
                // verify the name does not already exist
                $unique = false;
                $unique_id = 1;
                $orig_name = $name;
                while( !$unique ){
                $rs = $DB->select( K_TBL_PAGES, array('id'), "page_name='" . $DB->sanitize( $name ). "' and NOT id=" . $DB->sanitize( $this->id ) . " and template_id='" . $DB->sanitize( $this->tpl_id ). "'" );
                    if( !count($rs) ){
                        $unique = true;
                    }
                    else {
                       $rs = $DB->raw_select( 'SELECT page_name as max FROM ' . K_TBL_PAGES . ' WHERE page_name LIKE "' . $DB->sanitize( $name ) . '%" ORDER BY publish_date desc LIMIT 0,1' );
                        $largest_id = $rs[0]['max'];
                        $exploded_largest_id = explode("-", $largest_id);
                        $last_id = end($exploded_largest_id);
                        $last_id++;
                        if (is_numeric($last_id)) {
                          $name = $orig_name . '-' . $last_id;
                       } else {
                          $name = $orig_name . '-' . $unique_id;
                       }
                    }
                }
               
            $this->_fields['k_page_name']->store_posted_changes( $name );
        }


This is much quicker, and has removed 600 queries from my homepage, which loads in half the time. Nice addition if you use Couch for data analytics.
@keakie, I'll agree with @trendoman - while your mod could be more efficient (not sure how the LIKE and MAX in the query will fare), any use-case where you find the page-names being repeated to this degree really warrants a second look.

A page-name serves as a unique identifier so, if it does not have to appear in the URL, we can get away with just using random identifiers. The 'data-bound' tutorial (http://docs.couchcms.com/concepts/datab ... submission) takes this tack for user-submitted pages by setting '_auto_title' to '1' -
Code: Select all
    <cms:db_persist_form
        _invalidate_cache='0'
        _auto_title='1'
    />

If the page-name has to appear in the URL, then you may append a random value to the human-readable name (instead of using a fully random value as name). This way you'll never have more than a single query.

I think you can use the above mentioned method with your existing setup and all new pages will have the random values appended eliminating the loop slowing down the site.
Hi @KK,

We use the page_names for data analysis which we've built upon the couch naming which appends an incremental number at the end of non-unique names.

We've overcome the MAX limitation, which did not fare well and replaced with sort by p.publish_date which is indexed and much faster.
@keakie, the algorithm for page_name generation used by Couch is actually a 'fall back' if no page_name is set.

In your case, since you require the names to be of a particular format, it'd be better to set the name for a new page explicitly.
This way you'll have the names you desire and Couch won't have to use the loop that is slowing you up.

Just above the code you quoted, you'll find a hook -
Code: Select all
// HOOK: page_presave
// the save process is about to begin.
// Field values can be adjusted before subjecting them to the save routine.
$FUNCS->dispatch_event( 'page_presave', array(&$this) );

You can use it to make your MAX code provide the name for the page (if it is new and, perhaps, if it belongs to a particular template).

This way you won't have to make changes to the core thus avoiding the risk of losing the changes while updating.
8 posts Page 1 of 1

Who is online

In total there are 10 users online :: 1 registered, 0 hidden and 9 guests
(based on users active over the past 5 minutes)

Users browsing this forum: Exabot [Bot] and 9 guests