1084

Solving duplicate URL strings

Comments for “Solving duplicate URL strings”
 

Posted by DaddyJohn on Friday 22nd April 2022 at 14:42 GMT

If we create a post with a name of 'My excellent holiday' , then if we have created a 'url_string' field in the table, this will be published to the db as 'my-excellent-holiday'. However, if we then create a second post of the same name, then we get the same identical URL string. Which I don't think is ideal.

I came up with the following code, but am struggling with an issue I have come up with before and my solution was not elegant and involved me writing some custom SQL code. It would be good to use the Trongate database helpers.

So, to ensure I do not have identical URL strings, I have the following code, but am getting the following error

Fatal error: Uncaught Error: Cannot use object of type stdClass as array in C:\xampp\htdocs\dynamic_blog\modules\blog_posts\controllers\Blog_posts.php:151 Stack trace: #0 C:\xampp\htdocs\dynamic_blog\engine\Core.php(209): Blog_posts->submit('') #1 C:\xampp\htdocs\dynamic_blog\engine\Core.php(32): Core->serve_controller() #2 C:\xampp\htdocs\dynamic_blog\public\index.php(5): Core->__construct() #3 {main} thrown in C:\xampp\htdocs\dynamic_blog\modules\blog_posts\controllers\Blog_posts.php on line 151 


My code is below and I have commented where I have the issue , but I can't understand why.
 function submit() {
        $this->module('trongate_security');
        $this->trongate_security->_make_sure_allowed();

        $submit = post('submit', true);

        if ($submit == 'Submit') {

            $this->validation_helper->set_rules('blog_post_name', 'Blog Post Name', 'required|min_length[2]|max_length[255]');
            $this->validation_helper->set_rules('blog_post_content', 'Blog Post Content', 'min_length[2]');
            $this->validation_helper->set_rules('home_page_placement', 'Home Page Placement', 'max_length[1]|numeric|less_than[4]|integer');
            $this->validation_helper->set_rules('tags', 'Tags', 'min_length[2]|max_length[255]');

            $result = $this->validation_helper->run();
            //if validation is successful.
            if ($result == true) {

                $update_id = segment(3);
                $data = $this->_get_data_from_post();
              
                //createS url string for the database.
                $data['url_string'] = strtolower(url_title($data['blog_post_name']));
                
            //CREATE UNIQUE URL STRING CODE STARTS HERE

                //see if there are db entries already
                $num_rows = $this->model->count_where('url_string', $data['url_string']);
               // json($num_rows, true); -- ALL OKAY
                if($num_rows > 0) {
                    $result_obj = $this->model->get();
                    //make an array.
                    $resultData = (array) $result_obj;
                    //var_dump($resultData); die();  --ALL OKAY
                    $resultSlug = [];
                    foreach($resultData as $key)
                    {
                    //ERROR - doesnt like this statement here.
                    $resultSlug[] = $key['url_string'];
                    }

                    if(in_array($data['url_string'], $resultSlug)) {
                        $count = 0;
                        while( in_array( ($data['url_string'] . '-' . ++$count ), $data) );
                        $data['url_string'] = $data['url_string'] . '-' . $count;
                    }

                }
            //UNIQUE URL STRING CODE ENDS HERE
            //creates the post status of draft or publish.
                $data['post_status'] = ($data['post_status'] == 1 ? 1 : 0);

                if (is_numeric($update_id)) {
                    //update an existing record
                    $this->model->update($update_id, $data, 'blog_posts');
                    $flash_msg = 'The record was successfully updated';
                } else {
                    //insert the new record
                    $data['date_created'] = date("Y-m-d");
                    $data['time_created'] = date("H:i:s");
                    $update_id = $this->model->insert($data, 'blog_posts');
                    $flash_msg = 'The record was successfully created';
                }

                set_flashdata($flash_msg);
                redirect('blog_posts/show/'.$update_id);

            } else {
                //form submission error
                $this->create();
            }

        }

    }


Regards

John
Early Adopter

DaddyJohn

User Level: Early Adopter

Date Joined: 23/01/2022

Posted by Davcon on Friday 22nd April 2022 at 22:16 GMT

If you do a var_dump on the $key variable, you'll find that it's an object. However, with your code you are treating it as if it's an array.

So, instead of saying:

$resultSlug[] = $key['url_string'];


You should say...

$resultSlug[] = $key->url_string;


Does that help?
Founding Member

Davcon

User Level: Founding Member

Date Joined: 3/11/2018

Posted by trefwoordpunk on Friday 22nd April 2022 at 22:22 GMT

Hi John, I just had a quick look at your code but think there might be a slight bug, it's always searching only for the url_string "my-excellent-holiday", if this exists it will be unique and your count will only ever return 1, so each subsequent post of same name would always be suffixed -2. I think you need to use the LIKE operator. You should be able to do this with just another simple little function if all you want is that each additional post of similar name gets suffixed with a number, eg. my-excellent-holiday, my-excellent-holiday-2, my-excellent-holiday-3 etc.

Change this line to use a function
$data[ 'url_string' ] = $this->_unique_url_str( $data[ 'blog_post_name' ] );


then somewhere downstairs add a function like this
function _unique_url_str( $raw_string )
{
  $url_string = strtolower( url_title( $raw_string ) );
  $count      = $this->model->count_where( "url_string", "$url_string%", "LIKE" );
  
  return ( $count > 0 ) ? $url_string . "-" . ++$count : $url_string;
}


I haven't tested this but think it should work! :)

This comment was edited by trefwoordpunk on Friday 22nd April 2022 at 22:25 GMT

Early Adopter

trefwoordpunk

User Level: Early Adopter

Date Joined: 2/02/2021

Posted by DaddyJohn on Saturday 23rd April 2022 at 06:16 GMT

Hi both,

many, many thanks for the response.

DC, quite right. I had being using the PHP Array lessons to try and get the code together in conjunction with TG helpers. In doing so I had missed the Object vs Array difference. Thanks again.

trefwoordpunk - you were quite right. I woke this morning and the first thing that came into my head was 'mmm.. not sure that code is going to quite do the job here' and rather marvelously, you had replied with a solution which does work.

Many thanks - all good now and I have unique URLs.

DC - could we have a place where we can share code solutions in a repository somewhere? Would be very useful.

In terms of marking which person solved my problem - tricky, because there were two solutions to two different problems, but just to keep the honors on an even keel, I am going to select trefwoordpunk ;-) Sorry DC ;-)

This comment was edited by DaddyJohn on Saturday 23rd April 2022 at 06:24 GMT

Early Adopter

DaddyJohn

User Level: Early Adopter

Date Joined: 23/01/2022

Posted by michidesign on Monday 25th April 2022 at 21:31 GMT

You just made my day! I was encountering the same problem... thank you so much for this one.
Early Adopter

michidesign

User Level: Early Adopter

Date Joined: 13/02/2020

×