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?
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');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.
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.
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
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.
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 😊
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.
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
Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.