Source of file Answer.php
Size: 10,198 Bytes - Last Modified: 2021-12-24T06:40:50+00:00
/var/www/docs.ssmods.com/process/src/src/Model/Answer.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 | <?php namespace CodeCraft\Pathfinder\Model; use CodeCraft\Pathfinder\GridField\GridFieldConfig_CustomRelationEditor; use SilverStripe\Control\HTTPResponse; use SilverStripe\Forms\DropdownField; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter; use SilverStripe\Forms\GridField\GridFieldAddNewButton; use SilverStripe\Forms\GridField\GridFieldFilterHeader; use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\TextField; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\HasManyList; use SilverStripe\ORM\ManyManyList; use SilverStripe\Versioned\Versioned; /** * An answer, presented to users to progress to the next step of a Pathfinder * * @property string Answer * @property int Sort * @method Question|null Question() * @method HasManyList|Choice[] Choices() * @method ManyManyList|Question[] NextQuestions() */ class Answer extends DataObject { /** * @var array */ private static $extensions = [ Versioned::class, ]; /** * @var string */ private static $table_name = 'PathfinderAnswer'; /** * @var array */ private static $db = [ 'Sort' => 'Int', ]; /** * @var array */ private static $has_one = [ 'Question' => Question::class, ]; /** * @var array */ private static $has_many = [ 'Choices' => Choice::class, ]; /** * @var array */ private static $many_many = [ 'NextQuestions' => Question::class, ]; /** * @var array */ private static $owns = [ 'Choices', ]; /** * @var array */ private static $summary_fields = [ 'AnswerSummary' => 'Answer', 'Choices.Count' => 'No. of choices', 'GoesToSummary' => 'Goes to', ]; /** * @var string */ private static $default_sort = 'Sort'; /** * @var string */ private static $go_to_results_title = 'Results'; /** * @var DropdownField */ protected $goesToField; /** * {@inheritDoc} */ public function onAfterDelete() { // Establish whether we should clean up $cleanUp = true; // Allow implementors to apply alternative scenarios $this->invokeWithExtensions('updateCleanUp', $cleanUp); if ($cleanUp) { $this->Choices()->removeAll(); } parent::onAfterDelete(); } /** * {@inheritDoc} */ public function populateDefaults() { parent::populateDefaults(); if (!$this->Choices()->count()) { // Create a default choice, to avoid an empty view in the CMS $choice = Choice::create(); $choice->ChoiceText = 'None of the above'; $this->Choices()->add($choice); } } /** * {@inheritDoc} */ public function getCMSFields() { // Manipulate fields ahead of extension manipulations (such as Fluent) $this->beforeUpdateCMSFields(function (FieldList $fields) { $fields->removeByName([ 'Sort', 'QuestionID', 'Terms', 'NextQuestions', ]); // Options field /** @var GridField $choicesField */ $choicesField = $fields->dataFieldByName('Choices'); if ($choicesField) { $config = GridFieldConfig_CustomRelationEditor::create('Add Choice', true) ->setDisplayFields([ 'ChoiceText' => [ 'title' => 'Choice', 'callback' => function($record, $column, $grid) { return TextField::create($column); }, ], ]); $choicesField->setConfig($config); // Remove the tab and existing field placement $fields->removeByName('Choices'); // Re-add the field $fields->addFieldToTab('Root.Main', $choicesField); } // Goes to (next question) field $goesToField = $this->getGoesToField() ->setValue($this->getNextQuestion() ? $this->getNextQuestion()->ID : null); $fields->insertBefore('Choices', $goesToField); if (!$this->isInDB()) { // No options message $fields->addFieldToTab( 'Root.Main', LiteralField::create( 'NoRecordMsg', '<div class="alert alert-info">' . 'Answer must be created, before Choices can be added.' . '</div>' ) ); } if (!$this->Choices()->count()) { // No options message $fields->addFieldToTab( 'Root.Main', LiteralField::create( 'NoAnswersMsg', '<div class="alert alert-warning">' . 'This Answer will not be displayed until it has at least one Choices' . '</div>' ) ); } }); return parent::getCMSFields(); } /** * A title for the CMS to use * * @return string */ public function getTitle() { /** @var DBText $field */ $field = DBField::create_field('Text', "Answer: {$this->getAnswerSummary()}"); return $field->LimitCharactersToClosestWord(30); } /** * @return Pathfinder|null */ public function getPathfinder() { return $this->Question() ? $this->Question()->Pathfinder() : null; } /** * The first Question in the NextQuestions relation * * @return Question|null */ public function getNextQuestion() { /** @var Question|null $question */ $question = $this->NextQuestions()->first(); return $question; } /** * @return string */ public function getGoesToSummary() { return $this->NextQuestions()->count() ? $this->getNextQuestion()->getCMSTitle() : $this->getGoToResultsTitle(); } /** * @return DBField */ public function getAnswerSummary() { $field = DBField::create_field( 'Text', implode(' | ', $this->Choices()->column('ChoiceText')) ); return $field->LimitCharactersToClosestWord(60); } /** * @return string */ public function getGoToResultsTitle() { return $this->config()->get('go_to_results_title'); } /** * @return DropdownField */ public function getGoesToField() { if ($this->goesToField) { return $this->goesToField; } $field = DropdownField::create( 'NextQuestionID', 'Goes to' ); // Make it clear that having no next questions goes straight to results $field->setEmptyString($this->getGoToResultsTitle()); $pathfinder = $this->getPathfinder(); if (!$pathfinder || !$pathfinder->Flows()->count()) { // All questions are using the default flow $field->setDisabled(true); return $field; } $options = []; $disabledItems = []; // Add questions from the default flow $defaultFlowValue = 'Flow_Default'; $options[$defaultFlowValue] = 'Default flow'; $disabledItems[] = $defaultFlowValue; foreach ($pathfinder->Questions()->filter(['FlowID' => [null, 0]])->map('ID', 'CMSTitle') as $id => $text) { // Do this explicitly so keys are preserved $options[$id] = $text; } // Add questions per flow foreach ($pathfinder->Flows() as $flow) { $flowValue = sprintf('Flow_%s', $flow->ID); // Display the flow for easy reference, but disable it $options[$flowValue] = $flow->Title; $disabledItems[] = $flowValue; // We want the flow's questions, and to filter them to make sure they apply to the current pathfinder $questionsInFlow = $flow->Questions()->filter(['PathfinderID' => $pathfinder->ID]); foreach ($questionsInFlow->map('ID', 'CMSTitle') as $id => $text) { // Do this explicitly so keys are preserved $options[$id] = $text; } } // Set the field source $field->setSource($options); // Let's help the user avoid creating loops in the path $disabledItems = array_merge($disabledItems, $this->Question()->recursivePrecedentIDs()); $field ->setDisabledItems($disabledItems) ->setDescription('Note: All preceeding questions are disabled.'); $this->goesToField = $field; return $this->goesToField; } /** * Capture the {@see getGoesToField()}'s input and handle it * * This method is invoked by {@see Form::saveInto()} * * @param mixed $value */ public function saveNextQuestionID($value) { if (!is_numeric($value)) { // We're expecting Question IDs return; } // Coerce the value for our benefit $value = (int) $value; if ($this->NextQuestions()->count()) { // We're limiting the many_many to one for now $this->NextQuestions()->removeAll(); } if ($value <= 0) { // Nothing else to do return; } $question = Question::get()->byID($value); if (!$question) { throw new \Silverstripe\ORM\ValidationException(sprintf('Question not found with ID "%s"', $value)); } // Add the next question $this->NextQuestions()->add($question); } } |