We use cookies to improve your experience. No personal information is gathered and we don't serve ads. Cookies Policy.

ExpressionEngine Logo ExpressionEngine
Features Pricing Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University
Log In or Sign Up
Log In Sign Up
ExpressionEngine Logo
Features Pro new Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University Blog
  • Home
  • Forums

Using the new Models

Developer Preview

Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger

So it looks like I’m taking Derek’s advice and doing separate code branches for EE2 and EE3. You win this time, Derek. Mostly this decision was made because I wanted to start porting EE2 version of Publisher to use some sort of proper models or entities. I was about to use Doctrine, but then decided against it (even though Doctrine is freaking amazing). Anyway, I’m having trouble getting my model to load correctly. I put everything into a Gist: https://gist.github.com/litzinger/664ccbfbd88cfc4c6993

Is there something I’m doing wrong?

       
Kevin Cupp's avatar
Kevin Cupp
791 posts
10 years ago
Kevin Cupp's avatar Kevin Cupp

Hey Brian,

You may also need a namespace declaration at the top of your model file, like this:

namespace Publisher\Model;

Assuming your Language model is in a folder called Model. Otherwise, I think it’s looking good.

       
Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger

Ah dangit. How did I forget that. Thanks, I’ll try it tonight.

What about that prefix though… do we always have to do that?

       
Seth Barber's avatar
Seth Barber
172 posts
10 years ago
Seth Barber's avatar Seth Barber

Also, you do not need to add a prefix to the autoloader as that is automatically added based on the add-on/folder name. You can remove the following from your app.setup.php file:

$autoloader = EllisLab\ExpressionEngine\Core\Autoloader::getInstance();
$autoloader->addPrefix('Publisher', PATH_THIRD.'Publisher');
       
Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger

This prefix thing is weird. The only way I can get a service to load is like this:

ee(‘publisher:Publisher/MyService’);

Can it just work like this?

ee(‘Publisher/MyService’);

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
10 years ago
Pascal Kriete's avatar Pascal Kriete

Brian, how did you set up your service in the addon.setup file?

It should work like this:

ee('publisher:MyService')

The reason we didn’t go with the slash is that the prefix is also used for views which are a file system path, and that could potentially become ambiguous.

       
Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger

This is what I have so far

$publisher_config = array(
    'author'      => 'BoldMinded',
    'author_url'  => 'http://boldminded.com/add-ons/publisher',
    'name'        => 'Publisher',
    'description' => 'Content workflow and translations. <a href="http://boldminded.com/add-ons/publisher">Documentation</a>',
    'version'     => '1.6.7',
    'namespace'   => 'Publisher',

    'services.singletons' => array(
        'Publisher/Setting' => function() {
            return new Publisher\Service\Setting();
        },
        'Publisher/Request' => function() {
            $setting = bm('Setting');
            return new Publisher\Service\Request($setting);
        },
        'Publisher/Helper' => function() {
            $setting = bm('Setting');
            $requestCache = bm('RequestCache');
            return new Publisher\Service\Helper($setting, $requestCache);
        },
        'Publisher/RequestCache' => function() {
            return new Publisher\Service\RequestCache();
        }
    ),

    'models' => array(
        'Language' => 'Model\Language',
    )
);

So it sounds like I need to remove the ‘Publisher/’ part in the array keys. Not sure I’m a fan of the prefixes. Seems like extra cruft to type, which is why I already made a bm() method to make the calls shorter.

Thanks for the clarification.

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
10 years ago
Pascal Kriete's avatar Pascal Kriete

Yep, just ditch the ‘Publisher/’.

As for your bm() function I would discourage it for general use. I would strongly discourage it inside the addon.setup file. The service closure is given a service provider object that is scoped to your own prefix, so I would suggest using that:

<?php

use Publisher\Service\Helper;
use Publisher\Service\Setting;
use Publisher\Service\Request;
use Publisher\Service\RequestCache;

$publisher_config = array(
    'author'      => 'BoldMinded',
    'author_url'  => 'http://boldminded.com/add-ons/publisher',
    'name'        => 'Publisher',
    'description' => 'Content workflow and translations. <a href="http://boldminded.com/add-ons/publisher">Documentation</a>',
    'version'     => '1.6.7',
    'namespace'   => 'Publisher',

    'services.singletons' => array(
        'Setting' => function()
        {
            return new Setting();
        },
        'Request' => function($addon)
        {
            return new Request($addon->make('Setting'));
        },
        'Helper' => function($addon)
        {
            return new Helper(
                $addon->make('Setting'),
                $addon->make('RequestCache')
            );
        },
        'RequestCache' => function()
        {
            return new RequestCache();
        }
    ),

    'models' => array(
        'Language' => 'Model\Language',
    )
);

Essentially $addon in the above code is:

$addon = ee('App')->get('publisher');

I’m definitely open to ideas for the prefixes. Obviously being able to just call ‘Settings’ is ideal, but I don’t see how to allow that and avoid collisions at the same time.

       
Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger

I see. Thanks for the advice. I guess I’ll suck it up and type a few extra characters for the prefix 😊

I guess to shorten things I could just add a property to a class and in the constructor set $this->publisher = ee(‘App’)->get(‘publisher’); then just call $this->publisher->make(‘Service’) elsewhere? For add-ons with longer names the prefix may get annoying, but I’m not sure how else to work around it at this point.

edit: I guess

$this->publisher->make(‘Service’)

isn’t any shorter than

ee('publisher:Service')

:D

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
10 years ago
Pascal Kriete's avatar Pascal Kriete

Yep that’ll work. A way to make it easier is definitely on the roadmap, typing ‘simple_commerce:’ gets old pretty quickly.

The problem is that there are two levels of prefix. There are the top level ones (services), and then the parameter ones (views, models, etc). The first one is kind of solved with what you’re doing above, the second one needs a bit more work.

Appreciate the candid feedback - I’m sure we can come up with some sort of scoping mechanism down the road.

       
Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger

Found a decent work around to stringly typing the service name all over the place.

class Language extends Model
{
    const NAME = 'publisher:Language';

    protected static $_primary_key = 'id';
    protected static $_table_name = 'publisher_languages';

Then calling it with

$languageModel = ee('Model')->make(Language::NAME);

Also, it seems weird to be loading the query builder and calling a method named getFrontend() inside of a Model. This is what I have so far (and to get Intellisense to work I have to add all the @var lines)

public function findDefaultLangId()
    {
        /** @var Frontend $db */
        $db = $this->getFrontend();
        /** @var Builder $builder */
        $builder = $db->get(self::NAME);
        /** @var Language $language */
        $language = $builder
            ->filter('is_default', 'y')
            ->first();

        return (int) $language->getId();
    }

This seems like something that belongs in a repository class and not in a model file. I’m going to play around keeping the models to only the property definitions and use repositories for random queries. Are there other ways to get access to the query builder aside from calling getFrontend()? I’ve poked around in the code but haven’t noticed something obvious yet. getFrontend() to me sounds like a method that would be fetching a front end request or view layer. I’m still trying to figure out the new architecture, so forgive me if I’m saying stupid things or misunderstanding something 😊

       
Pascal Kriete's avatar
Pascal Kriete
2,589 posts
10 years ago
Pascal Kriete's avatar Pascal Kriete
This seems like something that belongs in a repository class and not in a model file. I’m going to play around keeping the models to only the property definitions and use repositories for random queries.

I would generally agree with that. The models are currently just a data representation, they’re not meant as a place where a lot of queries happen (although it does happen, especially in events).

Are there other ways to get access to the query builder aside from calling getFrontend()?

Currently not unless you go back to calling ee('Model'), which will end all quests for testing. We’re also not thrilled with the name. Unfortunately it’s not really the query builder that you’re getting, since you can also call make() on this class, which doesn’t require a query at all. It’s just the entry point to the model api.

       
Brian Litzinger's avatar
Brian Litzinger
711 posts
10 years ago
Brian Litzinger's avatar Brian Litzinger
Unfortunately it’s not really the query builder that you’re getting

I know, but the way the method chaining works it reminds me of Doctrine’s queryBuilder, so I’m rolling with it 😊

       
Tom Jaeger's avatar
Tom Jaeger
497 posts
10 years ago
Tom Jaeger's avatar Tom Jaeger

I’m also running into an issue getting my Models to load. I’m sure it’s something simple, a quick point in the right direction would be awesome!

addon.setup.php

return array(
  'author'      => 'EEHarbor',
  'author_url'  => 'http://EEHarbor.com',
  'name'        => 'Safe Harbor Lite',
  'description' => 'Database backups for your ExpressionEngine website.',
  'version'     => '2.0.0',
  'namespace'   => 'Safeharbor_lite',
  'settings_exist' => TRUE,

My Settings.php model

<?php
namespace Safeharbor_lite\Model;

use EllisLab\ExpressionEngine\Service\Model\Model;

class Settings extends Model {

 protected static $_primary_key = 'id';
 protected static $_table_name = 'exp_safeharbor_lite_settings';

 protected $id;
 protected $site_id;
 protected $notify_email;
 protected $attach_backup;
 protected $compression;
 protected $auth_code;
}

Calling the Model in my mcp.

$test = ee('Model')->make('safeharbor_lite:Settings');

The resulting error is

Unknown model: safeharbor_lite:Settings
       
Seth Barber's avatar
Seth Barber
172 posts
10 years ago
Seth Barber's avatar Seth Barber

Hi Tom,

Add this to your addon.setup.php file:

'models' => array(
    'Settings' => 'Model\Settings',
)
       
1 2

Reply

Sign In To Reply

ExpressionEngine Home Features Pro Contact Version Support
Learn Docs University Forums
Resources Support Add-Ons Partners Blog
Privacy Terms Trademark Use License

Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.