- Notifications
You must be signed in to change notification settings - Fork14
A set of Eloquent models for ExpressionEngine Channel Entries.
License
rsanchez/Deep
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A read-only set ofEloquent models for ExpressionEngine Channel Entries. This library has a few goals in mind:
- replicate as much of the
{exp:channel:entries}
functionality as possible using Eloquentquery scopes - chainable with standard Eloquent model methods (ex.
->where('foo', 'bar')
) - minimize the number of queries needed using eager loading
- provide an base plugin from which EE plugins/modules can extend, which has near parity with
{exp:channel:entries}
- automatically fetch custom fields using field names and entities instead of just raw text from
exp_channel_data
For more detailed information, see theauto-generated API docs.
EE Version | Deep Version |
---|---|
2.x | 2.0.x |
3.x | 2.1.x |
>= 4.x | 3.0.x |
<?phpuse rsanchez\Deep\Deep;use rsanchez\Deep\Model\Entry;Deep::bootInstance();$entries = Entry::channel('blog') ->limit(10) ->showFutureEntries() ->get();?><?php foreach ($entries as $entry) : ?><article> <h1><?php echo e($entry->title); ?></h1> <p><?php echo $entry->entry_date->format('F j, Y'); ?></p> <?php echo $entry->description; ?></article><?php endforeach ?>
Run this command in your terminal:
composer require rsanchez/deep
Make sure you load composer's autoloader at the top of yourconfig.php
(your actual vendor path may vary):
require_once FCPATH.'vendor/autoload.php'
Then you can create your own plugin that uses Deep byextending theBasePlugin
class. Or you can use the built-in wrapper class, which bootstraps Deep with EE for you:
use rsanchez\Deep\Deep;use rsanchez\Deep\Model\Entry;Deep::bootEE();$entries = Entry::channel('blog') ->limit(10) ->get();
Deep comes with a service provider for Laravel. Add this to the list of providers inapp/config/app.php
:
'rsanchez\Deep\App\Laravel\ServiceProvider',use rsanchez\Deep\Model\Entry;route('/blog', function(){ $entries = Entry::channel('blog')->get(); return View::make('blog.index')->withEntries($entries);});route('/blog/json', function(){ $entries = Entry::channel('blog')->get(); return Response::json($entries);});
If you are using a table prefix for your database tables (EE usesexp_
by default, so you most likely are), make sure to set the prefix in Laravel'sapp/config/database.php
If you need to use a DB connection other than Laravel's default connection, you should add the following configuration toapp/config/database.php
:
'deep' => array( 'connection' => 'your_connection_name',),
The specified connection will be used for all of Deep's models.
First you must bootstrap Eloquent for use outside of Laravel. There aremanyguidesoutthere on how to do this.
Then you can simply use the generic wrapper:
use rsanchez\Deep\Deep;use rsanchez\Deep\Model\Entry;Deep::bootInstance();$entries = Entry::channel('blog') ->limit(10) ->get();
Or instantiate your own instance of the Deep DI container if you prefer:
use rsanchez\Deep\Deep;$deep = new Deep();$entries = $deep->make('Entry') ->channel('blog') ->limit(10) ->get();
You can build a Phar archive as an alternative installation method. The best way to package Deep with your custom distributed add-on is to use the Phar archive, since EE doesn't natively support compser installation out of the box.
To build the Phar archive, you must havebox installed. Then you can clone this repo, runcomposer install
to fetch all the dependencies, and runbox build
to create the Phar archive. The archive can be found inbuild/deep.phar
after it's built.
Now you can package that single Phar archive with your add-on (say, in aphar
folder in your add-on root) and load it like so:
// this is a courtesy check in case other add-ons are also// using deep.pharif ( ! class_exists('\\rsanchez\\Deep\\Deep')){ require_once PATH_THIRD.'your_addon/phar/deep.phar';}
Filtering scopes should look familiar, since most of them relate to a native{exp:channel:entries}
parameter.
Entry::channel('blog', 'news')->get();
Entry::notChannel('blog', 'news')->get();
Entry::channelId(1, 2)->get();
Entry::notChannelId(1, 2)->get();
Entry::authorId(1, 2)->get();
Entry::notAuthorId(1, 2)->get();
Entry::category(1, 2)->get();
Entry::notCategory(1, 2)->get();
Only show entries that have all of the specified categories.
Entry::allCategories(1, 2)->get();
Exclude entries that have all of the specified categories.
Entry::notAllCategories(1, 2)->get();
Entry::categoryName('mammals', 'reptiles')->get();
Entry::notCategoryName('mammals', 'reptiles')->get();
Entry::categoryGroup(1, 2)->get();
Entry::notCategoryGroup(1, 2)->get();
Entry::day(31)->get();
Entry::dynamicParameters(array('limit', 'search:your_field_name'), $_REQUEST)->get();
Entry::entryId(1, 2)->get();
Entry::notEntryId(1, 2)->get();
Entry::entryIdFrom(1)->get();
Entry::entryIdTo(100)->get();
Entry::fixedOrder(4, 8, 15, 16, 23, 42)->get();
Entry::groupId(1, 2)->get();
Entry::notGroupId(1, 2)->get();
Entry::limit(1)->get();
Entry::month(12)->get();
Entry::offset(1)->get();
Entry::showExpired(false)->get();
Entry::showFutureEntries(true)->get();
Entry::showPages(false)->get();
Entry::showPagesOnly(true)->get();
Entry::siteId(1, 2)->get();
Unix time:
Entry::startOn(1394393247)->get();
Or use aDateTime
object:
$date = new DateTime();Entry::startOn($date)->get();
Unix time:
Entry::stopBefore(1394393247)->get();
Or use aDateTime
object:
$date = new DateTime();Entry::stopBefore($date)->get();
Entry::sticky(true)->get();
Entry::status('open', 'closed')->get();
Entry::notStatus('open', 'closed')->get();
Entry::urlTitle('cats', 'dogs')->get();
Entry::notUrlTitle('cats', 'dogs')->get();
Entry::username('john_doe', 'jane_doe')->get();
Entry::notUsername('john_doe', 'jane_doe')->get();
Entry::year(2014)->get();
This scope accepts an array of parameters And applies all thesupported{exp:channel:entries}
parameters to the query.
Entry::tagparams(ee()->TMPL->tagparams)->get();
The following channel:entries parameters are not implemented by thetagparams
scope:
- cache
- display_by
- disable
- dynamic
- dynamic_start
- month_limit
- paginate
- paginate_base
- paginate_type
- refresh
- related_categories_mode
- relaxed_categories
- require_entry
- show_current_week
- track_views
- week_sort
- uncategorized_entries
These scopes force eager loading of certain relationships. Eager loading of custom field data is done automatically with theEntry
model (and theEntries
proxy). Use theTitle
model (or theTitles
proxy) tonot eager load custom field data.
Eager load thecategories
attribute.
Entry::withCategories()->get();
Eager load thecategories
attribute with custom category fields.
Entry::withCategoryFields()->get();
Eager load theauthor
attribute.
Entry::withAuthor()->get();
Eager load theauthor
attribute with custom member fields.
Entry::withAuthorFields()->get();
Eager load theparents
attribute (native EE relationship fields only).
Entry::withParents()->get();
Eager load thesiblings
attribute (native EE relationship fields only).
Entry::withSiblings()->get();
Eager load thecomments
attribute, a collection of Comment models.
Entry::withComments()->get();
Do not load custom fields.
Entry::withoutFields()->get();
Do not load custom fields in child (Playa/Relationship) entries.
Entry::withoutChildFields()->get();
Specify exactly which custom fields to load.
Entry::withFields(['your_custom_field', 'your_other_custom_field'])->get();
This set of scopes allows you to use the traditional some Eloquent methods with custom field names instead offield_id_X
.
Entry::orderByField('your_custom_field', 'asc')->get();
Entry::whereField('your_custom_field', 'foo')->get();
Entry::orWhereField('your_custom_field', 'foo')->get();
Entry::whereFieldIn('your_custom_field', array('foo', 'bar'))->get();
Entry::orWhereFieldIn('your_custom_field', array('foo', 'bar'))->get();
Entry::whereFieldNotIn('your_custom_field', array('foo', 'bar'))->get();
Entry::orWhereFieldNotIn('your_custom_field', array('foo', 'bar'))->get();
Entry::whereFieldBetween('your_custom_field', array(1, 10))->get();
Entry::orWhereFieldBetween('your_custom_field', array(1, 10))->get();
Entry::whereFieldNotBetween('your_custom_field', array(1, 10))->get();
Entry::orWhereFieldNotBetween('your_custom_field', array(1, 10))->get();
Entry::whereFieldNull('your_custom_field')->get();
Entry::orWhereFieldNull('your_custom_field')->get();
Entry::whereFieldNotNull('your_custom_field')->get();
Entry::orWhereFieldNotNull('your_custom_field')->get();
This is likesearch:your_custom_field="foo|bar"
.
Entry::whereFieldContains('your_custom_field', 'foo', 'bar')->get();
Entry::orWhereFieldContains('your_custom_field', 'foo', 'bar')->get();
This is likesearch:your_custom_field="not foo|bar"
.
Entry::whereFieldDoesNotContain('your_custom_field', 'foo', 'bar')->get();
Entry::orWhereFieldDoesNotContain('your_custom_field', 'foo', 'bar')->get();
This is likesearch:your_custom_field="foo\W|bar\W"
.
Entry::whereFieldContainsWholeWord('your_custom_field', 'foo', 'bar')->get();
Entry::orWhereFieldContainsWholeWord('your_custom_field', 'foo', 'bar')->get();
This is likesearch:your_custom_field="not foo\W|bar\W"
.
Entry::whereFieldDoesNotContainWholeWord('your_custom_field', 'foo', 'bar')->get();
Entry::orWhereFieldDoesNotContainWholeWord('your_custom_field', 'foo', 'bar')->get();
This library makes use of Eloquent'srelationship capabilities. If you need to do more advanced category querying than the default category scopes, you can use thewhereHas
andorWhereHas
methods.
Entry::whereHas('categories', function ($query) { // category starts with A $query->where('cat_name', 'LIKE', 'A%');})->get();
Each entry object has the following string properties from theexp_channel_titles
table.
$entry->entry_id$entry->site_id$entry->channel_id$entry->author_id$entry->forum_topic_id$entry->ip_address$entry->title$entry->url_title$entry->status$entry->versioning_enabled$entry->view_count_one$entry->view_count_two$entry->view_count_three$entry->view_count_four$entry->allow_comments$entry->sticky$entry->year$entry->month$entry->day$entry->comment_total$entry->page_uri
Entries have the following date properties. Each of these will be aCarbon
object.expiration_date
,comment_expiration_date
andrecent_comment_date
can benull
.
$entry->entry_date$entry->edit_date$entry->expiration_date$entry->comment_expiration_date$entry->recent_comment_date
Dates are serialized to ISO-8601 format during toArray and toJson. To do this, Deep sets Carbon's default format toDateTime::ISO8601
orY-m-d\TH:i:sO
. If you wish to change the default format, you should call\Carbon\Carbon::setToStringFormat($yourDateFormatString)
prior to serialization. If you wish to reset this attribute globally in Carbon to the original default, you should callCarbon::resetToStringFormat()
.
If you need info about the entry's channel, there is the$entry->channel
object. The channel object contains the following properties from theexp_channels
table.
$entry->channel->channel_id$entry->channel->site_id$entry->channel->channel_name$entry->channel->channel_title$entry->channel->channel_url$entry->channel->channel_description$entry->channel->channel_lang$entry->channel->total_entries$entry->channel->total_comments$entry->channel->last_entry_date$entry->channel->last_comment_date$entry->channel->cat_group$entry->channel->status_group$entry->channel->deft_status$entry->channel->field_group$entry->channel->search_excerpt$entry->channel->deft_category$entry->channel->deft_comments$entry->channel->channel_require_membership$entry->channel->channel_max_chars$entry->channel->channel_html_formatting$entry->channel->channel_allow_img_urls$entry->channel->channel_auto_link_urls$entry->channel->channel_notify$entry->channel->channel_notify_emails$entry->channel->comment_url$entry->channel->comment_system_enabled$entry->channel->comment_require_membership$entry->channel->comment_use_captcha$entry->channel->comment_moderate$entry->channel->comment_max_chars$entry->channel->comment_timelock$entry->channel->comment_require_email$entry->channel->comment_text_formatting$entry->channel->comment_html_formatting$entry->channel->comment_allow_img_urls$entry->channel->comment_auto_link_urls$entry->channel->comment_notify$entry->channel->comment_notify_authors$entry->channel->comment_notify_emails$entry->channel->comment_expiration$entry->channel->search_results_url$entry->channel->show_button_cluster$entry->channel->rss_url$entry->channel->enable_versioning$entry->channel->max_revisions$entry->channel->default_entry_title$entry->channel->url_title_prefix$entry->channel->live_look_template
EachEntry
object has acategories
property which is a collection ofCategory
objects. Use thewithCategories
orwithCategoryFields
scope to eager load this relationship.
foreach ($entry->categories as $category) { echo '<li><a href="/blog/category/'.$category->cat_url_title.'">'.$category->cat_name.'</a></li>';}
$category->cat_id$category->site_id$category->group_id$category->parent_id$category->cat_name$category->cat_description$category->cat_image$category->cat_order$category->your_custom_field
EachEntry
object has aauthor
property which is aMember
object. Use thewithAuthor
orwithAuthorFields
scope to eager load this relationship.
$entry->author->member_id$entry->author->group_id$entry->author->username$entry->author->screen_name$entry->author->password$entry->author->salt$entry->author->unique_id$entry->author->crypt_key$entry->author->authcode$entry->author->email$entry->author->url$entry->author->location$entry->author->occupation$entry->author->interests$entry->author->bday_d$entry->author->bday_m$entry->author->bday_y$entry->author->aol_im$entry->author->yahoo_im$entry->author->msn_im$entry->author->icq$entry->author->bio$entry->author->signature$entry->author->avatar_filename$entry->author->avatar_width$entry->author->avatar_height$entry->author->photo_filename$entry->author->photo_width$entry->author->photo_height$entry->author->sig_img_filename$entry->author->sig_img_width$entry->author->sig_img_height$entry->author->ignore_list$entry->author->private_messages$entry->author->accept_messages$entry->author->last_view_bulletins$entry->author->last_bulletin_date$entry->author->ip_address$entry->author->join_date$entry->author->last_visit$entry->author->last_activity$entry->author->total_entries$entry->author->total_comments$entry->author->total_forum_topics$entry->author->total_forum_posts$entry->author->last_entry_date$entry->author->last_comment_date$entry->author->last_forum_post_date$entry->author->last_email_date$entry->author->in_authorlist$entry->author->accept_admin_email$entry->author->accept_user_email$entry->author->notify_by_default$entry->author->notify_of_pm$entry->author->display_avatars$entry->author->display_signatures$entry->author->parse_smileys$entry->author->smart_notifications$entry->author->language$entry->author->timezone$entry->author->time_format$entry->author->include_seconds$entry->author->date_format$entry->author->cp_theme$entry->author->profile_theme$entry->author->forum_theme$entry->author->tracker$entry->author->template_size$entry->author->notepad$entry->author->notepad_size$entry->author->quick_links$entry->author->quick_tabs$entry->author->show_sidebar$entry->author->pmember_id$entry->author->rte_enabled$entry->author->rte_toolset_id$entry->author->your_custom_field
EachEntry
object has acomments
property which is a collection ofComment
objects. Use thewithComments
scope to eager load this relationship.
$entry->comment->comment_id$entry->comment->site_id$entry->comment->entry_id$entry->comment->channel_id$entry->comment->author_id$entry->comment->status$entry->comment->name$entry->comment->email$entry->comment->url$entry->comment->location$entry->comment->ip_address$entry->comment->comment_date$entry->comment->edit_date$entry->comment->comment$entry->comment->author->member_id$entry->comment->author->username$entry->comment->author->screen_name
Entries have their custom fields as properties, keyed by the field short name. Most custom field properties merely the string data from the correspondingexp_channel_data
field_id_X
column.
$entry->your_field_name
For the following fieldtypes, an entry's custom field properties will be special objects, rather than string data from theexp_channel_data
table.
Matrix & Grid fields will be Eloquent Collections ofRow
objects. EachRow
object has string properties keyed to the column short name from theexp_matrix_data
andexp_channel_grid_field_X
tables, respectively. CustomRow
fields follow the same logic asEntry
custom fields.
$number_of_rows = $entry->your_matrix_field->count();foreach ($entry->your_matrix_field as $row) { echo $row->your_text_column; foreach ($row->your_playa_column as $childEntry) { echo $childEntry->title; }}
Playa & Relationship fields will be Eloquent Collections of relatedEntry
objects. TheseEntry
objects behave just as parentEntry
objects do.
$number_of_rows = $entry->your_playa_field->count();foreach ($entry->your_playa_field as $childEntry) { echo $childEntry->title;}
Assets fields will be Eloquent Collections ofAsset
objects.Asset
objects have the following properties:
foreach ($entry->your_assets_field as $file) { $file->url $file->server_path $file->file_id $file->folder_id $file->source_type $file->source_id $file->filedir_id $file->file_name $file->title $file->date $file->alt_text $file->caption $file->author $file->desc $file->location $file->keywords $file->date_modified $file->kind $file->width $file->height $file->size $file->search_keywords}
File fields will be a singleFile
object.File
objects have the following properties:
$entry->your_file_field->url$entry->your_file_field->server_path$entry->your_file_field->file_id$entry->your_file_field->site_id$entry->your_file_field->title$entry->your_file_field->upload_location_id$entry->your_file_field->rel_path$entry->your_file_field->mime_type$entry->your_file_field->file_name$entry->your_file_field->file_size$entry->your_file_field->description$entry->your_file_field->credit$entry->your_file_field->location$entry->your_file_field->uploaded_by_member_id$entry->your_file_field->upload_date$entry->your_file_field->modified_by_member_id$entry->your_file_field->modified_date$entry->your_file_field->file_hw_original
echo '<img src="'.$entry->your_file_field->url.'" />';
Date fields will be a singleCarbon
object.
echo $entry->your_date_field->format('Y-m-d H:i:s');
These fields will be arrays of values:
foreach ($entry->your_multiselect_field as $value) { echo $value;}
The abstractrsanchez\Deep\Plugin\BasePlugin
class is provided as a base for ExpressionEngine modules and plugins. TheparseEntries
method parses a template using anEntryCollection
.
<?phpuse rsanchez\Deep\Plugin\BasePlugin;class My_plugin extends BasePlugin{ public function entries() { return $this->parseEntries(); } public function entries_that_start_with() { $letter = ee()->TMPL->fetch_param('letter'); return $this->parseEntries(function ($query) use ($letter) { // do additional custom querying here $query->where('title', 'LIKE', $letter.'%'); }); }}
Now you can parse your plugin like a channel:entries tag:
{exp:my_plugin:entries channel="blog"} {title} {url_title_path="blog/view"}{/exp:my_plugin:entries}{exp:my_plugin:entries_that_start_with channel="blog" letter="A"} {title} {url_title_path="blog/view"}{/exp:my_plugin:entries_that_start_with}
The following channel:entries single tags / conditionals are not implemented by theBasePlugin
class:
- gmt_entry_date
- gmt_edit_date
- member_search_path
- relative_url
- relative_date
- trimmed_url
- week_date
The following channel:entries parameters are not implemented by theBasePlugin
class:
- display_by
- dynamic_start
- month_limit
- paginate_type
- relaxed_categories
- show_current_week
- track_views
- week_sort
- uncategorized_entries
TheparseEntries
method has the following default parameters:
orderby="entry_date"show_future_entries="no"show_expired="no"sort="desc"status="open"dynamic="yes"limit="100"
You can change this by overloading thegetEntriesDefaultParameters
method in your plugin/module class:
protected function getEntriesDefaultParameters(){ return array( 'dynamic' => 'no', 'status' => 'open|Featured', );}
TheBasePlugin
class allows the following parameters on Matrix, Grid, Playa and Relationships tag pairs:
- limit
- offset
- orderby
- sort
- search:your_field
- fixed_order
- backspace
- entry_id*
- row_id**
*Playa and Relationships only**Matrix and Grid only
TheBasePlugin
class can also parse the equivalent of a channel:categories tag.
<?phpuse rsanchez\Deep\Plugin\BasePlugin;class My_plugin extends BasePlugin{ public function categories() { return $this->parseCategories(); } public function offices() { $country = ee()->TMPL->fetch_param('country', 'us'); ee()->TMPL->tagparams['style'] = 'linear'; return $this->parseCategories(function ($query) use ($country) { return $query->channel('offices')->where('categories.cat_name', $country); }); }}
Now you can parse your plugin like a channel:categories tag:
{exp:my_plugin:categories channel="blog"} <a href="{path='blog'}"{if active}{/if}>{category_name}</a>{/exp:my_plugin:categories}{exp:my_plugin:offices country="{segment_2}"}{if no_results}{redirect="404"}{/if}<h1><a href="{site_url}offices/{category_url_title}">{category_name}</a></h1>{category_description}{/exp:my_plugin:offices}
TheparseCategories
method has the following default parameters:
show_empty="yes"show_future_entries="no"show_expired="no"restrict_channel="yes"style="nested"id="nav_categories"class="nav_categories"orderby="categories.group_id|categories.parent_id|categories.cat_order"
You can change this by overloading thegetCategoriesDefaultParameters
method in your plugin/module class:
protected function getCategoriesDefaultParameters(){ $params = parent::getCategoriesDefaultParameters(); $params['style'] = 'linear'; return $params;}
About
A set of Eloquent models for ExpressionEngine Channel Entries.