Project S: what Rateo prints
The Rateo engine, run on Project S, a production Symfony application. Every number below comes from the engine's output, which is linked in full at the end.
Names that identify the project or its authors are replaced by stand ins of the same length, so every number on this page is what the engine prints for the original code.
- License
- proprietary
- Engine
2026.10.12- Rules
2026.10.7-provisional- Ran on
- 2026-10-16
- Zip SHA-256
9c7b98dd70816f3f3c73d7060ae9aeb263b8441a32e88037d0c17e2cf234b7ba- Command
build/rateo project-s --cache=none
from the folder the zip was extracted into
At a glance
- Files analysed
- 1,048
- Findings
- 973
- Errors
- 31
- Warnings
- 942
platform PHP: Symfony (composer.json requires symfony/framework-bundle; bin/console)
not analysed: 3326 files (JavaScript 1398, SVG 521, CSS 372, Twig 316, YAML 193, binary 126, Text 67, map 60, XML 51, Handlebars 46, HTML 40, Markdown 37, SCSS 34, JSON 29, unknown 9, Ignore List 7, Shell 5, JSON with Comments 3, Git Attributes 2, NPM Config 2, ApacheConf 1, Dockerfile 1, EditorConfig 1, Nginx 1, conf 1, dist 1, flow 1, lock 1)
Folders and files not analysed, by reason: TooLarge 1.
What it checks
Checked today
- Size: long files, classes and functions
- Complexity: functions and file level code with too many paths
- Naming: mixed styles in a file, generic, one letter and very long names
- Duplication: blocks repeated inside a file, even with renamed variables
- Security:
eval, shell commands, unserialize and includes built from data, SQL with values pasted in, request input never sanitized, output never escaped
Not checked yet
- Symfony rules: best practices for controllers, services and templates
- Security checks: hard coded secrets
- Tests: whether there are any, and how much test code there is next to the app code
- Repository hygiene:
.gitignore, a lockfile, no committed vendor/ or .env, a README with setup steps
The security checks read one call or statement at a time and never follow a value through variables, so they show where to look, not proof of a hole. A long or branchy function is common in a large, mature project; each finding is a place worth a closer look, not a judgement of the code as a whole.
Findings by check
A value equal to a limit is no finding.
Where they concentrate
The 10 files with the most findings
Findings per top level folder
Grades
AOverall: 91 out of 100
3 of 5 metrics graded
round((3 × 99Complexity+2 × 76Duplication+1 × 98Naming) ÷ 6) = 91
Weights: Complexity 3, Duplication 2, Naming 1. Size and Security are not graded, so they are left out and the other weights are rescaled.
A summary of the grades below, which you can recompute. Not a pass mark, and not a hiring decision.
The table shows how many files got each letter. A file with nothing to judge for a metric gets no grade for it. The whole project column pools every file's grade, so a file with more code to judge counts for more. The overall above weights those whole project grades. In the full engine output these are CodeLength, CyclomaticComplexity, Duplication, NamingConvention and Security.
Security
Findings only, never a grade: a wrong security grade would hurt more than none. A finding the author already silenced with a phpcs comment counts as suppressed, apart from Errors and Warnings, so you can tell reviewed code from unreviewed code.
Where to look first
Up to 10 places, Errors first, then Warnings, then by path and line. An Error means request input reaches the call or the output directly.
#1 project-s/src/Infrastructure/Persistence/Session/Repository/CartRepository.php:20
| 20 | return unserialize($cart); |
| 21 | } |
| 22 | |
| 23 | return null; |
| 24 | } |
| 25 | |
| 26 | public function findProductByUuid( string $uuid ): ?CartItem |
| 27 | { |
| 28 | $cart = $this->current(); |
| 29 | |
#2 project-s/src/Kernel.php:23
| 23 | (require $path)($container->withPath($path), $this); |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | protected function configureRoutes(RoutingConfigurator $routes): void |
| 28 | { |
| 29 | $routes->import('../config/{routes}/'.$this->environment.'/*.yaml'); |
| 30 | $routes->import('../config/{routes}/*.yaml'); |
| 31 | |
| 32 | if (is_file(\dirname(__DIR__).'/config/routes.yaml')) { |
#3 project-s/src/Kernel.php:35
| 35 | (require $path)($routes->withPath($path), $this); |
| 36 | } |
| 37 | } |
| 38 | } |
The 10 worst places
Security findings are listed in their own section above. A place is a file and a line, so a function that is both too long and too complex shows once, with both findings. Places rank by their worst finding: errors first, then by how far the measured value goes beyond its limit. Each message is the engine's own, word for word.
#1 project-s/src/Infrastructure/Symfony/Http/Controller/Web/IndexController.php:39
Error length.function
IndexController::index has 213 lines in its body, above 100
Warning complexity.function
IndexController::index has a cyclomatic complexity of 18, moderate risk (above 10): each of its 18 paths needs its own test, which makes it hard to follow and to change safely
| 39 | public function index(Request $request) |
| 40 | { |
| 41 | |
| 42 | |
| 43 | // ROLE_COLLAB_WIKYCASA |
| 44 | if ($this->security->isGranted('ROLE_COLLAB_WIKYCASA')) { |
| 45 | // Recupera l'utente per il ruolo ROLE_COLLAB_WIKYCASA |
| 46 | $query = new FindSecurityUserByUuidQuery($this->getUser()->getUuid()->value()); |
| 47 | $securityUser = $this->commandBus->handle($query); |
| 48 | |
#2 project-s/src/Infrastructure/Persistence/Doctrine/Repository/SecurityUserRepository.php:217
Error length.function
SecurityUserRepository::findByMeta has 200 lines in its body, above 100
Error complexity.function
SecurityUserRepository::findByMeta has a cyclomatic complexity of 22, high risk (above 10): each of its 22 paths needs its own test, which makes it hard to follow and to change safely
| 217 | public function findByMeta(array $meta = []): array |
| 218 | { |
| 219 | $queryParams = []; |
| 220 | |
| 221 | // using DBAL query here for performances purposes |
| 222 | $query = "SELECT |
| 223 | su.uuid, |
| 224 | su.email, |
| 225 | su.is_active, |
| 226 | su.username, |
#3 project-s/src/Infrastructure/Symfony/Form/Type/Web/EditUserType.php:24
| 24 | public function buildForm(FormBuilderInterface $builder, array $options) |
| 25 | { |
| 26 | $builder |
| 27 | ->add('businessName', TextType::class, [ |
| 28 | 'label' => $this->translator->trans('user.form.businessName'), |
| 29 | 'required' => false, |
| 30 | 'attr' => ['class' => 'form-control'], |
| 31 | ]) |
| 32 | ->add('name', TextType::class, [ |
| 33 | 'label' => $this->translator->trans('user.form.name'), |
#4 project-s/src/Application/CommandHandler/HandleJobAcceptanceCommandHandler.php:66
Error length.function
HandleJobAcceptanceCommandHandler::handle has 160 lines in its body, above 100
Warning complexity.function
HandleJobAcceptanceCommandHandler::handle has a cyclomatic complexity of 19, moderate risk (above 10): each of its 19 paths needs its own test, which makes it hard to follow and to change safely
| 66 | public function handle(HandleJobAcceptanceCommand $command) |
| 67 | { |
| 68 | // get admin email |
| 69 | $adminEmail = $this->adminMetaRepository->get('email') ?? $_SERVER['ADMIN_MAIL'] ?? 'direzione@persononebrandco.com'; |
| 70 | |
| 71 | /** @var JobAcceptance $acceptance */ |
| 72 | if(!$acceptance = $this->acceptanceRepository->findByUuid($command->getAcceptanceUuid())){ |
| 73 | throw new EntityNotFoundException($this->translator->trans('general.errors.no_record_found_with_id')); |
| 74 | } |
| 75 | |
#5 project-s/src/Infrastructure/Persistence/Doctrine/DataFixtures/LanguageFixture.php:15
| 15 | public function load( ObjectManager $manager ) |
| 16 | { |
| 17 | $data = [ |
| 18 | ['English', 'en'], |
| 19 | ['Afar', 'aa'], |
| 20 | ['Abkhazian', 'ab'], |
| 21 | ['Afrikaans', 'af'], |
| 22 | [ 'Amharic', 'am'], |
| 23 | [ 'Arabic', 'ar'], |
| 24 | [ 'Assamese', 'as'], |
#6 project-s/src/Infrastructure/Symfony/Form/Type/Web/CreateUserType.php:34
| 34 | public function buildForm(FormBuilderInterface $builder, array $options) |
| 35 | { |
| 36 | $builder |
| 37 | ->add('securityRole', ChoiceType::class, [ |
| 38 | 'label' => $this->translator->trans('security.user_role'), |
| 39 | 'required' => true, |
| 40 | 'placeholder' => $this->translator->trans('general.site.select'), |
| 41 | 'attr' => ['class' => 'form-control'], |
| 42 | 'choices' => $this->getRolesArray($options['allow_super_admin']), |
| 43 | ]) |
#7 project-s/src/Infrastructure/Persistence/Doctrine/Repository/ProductRepository.php:76
Error length.function
ProductRepository::find has 136 lines in its body, above 100
Warning complexity.function
ProductRepository::find has a cyclomatic complexity of 17, moderate risk (above 10): each of its 17 paths needs its own test, which makes it hard to follow and to change safely
| 76 | public function find( array $meta = [] ) |
| 77 | { |
| 78 | // using DBAL query here for performances purposes |
| 79 | $query = "SELECT |
| 80 | p.uuid, |
| 81 | p.sku, |
| 82 | p.name, |
| 83 | p.due_date, |
| 84 | p.created_at as createdAt, |
| 85 | p.discr as productType, |
#8 project-s/src/Infrastructure/Persistence/Doctrine/Repository/JobRepository.php:315
Error length.function
JobRepository::filterByMetaQuery has 135 lines in its body, above 100
Error complexity.function
JobRepository::filterByMetaQuery has a cyclomatic complexity of 21, high risk (above 10): each of its 21 paths needs its own test, which makes it hard to follow and to change safely
| 315 | private function filterByMetaQuery(array $meta = []) |
| 316 | { |
| 317 | $query = ''; |
| 318 | $params = []; |
| 319 | |
| 320 | if(isset($meta['status'])){ |
| 321 | |
| 322 | switch ($meta['status']){ |
| 323 | case 'to_be_modified': |
| 324 | $orderStatuses = []; |
#9 project-s/src/Infrastructure/Symfony/Form/Type/Web/EditCustomerType.php:50
| 50 | public function buildForm(FormBuilderInterface $builder, array $options) |
| 51 | { |
| 52 | $builder |
| 53 | ->add('businessName', TextType::class, [ |
| 54 | 'label' => $this->translator->trans('customer.form.businessName'), |
| 55 | 'required' => true, |
| 56 | 'attr' => ['class' => 'form-control'], |
| 57 | 'constraints' => [new NotBlank()], |
| 58 | ]) |
| 59 | ->add('name', TextType::class, [ |
#10 project-s/src/Infrastructure/Symfony/Form/Type/Web/CreateCustomerType.php:50
| 50 | public function buildForm(FormBuilderInterface $builder, array $options) |
| 51 | { |
| 52 | $builder |
| 53 | ->add('security', CreateSecurityUserType::class,[ |
| 54 | 'isActive' => true |
| 55 | ]) |
| 56 | ->add('group', EntityType::class, [ |
| 57 | 'label' => $this->translator->trans('customer.form.group'), |
| 58 | 'required' => false, |
| 59 | 'attr' => ['class' => 'form-control'], |
Full engine output
All 973 findings, exactly as the engine printed them: symfony-project-s.txt (plain text).