/**
  * @param CheckAction $action
  */
 public function perform(CheckAction $action)
 {
     $parser = new Parser();
     foreach ($this->getFiles($action->getBasePath()) as $file) {
         try {
             $parser->parse(file_get_contents($file->getRealPath()));
         } catch (ParseException $e) {
             $action->addError('parser', $e->getMessage(), ['file_name' => $file->getFileName(), 'file_path' => $file->getPathName(), 'training' => $this->getCurrentTraining($file), 'discriminator' => 'training']);
             $action->addSkip('file', $file->getFileName());
         }
     }
 }
 /**
  * @param CheckAction $action
  */
 public function perform(CheckAction $action)
 {
     $files = $this->getFiles($action->getBasePath());
     $parser = new Parser();
     foreach ($files as $file) {
         if (in_array($file->getFileName(), $action->getSkip('file'))) {
             continue;
         }
         $data = $parser->parse(file_get_contents($file->getRealPath()));
         $context = ['file_name' => $file->getFileName(), 'file_path' => $file->getPathName(), 'discriminator' => 'category', 'training' => $this->getCurrentTraining($file)];
         if (!is_array($data)) {
             $action->addError('structure', 'Output must be type of array, given ' . gettype($data), $context);
             $action->addSkip('category', $file->getFileName());
             continue;
         }
         if (empty($data)) {
             $action->addError('structure', 'Resource file cannot be empty', $context);
             continue;
         }
         //Structure without data can pass
         if (1 === count($data) && isset($data['category'])) {
             $action->addSkip('category', $data['category']);
             continue;
         }
         if (empty($data['category'])) {
             $action->addError('structure', 'Cannot have empty label', $context);
         }
         if (!isset($data['questions']) || empty($data['questions'])) {
             $action->addError('structure', 'Missing questions', $context);
             $action->addSkip('category', $data['category']);
             continue;
         }
         foreach ($data['questions'] as $questionNode) {
             $context['discriminator'] = 'question';
             if (!isset($questionNode['question'])) {
                 $action->addError('structure', 'Required a question', $context);
                 continue 2;
             }
             if (!is_string($questionNode['question'])) {
                 $action->addError('structure', 'Should be a string', $context);
                 continue 2;
             }
             if (empty($questionNode['question'])) {
                 $action->addError('structure', 'Cannot have empty label', $context);
             }
             if (!isset($questionNode['answers']) || count($questionNode['answers']) <= 1) {
                 $action->addError('structure', 'Must contains at least 2 answers to be valid', $context);
                 continue 2;
             }
             $good = 0;
             foreach ($questionNode['answers'] as $answerNode) {
                 $context['discriminator'] = 'answer';
                 if (!isset($answerNode['value']) || !is_string($answerNode['value'])) {
                     $action->addError('structure', 'Missing or invalid [value] field', $context);
                     continue 3;
                 }
                 if (empty($answerNode['value'])) {
                     $action->addError('structure', sprintf('Cannot have empty label, related question : "%s"', $questionNode['question']), $context);
                 }
                 if (!isset($answerNode['correct']) || !is_bool($answerNode['correct'])) {
                     $action->addError('structure', 'Missing or invalid [correct] field', $context);
                     continue 3;
                 }
                 if (true === $answerNode['correct']) {
                     $good++;
                 }
             }
             if (0 === $good) {
                 $action->addError('structure', 'Must have at least one valid answer', $context);
                 continue 2;
             }
         }
     }
 }
 /**
  * @param CheckAction $action
  *
  * @return Finder
  */
 public function perform(CheckAction $action)
 {
     $finder = new Finder();
     $files = $finder->in($action->getBasePath() . '/*')->name('context.yml');
     $parser = new Parser();
     $collector = [];
     foreach ($files as $context) {
         $errorContext = ['file_name' => $context->getFileName(), 'file_path' => $context->getPathName(), 'discriminator' => 'context', 'training' => $this->getCurrentTraining($context)];
         try {
             $contextData = $parser->parse(file_get_contents($context->getRealPath()));
         } catch (ParseException $e) {
             $action->addError('parser', $e->getMessage(), $errorContext);
             $action->addSkip('file', $context->getFileName());
             continue;
         }
         $mandatory = ['name', 'icons', 'label', 'availableLanguages', 'customize', 'threshold', 'defaults'];
         foreach ($mandatory as $key) {
             if (!isset($contextData[$key])) {
                 $action->addError('structure', sprintf('Missing required key "%s"', $key), $errorContext);
             }
         }
         if (isset($contextData['name']) && isset($contextData['label'])) {
             $collector[$this->getCurrentTraining($context) . '=name'][] = $contextData['name'];
             $collector[$this->getCurrentTraining($context) . '=label'][] = $contextData['label'];
         }
         foreach ($contextData as $key => $value) {
             if (in_array($key, ['name', 'label'])) {
                 if (!is_string($key) || empty($key)) {
                     $action->addError('structure', sprintf('Key "%s" must be type of "string" and not empty', $key), $errorContext);
                 }
                 continue;
             }
             if ('availableLanguages' === $key) {
                 if (!is_array($value)) {
                     $action->addError('structure', sprintf('Key "%s" must be type of array with at least one element', $key), $errorContext);
                     continue;
                 }
                 if (0 === count($value)) {
                     $action->addError('structure', sprintf('Key "%s" must contain at least one element', $key), $errorContext);
                     continue;
                 }
                 foreach ($value as $vlKey => $vlValue) {
                     if (!is_string($vlValue)) {
                         $action->addError('structure', sprintf('Child %s of key "%s" must be a string, given "%s"', $vlKey, $key, gettype($vlValue)), $errorContext);
                         continue 2;
                     }
                 }
             }
             if ('availableLevels' === $key && null !== $value) {
                 foreach ($value as $vlKey => $vlValue) {
                     if (!is_string($vlValue)) {
                         $action->addError('structure', $errorContext);
                         continue 2;
                     }
                 }
             }
             if ('customize' === $key) {
                 $requiredKeys = ['exclude_categories', 'number_of_questions'];
                 foreach ($requiredKeys as $vlValue) {
                     if (!array_key_exists($vlValue, $value)) {
                         $action->addError('structure', sprintf('Mandatory key "%s" missing for parameter "%s"', $vlValue, $key), $errorContext);
                         continue 2;
                     }
                     if (!is_bool($value[$vlValue])) {
                         $action->addError('structure', sprintf('Child "%s" of "%s" must be type of "bool", given "%s"', $vlValue, $key, gettype($value)), $errorContext);
                         continue 2;
                     }
                 }
             }
             if ('threshold' === $key && null !== $value) {
                 if (!is_array($value) || empty($value)) {
                     $action->addError('structure', sprintf('Key "%s" must be type of array with at least one element, given "%s"', $key, gettype($value)), $errorContext);
                     continue;
                 }
                 foreach ($value as $vlKey => $vlValue) {
                     if (!is_string($vlKey) || !is_int($vlValue)) {
                         $action->addError('structure', sprintf('Threshold must be like "(string) level_id => (int) score_trigger, given %s => %s"', $vlKey, $vlValue), $errorContext);
                     }
                 }
             }
             if ('defaults' === $key) {
                 if (!is_array($value)) {
                     $action->addError('structure', sprintf('Key "%s" must be type of array, given "%s"', $key, gettype($value)), $errorContext);
                     continue;
                 }
                 $childrenRequired = ['language', 'questions_peer_category'];
                 foreach ($childrenRequired as $mandatoryKey) {
                     if (!array_key_exists($mandatoryKey, $value)) {
                         $action->addError('structure', sprintf('Child %s of %s is required', $mandatoryKey, $key), $errorContext);
                     }
                 }
                 foreach ($value as $vlKey => $vlValue) {
                     if (!in_array($vlKey, $childrenRequired)) {
                         $action->addError('structure', sprintf('Unknown %s key', $vlKey), $errorContext);
                         continue 2;
                     }
                     if ('language' === $vlKey) {
                         if (!is_string($vlValue)) {
                             if (!in_array($vlKey, $childrenRequired)) {
                                 $action->addError('structure', sprintf('Child %s of %s must be type of "string", given %s', $vlKey, $key, gettype($value)), $errorContext);
                             }
                         }
                         continue 2;
                     }
                     if ('questions_peer_category' === $vlKey) {
                         if (!is_int($vlValue)) {
                             $action->addError('structure', sprintf('Child %s of %s must be type of "integer", given %s', $vlKey, $key, gettype($value)), $errorContext);
                         }
                         continue 2;
                     }
                 }
             }
         }
     }
     foreach ($collector as $properties => $elements) {
         list($training, $property) = explode('=', $properties);
         foreach (array_count_values($elements) as $count) {
             if ($count > 1) {
                 $action->addError('integrity', sprintf('A training has already the same %s', $property), ['file_name' => 'context.yml', 'training' => $training]);
             }
         }
     }
 }
 /**
  * @param CheckAction $action
  */
 public function perform(CheckAction $action)
 {
     $files = $this->getFiles($action->getBasePath());
     $parser = new Parser();
     $collector = ['category' => [], 'question' => [], 'answer' => []];
     foreach ($files as $file) {
         if (in_array($file->getFileName(), $action->getSkip('file'))) {
             continue 1;
         }
         $data = $parser->parse(file_get_contents($file->getRealPath()));
         if (in_array($data['category'], $action->getSkip('category'))) {
             continue 1;
         }
         $trainingName = $this->getCurrentTraining($file);
         $identifier = implode('=', [$trainingName, $file->getFileName()]);
         $collector['category'][$identifier] = $data['category'];
         foreach ($data['questions'] as $questionNode) {
             if (in_array($questionNode['question'], $action->getSkip('question'))) {
                 continue 2;
             }
             $collector['question'][$identifier][] = $questionNode['question'];
             foreach ($questionNode['answers'] as $answerNode) {
                 if (in_array($answerNode['value'], $action->getSkip('answer'))) {
                     continue 3;
                 }
                 $collector['answer'][$identifier][$questionNode['question']][] = $answerNode['value'];
             }
         }
     }
     foreach ($collector as $type => $node) {
         if ($type === 'category') {
             //flatten
             foreach (array_count_values($collector[$type]) as $category => $count) {
                 if ($count > 1) {
                     $affected = array_keys($collector[$type], $category);
                     $errorFiles = [];
                     foreach ($affected as $value) {
                         list($training, $file) = explode('=', $value);
                         $errorFiles[] = $file;
                     }
                     $action->addError('integrity', sprintf('Category "%s" was find several times', $category), ['file_name' => $errorFiles, 'discriminator' => 'category', 'training' => $training]);
                 }
             }
         }
         if ($type === 'question') {
             //nested
             foreach ($node as $context => $questionsNodes) {
                 list($training, $fileName) = explode('=', $context);
                 foreach (array_count_values($questionsNodes) as $question => $count) {
                     if ($count > 1) {
                         $action->addError('integrity', sprintf('Question "%s" was find several times', $question), ['file_name' => $fileName, 'discriminator' => 'question', 'training' => $training]);
                     }
                 }
             }
         }
         if ($type === 'answer') {
             //nested
             foreach ($node as $context => $answerNode) {
                 list($training, $fileName) = explode('=', $context);
                 foreach ($answerNode as $question => $answers) {
                     foreach (array_count_values($answers) as $answer => $count) {
                         if ($count > 1) {
                             $action->addError('integrity', sprintf('Answer "%s" was find several times for question "%s"', $answer, $question), ['file_name' => $fileName, 'discriminator' => 'answer', 'training' => $training]);
                         }
                     }
                 }
             }
         }
     }
 }