Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

State Bridge Bundle Laravel Package

devtrw/state-bridge-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle:

    composer require devtrw/state-bridge-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Devtrw\StateBridgeBundle\DevtrwStateBridgeBundle::class => ['all' => true],
    ];
    
  2. Register JSONP Request Format (Critical for AngularJS compatibility): In config/packages/framework.yaml:

    framework:
        http_method_override: true
        allowed_http_methods: [GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH, JSONP]
    

    Create a custom request format listener (see Symfony docs) to handle jsonp requests.

  3. First Use Case: Role-Based State Activation Define states in config/packages/devtrw_state_bridge.yaml:

    devtrw_state_bridge:
        states:
            admin:
                path: /admin
                roles: [ROLE_ADMIN]
                template: admin.html.twig
            user:
                path: /user
                roles: [ROLE_USER]
                template: user.html.twig
    

    Access states via /_statebridge?callback=angularCallback (JSONP endpoint).


First Integration with AngularJS

  1. Inject the Service:

    angular.module('app').factory('StateBridge', ['$http', function($http) {
        return {
            fetchStates: function() {
                return $http.jsonp('/_statebridge', { params: { callback: 'JSON_CALLBACK' } });
            }
        };
    }]);
    
  2. Load States Dynamically:

    StateBridge.fetchStates().then(function(response) {
        angular.forEach(response.data, function(state) {
            if (state.roles.includes('ROLE_USER')) { // Check user role
                $stateProvider.state(state.name, state.config);
            }
        });
    });
    

Implementation Patterns

Core Workflow: State-Driven Frontend Routing

  1. Backend Configuration:

    • Define states in config/packages/devtrw_state_bridge.yaml with:
      • path: URL segment (e.g., /dashboard).
      • roles: Array of Symfony roles (e.g., [ROLE_EDITOR]).
      • template: Twig template path (optional, for server-side rendering).
      • config: Custom AngularJS state config (merged with defaults).
    • Example:
      devtrw_state_bridge:
          states:
              dashboard:
                  path: /dashboard
                  roles: [ROLE_USER, ROLE_ADMIN]
                  config:
                      url: /dashboard
                      templateUrl: 'app/dashboard.html'
                      controller: 'DashboardCtrl'
                      resolve:
                          data: ['DataService', function(DataService) {
                              return DataService.getDashboardData();
                          }]
      
  2. Role-Based Activation:

    • Use Symfony’s security system to filter states:
      // src/EventListener/StateBridgeListener.php
      use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
      
      class StateBridgeListener {
          public function __construct(TokenStorageInterface $tokenStorage) {
              $this->tokenStorage = $tokenStorage;
          }
      
          public function onStatesLoad(StatesLoadEvent $event) {
              $token = $this->tokenStorage->getToken();
              $roles = $token ? $token->getRoles() : [];
              $event->setStates(array_filter($event->getStates(), function($state) use ($roles) {
                  return array_intersect($state['roles'], $roles);
              }));
          }
      }
      
    • Register the listener in services.yaml:
      services:
          App\EventListener\StateBridgeListener:
              tags:
                  - { name: kernel.event_listener, event: devtrw_state_bridge.states_load, method: onStatesLoad }
      
  3. Dynamic Template Injection:

    • For hybrid rendering (SSR + SPA), inject Twig templates into AngularJS:
      // In your AngularJS app
      $http.get('/_statebridge/template/dashboard').then(function(response) {
          $compile(response.data)($scope); // Inject into DOM
      });
      

Integration Tips

  1. AngularJS UI-Router Integration:

    • Use ui-router’s stateRegistry to dynamically register states:
      angular.module('app').run(['$stateRegistry', 'StateBridge', function($stateRegistry, StateBridge) {
          StateBridge.fetchStates().then(function(states) {
              states.forEach(function(state) {
                  $stateRegistry.state(state.name, state.config);
              });
          });
      }]);
      
  2. Symfony Security Integration:

    • Combine with Symfony’s voter system for fine-grained access control:
      // src/Voter/StateVoter.php
      class StateVoter extends AbstractVoter {
          public function supports(string $attribute, $subject): bool {
              return $attribute === 'ACCESS_STATE' && $subject instanceof State;
          }
      
          protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool {
              return in_array($subject->getRole(), $token->getRoles());
          }
      }
      
  3. Caching States:

    • Cache the filtered states in Symfony’s cache system:
      # config/packages/devtrw_state_bridge.yaml
      devtrw_state_bridge:
          cache_enabled: true
          cache_lifetime: 3600 # 1 hour
      

Gotchas and Tips

Pitfalls

  1. JSONP CORS Issues:

    • If using JSONP, ensure your server allows cross-origin requests. Add to .htaccess:
      Header set Access-Control-Allow-Origin "*"
      
    • For production, restrict origins in Symfony’s EventListener:
      $response->headers->set('Access-Control-Allow-Origin', ['https://yourdomain.com']);
      
  2. State Name Collisions:

    • Avoid naming conflicts between AngularJS and Symfony routes. Prefix states:
      states:
          app_dashboard:
              path: /dashboard
      
    • In AngularJS:
      $state.go('app_dashboard');
      
  3. Template Path Resolution:

    • Twig templates must be resolvable from the Symfony root. Use @ prefix for bundles:
      template: '@AppBundle/Resources/views/dashboard.html.twig'
      
  4. Role Hierarchy Misconfiguration:

    • Symfony’s role hierarchy (e.g., ROLE_ADMIN implies ROLE_USER) may cause unexpected state exposure. Explicitly list all required roles:
      roles: [ROLE_ADMIN, ROLE_SUPER_ADMIN]
      

Debugging

  1. Check State Filtering:

    • Enable debug mode and inspect the StatesLoadEvent:
      // In your listener
      dump($event->getStates());
      
    • Verify roles are correctly passed to the frontend:
      console.log(response.data); // Check filtered states
      
  2. JSONP Callback Issues:

    • If AngularJS fails to parse JSONP, ensure the callback parameter is named callback (not jsonp):
      $http.jsonp('/_statebridge', { params: { callback: 'JSON_CALLBACK' } });
      
    • Test the endpoint directly in a browser:
      /_statebridge?callback=testCallback
      
  3. Twig Template Not Found:

    • Clear Symfony’s cache:
      php bin/console cache:clear
      
    • Verify the template path is correct by testing Twig rendering directly:
      php bin/console debug:twig @AppBundle/Resources/views/dashboard.html.twig
      

Extension Points

  1. Custom State Providers:

    • Extend the bundle by creating a custom state provider:
      // src/StateProvider/CustomStateProvider.php
      class CustomStateProvider implements StateProviderInterface {
          public function getStates(): array {
              return [
                  'custom_state' => [
                      'path' => '/custom',
                      'roles' => ['ROLE_CUSTOM'],
                      'config' => ['nested' => true],
                  ],
              ];
          }
      }
      
    • Register it in services.yaml:
      services:
          App\StateProvider\CustomStateProvider:
              tags: [devtrw_state_bridge.state_provider]
      
  2. Event-Driven Extensions:

    • Listen to devtrw_state_bridge.states_load to modify states dynamically:
      // src/EventListener/StateModifierListener.php
      class StateModifierListener {
          public function onStatesLoad(StatesLoadEvent $event) {
              foreach ($event->getStates() as &$state) {
                  $state['config']['data'] = ['dynamic' => true]; // Add custom config
              }
          }
      }
      
  3. Frontend-Specific Extensions:

    • Override AngularJS state config after fetching from the backend:
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky