1

I am using CakePHP 3.4+

I have written an application with multi level membership.

The Pro members will have benefit to view short url for external links which when shared will record the visit count to that url.

The original url is stored in PostVideos table for all user.

I have created a table to store uniuqe keys for short urls inside short_video_post_urls with columns

+----+---------------+------------+-------------+
| id | post_video_id | unique_key | visit_count |
+----+---------------+------------+-------------+

Since, count of Pro members will be low than normal users, I don't want to generate unique_key entry in short_video_post_urls because It will flood database with useless records.

So, what I want is to generate them dynamically and store them for PRO members only

Now, in template file I'm using $postVideo->video_url to display original video url from post_videos table.

Question

What I want is to tweak video_url entity call which will check for

  • Membership level of logged in user
  • If member is pro
    • check if unique key exists in ShortVideoPostUrls model for the url requested
    • If no record exists, then create a unique_key in ShortVideoPostUrls
    • return the new url with unique_key

But for that I need to access logged_in user data in the entity class.

What I tried?

class PostVideoLog extends Entity
{
    /*
     * ----
     * ----
    */

    protected function _getVideoUrl()
    {
        $user = $this->Users->get($this->Auth->user('id'), [
            'contain' => [
                'MembershipLevels'
            ]
        ]);

        if ($user) {
            if (strtolower($user->membership_level->title) === 'pro') {
                /**
                 * check if unique_key exists for this request
                 */
                $checkShortUrl = $this->ShortVideoPostUrls->find()
                    ->where(['post_video_log_id' => $this->_properties['id']])
                    ->first();

                if ($checkShortUrl) {
                    return $this->_generateUrl($checkShortUrl->unique_key);
                }

                /**
                 * create new record
                 */
                $unique_key_generator = new Hashids(UNIQUE_SHORT_URL_SALT, 4);
                $unique_key = $unique_key_generator->encode($this->_properties['id']);

                $newShortUrl = $this->ShortVideoPostUrls->newEntity();
                $newShortUrl = $this->ShortVideoPostUrls->patchEntity($newShortUrl, [
                    'unique_key' => $unique_key,
                    'post_video_log_id' => $this->_properties['id']
                ]);

                if ($this->ShortVideoPostUrls->save($newShortUrl)) {
                    return $this->_generateUrl($unique_key);
                }
            }
        }

        return $this->_properties['video_url'];
    }

    private function _generateUrl($unique_key)
    {
        $base_url = Router::url('/', true);

        return $base_url . '/u/' . $unique_key;
    }
}

I'm not sure, whether my approach is right or wrong.

To load Users model and other models I'm using in above function requires to use

$this->loadModel('Users');

But, loadModel seems not to be working here.

What is other approach to do this? Or how to load external model and Auth component in Entity class?

Edit 2

Is there any better alternative to do what I want without entity? or simply some way to call function from template on each entity?

Ex.

$postVideo->video_url()
Anuj TBE
  • 9,198
  • 27
  • 136
  • 285
  • 2
    You're violating the MVC pattern: Business logic in an entity. There is no "flooding" a DB with a few characters, nor do I see a need for a separate table. Just always save them on creation and just expose them the your user group as needed. Also use the router in a proper way to generate your /u/ URL. This code wouldn't pass our internal review, I would tell you to completely rewrite it. – floriank Nov 07 '17 at 21:31

1 Answers1

1

To load other model inside entity You can use TableRegistry class

use Cake\ORM\TableRegistry;

class MyModel extends Entity {

    protected function _getVideoUrl() {

        $table = TableRegistry::get('Users');
        $users = $table->find('all')->toArray();
    }
}

I think its not the best idea to use Auth component in model - I dont know how to do this "properly", but all session data (including auth data) is still available in $_SESSION array

Dariusz Majchrzak
  • 1,227
  • 2
  • 12
  • 22
  • 2
    There is no proper way of doing that, entities shouldn't be more than data containers, they're not supposed to contain business logic! Also please never access superglobals directly, whenever you feel the need to do that, this indicates that you're doing things the wrong way - instead use the APIs provided by the framework. – ndm Nov 09 '17 at 15:02