Creating, Reading, Searching, Updating and Deleting Express Entries

This requires Concrete CMS 8.1.0 or greater.

While it's easy to programmatically add Express objects in your package controllers, you can also use a similar approach to programmatically add Express entries, their attributes, and even associate these entries with each other. f

Create Entities

Package Prerequisite

Note: this documentation assumes you'll be adding an Express Object via the install() method of a Package. If you aren't familiar with creating Concrete packages you should check out that documentation first.

First, create some Express entities as described in the Express Object Builder documentation.. For example, let's say you create a student entity:

$student = Express::buildObject('student', 'students', 'Student');
$student->addAttribute('text', 'First Name', 'student_first_name');
$student->addAttribute('text', 'Last Name', 'student_last_name');
$student->addAttribute('textarea', 'Bio', 'student_bio');
$student->addAttribute('address', 'Address', 'student_contact_address');
$student->save();

This creates a student object with four attributes. Next, you'll use the Express Entry Builder to create some student entries.

The Express Entry Builder

First, you're going to retrieve an instance of the Express Entry Builder. This can be done by importing Express facade into your package's controller.php file:

use Express;

Then, within the install() method of the controller.php file, you'll retrieve an instance of the Concrete\Core\Express\EntryBuilder and add some attributes to it:

    $address = new \Concrete\Core\Entity\Attribute\Value\Value\AddressValue();
    $address->setAddress1('123 SW Test');
    $address->setCity('Portland');
    $address->setStateProvince('OR');
    $address->setPostalCode('97200');

    $entry = Express::buildEntry('student')
        ->setStudentFirstName('Andrew')
        ->setStudentLastName('Embler')
        ->setStudentContactAddress($address)
        ->save();

The $entry object here is the full Concrete\Core\Entity\Express\Entry object, with three attribute keys attached to it. The magic methods setStudent* work automatically based off the attribute key handles set in the ObjectBuilder class.

Adding Associations to the Object

Adding associations to the entry object is easy too. It's not done through the EntryBuilder class, because unlike the EntryBuilder class objects, associations happen immediately (there is no save() method.). Let's create a Teacher object, and associate a couple student objects with the teacher:

$teacher = Express::buildObject('teacher', 'teachers', 'Teacher');
$teacher->addAttribute('text', 'First Name', 'teacher_first_name');
$teacher->addAttribute('text', 'Last Name', 'teacher_last_name');
$teacher = $teacher->save();

Now $student and $teacher are populated by the Concrete\Core\Entity\Express\Entity objects that correspond to the relevant Express objects.

$student1 = Express::buildEntry('student')
    ->setStudentFirstName('Andrew')
    ->setStudentLastName('Embler')
    ->save();

$student2 = Express::buildEntry('student')
    ->setStudentFirstName('Jane')
    ->setStudentLastName('Doe')
    ->save();

$teacher = Express::buildEntry('teacher')
    ->setTeacherFirstName('Albert')
    ->setTeacherLastName('Einstein')
    ->save();

Now, assuming there's a one-to-many association from Teacher to Student, we can use the associateEntries() method on either of the entry objects above, and set the appropriate associated objects.

$teacher->associateEntries()->setStudents([$student1, $student2]);

That's it! The association is updated.

Getting Data From an Express Entry

Once you have an express entry object, it's easy to get data from it. Simply call $entry->get* where the * matches the camelcased handle of the attribute. So in the example of our attribute named teacher_first_name, if we had a teacher entry, we'd call

print $entry->getTeacherFirstName();

This returns data in the native value response for the attribute. So in this example it will return text. Want the underlying attribute value object? Just call

$value = $entry->getAttributeValueObject('teacher_first_name');

Getting Associated Entries

It's just as easy to get associated entries from an entry object. In our example above, we have a student and its many-to-one relation with a teacher, and vice versa. When getting the related teacher entries from a student, that target property name will generally be singular, and will by default use the standard handle for teacher ("teacher"). When operating on a teacher entry, since it's a one-to-many association we're working with, we'll be using the target property name that corresponds to the plural handle ("students."). Once we know the relevant target property name for our type of association, we simply call $entry->get* with the camelcased version of the target property name:

$students = $teacher->getStudents(); // Returns a collection of students since this is one-to-many;
foreach($students as $student) {
    print $student->getStudentFirstName();
}

$teacher = $student->getTeacher(); // Returns a single teacher object, since this association is many to one
print $teacher->getTeacherFirstName();

Retrieving Entries

Getting a List of Entries

Getting a list of entries of a certain type is a matter of using the Concrete\Core\Express\EntryList class. Let's use this class to get a list of all students. First, retrieve the student Express object:

$entity = Express::getObjectByHandle('student');

Then instantiate the entry list object with the entity as its argument.

$list = new Concrete\Core\Express\EntryList($entity);

This is an instance of the Concrete\Core\Search\ItemList\Database\AttributedItemList class. You can use all the same methods you use to filter pages and files here:

$students = $list->getResults();

Filtering the List

Filter the list the same way you would for custom attributes in a page list:

$list->filterByStudentFirstName('Andrew');
$results = $list->getResults(); // Only returns student objects where the attribute student_first_name is Andrew

Filtering by Association

Filtering by association is possible using the filterByAssociatedEntry method of the EntryList. Here's an example filtering the "Medium" object by its associated "Medium Language" entry.

$entity = Express::getObjectByHandle('medium');
$list = new EntryList($entity);
/** @var ExpressEntry $languageEntry */
$languageEntry = Express::getEntry(10); // ID of language entry
/** @var \Concrete\Core\Entity\Express\Association $association */
$association = $entity->getAssociation('medium_language');
$list->filterByAssociatedEntry($association, $languageEntry);
$entries = $list->getResults();

Getting an Entry By Its ID

Need to retrieve an entry by its ID? It's simple:

$student = Express::getEntry(1);

Now you can get its associates or attributes:

print $student->getFirstName();
$teacher = $student->getTeacher();
print $teacher->getTeacherFirstName();

Sorting the List

The same magic methods that work for filtering also work for sorting.

$list = new Concrete\Core\Express\EntryList($entity);
$list->sortByStudentFirstName('desc');
$result = $list->getResults();

Updating Entries

Updating entries is a simple matter as well.

$student = Express::getEntry(1);

We have our first student entry. Let's change his name from Andrew to Andy.

$student->setStudentFirstName('Andy');
$student->setAttribute("student_first_name", "Andy"); // These methods are the same and are interchangeable

Setting the attribute on the object changes it immediately. However, if you were to immediately call getAttribute() later in the script, the attribute value in the object might not be updated. To combat this, use the refresh() method in the express Object manager:

$student = Express::refresh($student);
print $student->getStudentFirstName(); // Returns "Andy"

Updating associations is the same as creating them. Note: updating associations clears the existing association.

$student->associateEntries()->setTeacher(null); // Now Andrew has no teacher.

Deleting Entries

Need to delete an Express entry? It's easy:

Express::deleteEntry($student->getID());

Now the student entry is gone. All attribute values and association joins in the database are gone as well. The associations on related entries are kept up to date.