Skip to content

[detector-report] mutable-static-state #585

Description

@jessegall

Detector: mutable-static-state

Report (why the flagged code is CORRECT and the detector is wrong):
Stylesheet::$active is the theme's role map, written once at application boot by ViewServiceProvider from workflows.theme and guarded so a second, different choice throws ThemeAlreadyChosen. It is read by Stylesheet::of from static composition and stylesheet lookups that hold no collaborator. It is boot-time configuration with a single writer, not state that changes while the application runs.

Cleanest design the reporter can conceive:
A role map bound once at boot by the one service provider that reads the theme config, refusing a second different binding, and resolved by a static lookup, which is the flagged code.

⚖️ Maintainer litmus: a valid detector-report needs the flagged code to ALREADY BE the
cleanest design. If the design above differs from the flagged code at all, THAT design is
the owed fix — close this report; the fix is still owed.

Where: src/View/Stylesheets/Stylesheet.php:12-37

Code (src/View/Stylesheets/Stylesheet.php:12-37):

   9      /**
  10       * @var array<class-string<PrimitiveRole|CompositionRole>, class-string<PrimitiveRole|CompositionRole>>
  11       */12      private static array $active = [];
→ 1314      /**
→ 15       * @param  array<class-string<PrimitiveRole|CompositionRole>, class-string<PrimitiveRole|CompositionRole>>  $roles
→ 16       */17      public static function use(array $roles): void
18      {
 19          if (self::$active !== [] && self::$active !== $roles)
→ 20          {
→ 21              throw ThemeAlreadyChosen::for(array_keys($roles));
→ 22          }
→ 2324          self::$active = $roles;
→ 25      }
→ 2627      /**
→ 28       * @template T of PrimitiveRole|CompositionRole
→ 29       *
→ 30       * @param  class-string<T>  $role
→ 31       * @return class-string<T>
→ 32       */33      public static function of(string $role): string34      {
→ 35          return self::$active[$role] ?? $role;
→ 36      }
→ 37  }

Where: src/Laravel/ViewServiceProvider.php:95

Code (src/Laravel/ViewServiceProvider.php:95):

   92  
   93      public function register(): void
   94      {
→  95          Stylesheet::use($this->app['config']->get('workflows.theme', []));
   96  
   97          foreach (self::DRIVERS as $contract => $driver)
   98          {
   99              $this->app->scoped($driver);
  100              $this->app->bind($contract, $driver);
  101          }
  102  
  103          $this->app->singleton(CompiledScenes::class, static fn ($app) => new CompiledScenes($app->basePath()));
  104          $this->app->scoped(Shapes::class, static fn ($app) => new Shapes($app->basePath()));
  105          $this->app->singleton(RenderedScenes::class, static fn ($app) => new RenderedScenes($app->basePath()));
  106  
  107          $this->app->scoped(ClientState::class, static fn ($app) => $app->make(Navigation::class)->hasDestination()
  108              ? ClientState::none()
  109              : ClientState::from($app->make(Request::class)));
  110  
  111          $this->app->scoped(Pipes::class);
  112          $this->app->scoped(PipeTimings::class);
  113  
  114          $this->app->scoped(SceneResponse::class, static function ($app) {
  115              $request = $app->make(Request::class);
  116  
  117              return $request->wantsJson() || $request->boolean('json')
  118                  ? $app->make(AsJson::class)
  119                  : $app->make(AsPage::class);

Filed via commandments report from a consumer project.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions