/** * Method to handle DELETE requests. * * @param Alpha\Util\Http\Request $request * * @throws Alpha\Exception\IllegalArguementException * @throws Alpha\Exception\SecurityException * * @return Alpha\Util\Http\Response * * @since 2.0 */ public function doDELETE($request) { self::$logger->debug('>>doDELETE(request=[' . var_export($request, true) . '])'); $config = ConfigProvider::getInstance(); $params = $request->getParams(); $accept = $request->getAccept(); try { // check the hidden security fields before accepting the form data if (!$this->checkSecurityFields()) { throw new SecurityException('This page cannot accept data from remote servers!'); } if (isset($params['ActiveRecordType'])) { $ActiveRecordType = urldecode($params['ActiveRecordType']); } else { throw new IllegalArguementException('No ActiveRecord available to edit!'); } if (class_exists($ActiveRecordType)) { $record = new $ActiveRecordType(); } else { throw new IllegalArguementException('No ActiveRecord [' . $ActiveRecordType . '] available to edit!'); } // check the hidden security fields before accepting the form POST data if (!$this->checkSecurityFields()) { throw new SecurityException('This page cannot accept post data from remote servers!'); } $record->load($params['ActiveRecordOID']); ActiveRecord::begin(); $record->delete(); ActiveRecord::commit(); ActiveRecord::disconnect(); self::$logger->action('Deleted ' . $ActiveRecordType . ' instance with OID ' . $params['ActiveRecordOID']); if ($accept == 'application/json') { $response = new Response(200); $response->setHeader('Content-Type', 'application/json'); $response->setBody(json_encode(array('message' => 'deleted'))); } else { $response = new Response(301); if (isset($params['statusMessage'])) { $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage'])); } else { $this->setStatusMessage(View::displayUpdateMessage('Deleted')); } if ($this->getNextJob() != '') { $response->redirect($this->getNextJob()); } else { if ($this->request->isSecureURI()) { $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType=' . $ActiveRecordType . '&start=0&limit=' . $config->get('app.list.page.amount'))); } else { $response->redirect($config->get('app.url') . '/records/' . $params['ActiveRecordType']); } } } } catch (SecurityException $e) { self::$logger->warn($e->getMessage()); throw new ResourceNotAllowedException($e->getMessage()); } catch (RecordNotFoundException $e) { self::$logger->warn($e->getMessage()); throw new ResourceNotFoundException('The item that you have requested cannot be found!'); } catch (AlphaException $e) { self::$logger->error($e->getMessage()); ActiveRecord::rollback(); } self::$logger->debug('<<doDELETE'); return $response; }
/** * Handle GET requests. * * @param Alpha\Util\Http\Request $request * * @return Alpha\Util\Http\Response * * @since 1.0 */ public function doGET($request) { self::$logger->debug('>>doGET($request=[' . var_export($request, true) . '])'); $config = ConfigProvider::getInstance(); $sessionProvider = $config->get('session.provider.name'); $session = SessionProviderFactory::getInstance($sessionProvider); // if there is nobody logged in, we will send them off to the Login controller to do so before coming back here if ($session->get('currentUser') === false) { self::$logger->info('Nobody logged in, invoking Login controller...'); $controller = new LoginController(); $controller->setName('LoginController'); $controller->setRequest($request); $controller->setUnitOfWork(array('Alpha\\Controller\\LoginController', 'Alpha\\Controller\\InstallController')); self::$logger->debug('<<__construct'); return $controller->doGET($request); } $params = $request->getParams(); $sessionProvider = $config->get('session.provider.name'); $session = SessionProviderFactory::getInstance($sessionProvider); $body = View::displayPageHead($this); $body .= '<h1>Installing the ' . $config->get('app.title') . ' application</h1>'; try { $body .= $this->createApplicationDirs(); } catch (\Exception $e) { $body .= View::displayErrorMessage($e->getMessage()); $body .= View::displayErrorMessage('Aborting.'); return new Response(500, $body, array('Content-Type' => 'text/html')); } // start a new database transaction ActiveRecord::begin(); /* * Create DEnum tables */ $DEnum = new DEnum(); $DEnumItem = new DEnumItem(); try { $body .= '<p>Attempting to create the DEnum tables...'; if (!$DEnum->checkTableExists()) { $DEnum->makeTable(); } self::$logger->info('Created the [' . $DEnum->getTableName() . '] table successfully'); if (!$DEnumItem->checkTableExists()) { $DEnumItem->makeTable(); } self::$logger->info('Created the [' . $DEnumItem->getTableName() . '] table successfully'); // create a default article DEnum category $DEnum = new DEnum('Alpha\\Model\\Article::section'); $DEnumItem = new DEnumItem(); $DEnumItem->set('value', 'Main'); $DEnumItem->set('DEnumID', $DEnum->getID()); $DEnumItem->save(); $body .= View::displayUpdateMessage('DEnums set up successfully.'); } catch (\Exception $e) { $body .= View::displayErrorMessage($e->getMessage()); $body .= View::displayErrorMessage('Aborting.'); self::$logger->error($e->getMessage()); ActiveRecord::rollback(); return new Response(500, $body, array('Content-Type' => 'text/html')); } /* * Loop over each business object in the system, and create a table for it */ $classNames = ActiveRecord::getBOClassNames(); $loadedClasses = array(); foreach ($classNames as $classname) { array_push($loadedClasses, $classname); } foreach ($loadedClasses as $classname) { try { $body .= '<p>Attempting to create the table for the class [' . $classname . ']...'; try { $BO = new $classname(); if (!$BO->checkTableExists()) { $BO->makeTable(); } else { if ($BO->checkTableNeedsUpdate()) { $missingFields = $BO->findMissingFields(); $count = count($missingFields); for ($i = 0; $i < $count; ++$i) { $BO->addProperty($missingFields[$i]); } } } } catch (FailedIndexCreateException $eice) { // this are safe to ignore for now as they will be auto-created later once all of the tables are in place self::$logger->warn($eice->getMessage()); } catch (FailedLookupCreateException $elce) { // this are safe to ignore for now as they will be auto-created later once all of the tables are in place self::$logger->warn($elce->getMessage()); } self::$logger->info('Created the [' . $BO->getTableName() . '] table successfully'); $body .= View::displayUpdateMessage('Created the [' . $BO->getTableName() . '] table successfully'); } catch (\Exception $e) { $body .= View::displayErrorMessage($e->getMessage()); $body .= View::displayErrorMessage('Aborting.'); self::$logger->error($e->getMessage()); ActiveRecord::rollback(); return new Response(500, $body, array('Content-Type' => 'text/html')); } } $body .= View::displayUpdateMessage('All business object tables created successfully!'); /* * Create the Admin and Standard groups */ $adminGroup = new Rights(); $adminGroup->set('name', 'Admin'); $standardGroup = new Rights(); $standardGroup->set('name', 'Standard'); try { try { $body .= '<p>Attempting to create the Admin and Standard groups...'; $adminGroup->save(); $standardGroup->save(); self::$logger->info('Created the Admin and Standard rights groups successfully'); $body .= View::displayUpdateMessage('Created the Admin and Standard rights groups successfully'); } catch (FailedIndexCreateException $eice) { // this are safe to ignore for now as they will be auto-created later once all of the tables are in place self::$logger->warn($eice->getMessage()); } catch (FailedLookupCreateException $elce) { // this are safe to ignore for now as they will be auto-created later once all of the tables are in place self::$logger->warn($elce->getMessage()); } } catch (\Exception $e) { $body .= View::displayErrorMessage($e->getMessage()); $body .= View::displayErrorMessage('Aborting.'); self::$logger->error($e->getMessage()); ActiveRecord::rollback(); return new Response(500, $body, array('Content-Type' => 'text/html')); } /* * Save the admin user to the database in the right group */ try { try { $body .= '<p>Attempting to save the Admin account...'; $admin = new Person(); $admin->set('displayName', 'Admin'); $admin->set('email', $session->get('currentUser')->get('email')); $admin->set('password', $session->get('currentUser')->get('password')); $admin->save(); self::$logger->info('Created the admin user account [' . $session->get('currentUser')->get('email') . '] successfully'); $adminGroup->loadByAttribute('name', 'Admin'); $lookup = $adminGroup->getMembers()->getLookup(); $lookup->setValue(array($admin->getID(), $adminGroup->getID())); $lookup->save(); self::$logger->info('Added the admin account to the Admin group successfully'); $body .= View::displayUpdateMessage('Added the admin account to the Admin group successfully'); } catch (FailedIndexCreateException $eice) { // this are safe to ignore for now as they will be auto-created later once all of the tables are in place self::$logger->warn($eice->getMessage()); } catch (FailedLookupCreateException $elce) { // this are safe to ignore for now as they will be auto-created later once all of the tables are in place self::$logger->warn($elce->getMessage()); } } catch (\Exception $e) { $body .= View::displayErrorMessage($e->getMessage()); $body .= View::displayErrorMessage('Aborting.'); self::$logger->error($e->getMessage()); ActiveRecord::rollback(); return new Response(500, $body, array('Content-Type' => 'text/html')); } $body .= '<br><p align="center"><a href="' . FrontController::generateSecureURL('act=Alpha\\Controller\\ListActiveRecordsController') . '">Administration Home Page</a></p><br>'; $body .= View::displayPageFoot($this); // commit ActiveRecord::commit(); self::$logger->info('Finished installation!'); self::$logger->action('Installed the application'); self::$logger->debug('<<doGET'); return new Response(200, $body, array('Content-Type' => 'text/html')); }
/** * Handle POST requests. * * @param Alpha\Util\Http\Request $request * * @return Alpha\Util\Http\Response * * @throws Alpha\Exception\SecurityException * * @since 1.0 */ public function doPOST($request) { self::$logger->debug('>>doPOST($request=[' . var_export($request, true) . '])'); $params = $request->getParams(); try { // check the hidden security fields before accepting the form POST data if (!$this->checkSecurityFields()) { throw new SecurityException('This page cannot accept post data from remote servers!'); self::$logger->debug('<<doPOST'); } // ensure that a OID is provided if (isset($params['denumOID'])) { $BOoid = $params['denumOID']; } else { throw new IllegalArguementException('Could not load the DEnum object as an denumOID was not supplied!'); } if (isset($params['saveBut'])) { try { $this->BO->load($BOoid); // update the object from post data $this->BO->populateFromArray($params); ActiveRecord::begin(); $this->BO->save(); self::$logger->action('DEnum ' . $this->BO->getOID() . ' saved'); // now save the DEnumItems $tmp = new DEnumItem(); $denumItems = $tmp->loadItems($this->BO->getID()); foreach ($denumItems as $item) { $item->set('value', $params['value_' . $item->getID()]); $item->save(); self::$logger->action('DEnumItem ' . $item->getOID() . ' saved'); } // handle new DEnumItem if posted if (isset($params['new_value']) && trim($params['new_value']) != '') { $newItem = new DEnumItem(); $newItem->set('value', $params['new_value']); $newItem->set('DEnumID', $this->BO->getID()); $newItem->save(); self::$logger->action('DEnumItem ' . $newItem->getOID() . ' created'); } ActiveRecord::commit(); $this->setStatusMessage(View::displayUpdateMessage(get_class($this->BO) . ' ' . $this->BO->getID() . ' saved successfully.')); return $this->doGET($request); } catch (FailedSaveException $e) { self::$logger->error('Unable to save the DEnum of id [' . $params['oid'] . '], error was [' . $e->getMessage() . ']'); ActiveRecord::rollback(); } ActiveRecord::disconnect(); } } catch (SecurityException $e) { $this->setStatusMessage(View::displayErrorMessage($e->getMessage())); self::$logger->warn($e->getMessage()); } catch (IllegalArguementException $e) { $this->setStatusMessage(View::displayErrorMessage($e->getMessage())); self::$logger->error($e->getMessage()); } catch (RecordNotFoundException $e) { self::$logger->warn($e->getMessage()); $this->setStatusMessage(View::displayErrorMessage('Failed to load the requested item from the database!')); } $body = View::displayPageHead($this); $message = $this->getStatusMessage(); if (!empty($message)) { $body .= $message; } $body .= View::displayPageFoot($this); self::$logger->debug('<<doPOST'); return new Response(200, $body, array('Content-Type' => 'text/html')); }
/** * Handle POST requests. * * @param Alpha\Util\Http\Request $request * * @return Alpha\Util\Http\Response * * @throws Alpha\Exception\SecurityException * @throws Alpha\Exception\IllegalArguementException * * @since 1.0 */ public function doPOST($request) { self::$logger->debug('>>doPOST($request=[' . var_export($request, true) . '])'); $params = $request->getParams(); try { // check the hidden security fields before accepting the form POST data if (!$this->checkSecurityFields()) { throw new SecurityException('This page cannot accept post data from remote servers!'); } if (isset($params['clearTaggedClass']) && $params['clearTaggedClass'] != '') { try { self::$logger->info('About to start rebuilding the tags for the class [' . $params['clearTaggedClass'] . ']'); $startTime = microtime(true); $record = new $params['clearTaggedClass'](); $records = $record->loadAll(); self::$logger->info('Loaded all of the active records (elapsed time [' . round(microtime(true) - $startTime, 5) . '] seconds)'); ActiveRecord::begin(); $tag = new Tag(); $tag->deleteAllByAttribute('taggedClass', $params['clearTaggedClass']); self::$logger->info('Deleted all of the old tags (elapsed time [' . round(microtime(true) - $startTime, 5) . '] seconds)'); $this->regenerateTagsOnRecords($records); self::$logger->info('Saved all of the new tags (elapsed time [' . round(microtime(true) - $startTime, 5) . '] seconds)'); self::$logger->action('Tags recreated on the [' . $params['clearTaggedClass'] . '] class'); ActiveRecord::commit(); $this->setStatusMessage(View::displayUpdateMessage('Tags recreated on the ' . $record->getFriendlyClassName() . ' class.')); self::$logger->info('Tags recreated on the [' . $params['clearTaggedClass'] . '] class (time taken [' . round(microtime(true) - $startTime, 5) . '] seconds).'); } catch (AlphaException $e) { self::$logger->error($e->getMessage()); ActiveRecord::rollback(); } ActiveRecord::disconnect(); return $this->doGET($request); } elseif (isset($params['ActiveRecordType']) && isset($params['ActiveRecordOID'])) { $ActiveRecordType = urldecode($params['ActiveRecordType']); $ActiveRecordOID = $params['ActiveRecordOID']; if (class_exists($ActiveRecordType)) { $record = new $ActiveRecordType(); } else { throw new IllegalArguementException('No ActiveRecord available to display tags for!'); } if (isset($params['saveBut'])) { try { $record->load($ActiveRecordOID); $tags = $record->getPropObject('tags')->getRelatedObjects(); ActiveRecord::begin(); foreach ($tags as $tag) { $tag->set('content', Tag::cleanTagContent($params['content_' . $tag->getID()])); $tag->save(); self::$logger->action('Saved tag ' . $tag->get('content') . ' on ' . $ActiveRecordType . ' instance with OID ' . $ActiveRecordOID); } // handle new tag if posted if (isset($params['NewTagValue']) && trim($params['NewTagValue']) != '') { $newTag = new Tag(); $newTag->set('content', Tag::cleanTagContent($params['NewTagValue'])); $newTag->set('taggedOID', $ActiveRecordOID); $newTag->set('taggedClass', $ActiveRecordType); $newTag->save(); self::$logger->action('Created a new tag ' . $newTag->get('content') . ' on ' . $ActiveRecordType . ' instance with OID ' . $ActiveRecordOID); } ActiveRecord::commit(); $this->setStatusMessage(View::displayUpdateMessage('Tags on ' . get_class($record) . ' ' . $record->getID() . ' saved successfully.')); return $this->doGET($request); } catch (ValidationException $e) { /* * The unique key has most-likely been violated because this BO is already tagged with this * value. */ ActiveRecord::rollback(); $this->setStatusMessage(View::displayErrorMessage('Tags on ' . get_class($record) . ' ' . $record->getID() . ' not saved due to duplicate tag values, please try again.')); return $this->doGET($request); } catch (FailedSaveException $e) { self::$logger->error('Unable to save the tags of id [' . $params['ActiveRecordOID'] . '], error was [' . $e->getMessage() . ']'); ActiveRecord::rollback(); $this->setStatusMessage(View::displayErrorMessage('Tags on ' . get_class($record) . ' ' . $record->getID() . ' not saved, please check the application logs.')); return $this->doGET($request); } ActiveRecord::disconnect(); } } else { return parent::doPOST($request); } } catch (SecurityException $e) { $this->setStatusMessage(View::displayErrorMessage($e->getMessage())); self::$logger->warn($e->getMessage()); } catch (IllegalArguementException $e) { self::$logger->error($e->getMessage()); } catch (RecordNotFoundException $e) { self::$logger->warn($e->getMessage()); $this->setStatusMessage(View::displayErrorMessage('Failed to load the requested item from the database!')); } self::$logger->debug('<<doPOST'); }
/** * Commits (saves) all of the new and modified (dirty) objects in the unit of work to the database. * * @throws FailedUnitCommitException * * @since 1.0 */ public function commit() { self::$logger->debug('>>commit()'); if (method_exists($this, 'before_commit_callback')) { $this->before_commit_callback(); } ActiveRecord::begin(); $newObjects = $this->getNewObjects(); $count = count($newObjects); for ($i = 0; $i < $count; ++$i) { try { $newObjects[$i]->save(); } catch (FailedSaveException $e) { throw new FailedUnitCommitException($e->getMessage()); self::$logger->error('Failed to save new object of type [' . get_class($newObjects[$i]) . '], aborting...'); $this->abort(); return; } catch (LockingException $e) { throw new FailedUnitCommitException($e->getMessage()); self::$logger->error('Failed to save new object of type [' . get_class($newObjects[$i]) . '], aborting...'); $this->abort(); return; } } $dirtyObjects = $this->getDirtyObjects(); $count = count($dirtyObjects); for ($i = 0; $i < $count; ++$i) { try { $dirtyObjects[$i]->save(); } catch (FailedSaveException $e) { throw new FailedUnitCommitException($e->getMessage()); self::$logger->error('Failed to save OID [' . $dirtyObjects[$i]->getID() . '] of type [' . get_class($dirtyObjects[$i]) . '], aborting...'); $this->abort(); return; } catch (LockingException $e) { throw new FailedUnitCommitException($e->getMessage()); self::$logger->error('Failed to save OID [' . $dirtyObjects[$i]->getID() . '] of type [' . get_class($dirtyObjects[$i]) . '], aborting...'); $this->abort(); return; } } try { ActiveRecord::commit(); $this->clearUnitOfWorkAttributes(); if (method_exists($this, 'after_commit_callback')) { $this->after_commit_callback(); } self::$logger->debug('<<commit'); } catch (FailedSaveException $e) { throw new FailedUnitCommitException('Failed to commit the transaction, error is [' . $e->getMessage() . ']'); self::$logger->debug('<<commit'); } }
/** * Testing that a BO attached to a controller that contains tags will have those tags mapped to the controller's keywords. * * @since 1.0 */ public function testTagsMapToMetaKeywords() { ActiveRecord::begin(); $this->article->save(); ActiveRecord::commit(); $tags = $this->article->getPropObject('tags')->getRelatedObjects(); $found = false; foreach ($tags as $tag) { if ($tag->get('content') == 'unittestarticle') { $found = true; break; } } $this->assertTrue($found, 'Testing the Tag::tokenize method returns a tag called "unittestarticle"'); $this->controller->setRecord($this->article); $this->assertEquals('unittestarticle,unittestarticletagone,unittestarticletagtwo', $this->controller->getKeywords(), 'Testing that a BO attached to a controller that contains tags will have those tags mapped to the controller\'s keywords'); }
/** * Note that SQLite 3.6.19 is requrired for foreign key support. * * (non-PHPdoc) * * @see Alpha\Model\ActiveRecordProviderInterface::createForeignIndex() */ public function createForeignIndex($attributeName, $relatedClass, $relatedClassAttribute, $indexName = null) { self::$logger->info('>>createForeignIndex(attributeName=[' . $attributeName . '], relatedClass=[' . $relatedClass . '], relatedClassAttribute=[' . $relatedClassAttribute . '], indexName=[' . $indexName . ']'); /* * High-level approach * * 1. Rename the source table to [tablename]_temp * 2. Create a new [tablename] table, with the new FK in place. * 3. Copy all of the data from [tablename]_temp to [tablename]. * 4. Drop [tablename]_temp. */ try { ActiveRecord::begin($this->BO); // rename the table to [tablename]_temp $query = 'ALTER TABLE ' . $this->BO->getTableName() . ' RENAME TO ' . $this->BO->getTableName() . '_temp;'; $this->BO->setLastQuery($query); self::getConnection()->query($query); self::$logger->info('Renamed the table [' . $this->BO->getTableName() . '] to [' . $this->BO->getTableName() . '_temp]'); // now create the new table with the FK in place $record = new $relatedClass(); $tableName = $record->getTableName(); $this->foreignKeys[$attributeName] = array($tableName, $relatedClassAttribute); $this->makeTable(); self::$logger->info('Made a new copy of the table [' . $this->BO->getTableName() . ']'); // copy all of the old data to the new table $query = 'INSERT INTO ' . $this->BO->getTableName() . ' SELECT * FROM ' . $this->BO->getTableName() . '_temp;'; $this->BO->setLastQuery($query); self::getConnection()->query($query); self::$logger->info('Copied all of the data from [' . $this->BO->getTableName() . '] to [' . $this->BO->getTableName() . '_temp]'); // finally, drop the _temp table and commit the changes $this->BO->dropTable($this->BO->getTableName() . '_temp'); self::$logger->info('Dropped the table [' . $this->BO->getTableName() . '_temp]'); ActiveRecord::commit($this->BO); } catch (Exception $e) { ActiveRecord::rollback($this->BO); throw new FailedIndexCreateException('Failed to create the index [' . $attributeName . '] on [' . $this->BO->getTableName() . '], error is [' . $e->getMessage() . '], query [' . $this->BO->getLastQuery() . ']'); } self::$logger->info('<<createForeignIndex'); }