Unable to Programmatically Creating Express Objects

Permalink 1 user found helpful
Hi,
I followed the code mentioned at developer documentation to programmatically create Express Objects, this code copied exactly from this page:
https://documentation.concrete5.org/developers/express/programmatica...

$student = Express::buildObject('student', 'students', 'Student', $pkg);
$student->addAttribute('text', 'First Name', 'first_name');
$student->addAttribute('text', 'Last Name', 'last_name');
$student->addAttribute('textarea', 'Bio', 'bio');
$student->save();
$form = $student->buildForm('Form');
$form->addFieldset('Basics')
    ->addAttributeKeyControl('first_name')
    ->addAttributeKeyControl('last_name')
    ->addTextControl('', 'This is just some basic explanatory text.')
    ->addAttributeKeyControl('bio');
$form = $form->save();


When i run this code, it create the Express Object. But when i try to add a new Student, it returns this error:
Argument 2 passed to Concrete\Core\Express\Form\Renderer::__construct() must implement interface Concrete\Core\Express\Form\FormInterface, null given, called in \concrete\src\Page\Controller\DashboardExpressEntityPageController.php on line 73

Did anybody else face similar issue?

shahroq
View Replies: View Best Answer
MrKDilkington replied on at Permalink Best Answer Reply
MrKDilkington
Hi shahroq,

I can confirm the issue you are having with the sample code.

The problem is that when you create the express object, no views are set (Default Edit Form and Default Edit View). Without the views, attempting to create a new entity will throw an error because it can't create the entry form.

Here is the same sample code with changes at the bottom for setting the views.
$student = Express::buildObject('student', 'students', 'Student', $pkg);
$student->addAttribute('text', 'First Name', 'first_name');
$student->addAttribute('text', 'Last Name', 'last_name');
$student->addAttribute('textarea', 'Bio', 'bio');
$student->save();
$form = $student->buildForm('Form');
$form->addFieldset('Basics')
    ->addAttributeKeyControl('first_name')
    ->addAttributeKeyControl('last_name')
    ->addTextControl('', 'This is just some basic explanatory text.')
    ->addAttributeKeyControl('bio');
$form = $form->save();
// CHANGES
$student->getEntity()->setDefaultViewForm($form);
$student->getEntity()->setDefaultEditForm($form);
shahroq replied on at Permalink Reply
shahroq
Thanks Karl,
Ir works fine now, i wish you edit the code at documentation too:
https://documentation.concrete5.org/developers/express/programmatica...
MrKDilkington replied on at Permalink Reply
MrKDilkington
@shahroq

I am going to update the documentation tomorrow and add a couple small things.
- what happens when you uninstall a package used to create an express object
- how to check if an express object with a certain handle already exists before installing a new express object
shahroq replied on at Permalink Reply
shahroq
I got this error when try to uninstall the package:
An exception occurred while executing 'DELETE FROM ExpressEntities WHERE id = ?' with params ["470805a2-92da-11e7-8bb9-00ff61f60463"]: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`concrete5-8.2.1`.`expressentityentries`, CONSTRAINT `FK_B8AE3531AFC87D03` FOREIGN KEY (`exEntryEntityID`) REFERENCES `ExpressEntities` (`id`))

I'm also can't delete them via c5 dashboard page :
Dashboard > System & Settings > Data Objects
I am getting same error.
MrKDilkington replied on at Permalink Reply
MrKDilkington
@shahroq

When you programmatically add an express object in a package, uninstalling the package will remove the express object as long as no entities of that type have been created.

If you created entities of that type, uninstalling the package will throw an error. For situations where you have created entities, but want to uninstall the package, you need to delete the entities first.
MrKDilkington replied on at Permalink Reply
MrKDilkington
@shahroq

Here are a couple approaches to error handling.

Install
- prevent duplicate express object handle errors
- if a handle already exists, throw an exception
public function install()
{
    $pkg = parent::install();
    $studentExpressObject = Express::getObjectByHandle('student');
    if (is_object($studentExpressObject)) {
        throw new Exception(t('An express object with this handle already exists.'));
    } else {
        $student = Express::buildObject('student', 'students', 'Student', $pkg);
        $student->addAttribute('text', 'First Name', 'first_name');
        $student->addAttribute('text', 'Last Name', 'last_name');
        $student->addAttribute('textarea', 'Bio', 'bio');
        $student->save();
        $form = $student->buildForm('Form');
        $form->addFieldset('Basics')
            ->addAttributeKeyControl('first_name')

Uninstall
- throw an exception if an express object has entries
public function uninstall()
{
    $studentExpressObject = Express::getObjectByHandle('student');
    if (is_object($studentExpressObject)) {
        // check if there are express object entries
        // - if there are, throw an exception and prevent the uninstallation
        $studentEntryList = new EntryList($studentExpressObject);
        $studentEntries = $studentEntryList->getResults();
        if ($studentEntries) {
            throw new Exception(t('The %s express entity has entries, please delete these entries before uninstalling.', $studentExpressObject->getName()));
        } else {
            parent::uninstall();
        }
    }
}

You could also add a checkbox to the uninstall screen that asks users if they want to delete the express object entries. In the package controller install() method, you could then remove the entries.
https://documentation.concrete5.org/developers/packages/handling-uni...
shahroq replied on at Permalink Reply
shahroq
Good point, also suppose i can delete the entries manually via uninstall?
MrKDilkington replied on at Permalink Reply
MrKDilkington
@shahroq

You could create an exception to warn users to manually remove entries, add the custom uninstall checkbox and then remove them in the uninstall, or just remove them in the uninstall without asking.

Uninstall
- delete any entries before uninstalling
public function uninstall()
{
    $studentExpressObject = Express::getObjectByHandle('student');
    $studentEntryList = new EntryList($studentExpressObject);
    $studentEntries = $studentEntryList->getResults();
    if ($studentEntries) {
        foreach ($studentEntries as $studentEntry) {
            Express::deleteEntry($studentEntry->getID());
        }
    }
    parent::uninstall();
}