"Próbuję przenieść" (choć dokładnie powinienem nazwać to "przełożeniem", lub po prostu implementacją w innym miejscu i innej technologii) część logiki backendowej do frontendu.
Backend, to REST API na SF3 (chociaż na czym i gdzie to akurat mało ważne), frontend to Angular (4).
Co chcę uzyskać:
W Symfony mamy tagowane serwisy, tworzę sobie CompilerPass, taguję i "mam" dostępne serwisy w serwisie, tak... automagicznie. Staram się w jakiś magiczny sposób odtworzyć tą samą lub podobną logikę po stronie Angulara.
Dlaczego:
Powód jest jeden, w Symfony tagowane serwisy pomagają dodawać kolejną logikę do stosu (chociażby voter'y - bo to o nie mi akurat tutaj chodzi), brakuje mi tego po stronie frontendu w w/w frameworku. Mając 1 entry point (serwis, czy implementację poprzez dyrektywę/komponent i wtedy odwołanie się do serwisu) chciałbym pokazywać i/lub ukrywać coś w zależności od "czegoś" (tym "czymś" jest parametr z obiektem, lub sam parametr - permission).
Dlaczego tak, a nie napieprzać kod w komponencie renderującym?
Chociażby dlatego, że wiele miejsc w aplikacji wymaga sprawdzenia tych samych warunków (permission, lub permission + obiekt), a duplikowanie logiki jakoś mi nie po drodze.
Co zrobiłem (źle

// ... definicja SecurityModule export const SECURITY_VOTERS = new InjectionToken('PermissionCheckerService'); @NgModule(...) export class SecurityModule { /** * @param {Array<IPermissionVoter>} config * @returns {ModuleWithProviders} */ static forRoot (config: {voters: Array<Type<IPermissionVoter>>} = {voters: []}): ModuleWithProviders { return { ngModule: SecurityModule, providers: [ <ClassProvider>{ useClass: PermissionCheckerService, provide: SECURITY_VOTERS, useValue: config, multi: true } ], }; } /** * @param {Array<IPermissionVoter>} config * @returns {ModuleWithProviders} */ static forChild (config: {voters: Array<Type<IPermissionVoter>>} = {voters: []}): ModuleWithProviders { return { ngModule: SecurityModule, providers: [ <ClassProvider>{ useClass: PermissionCheckerService, provide: SECURITY_VOTERS, useValue: config, multi: true } ], }; } }
// ... użycie w module głównym @NgModule({ // ... imports: [ // ... // INTERNAL MODULES SecurityModule.forRoot({ voters: [UserPermissionVoter] }) ], providers: [ UserPermissionVoter ], bootstrap: [UIView], entryComponents: [] }) export class AppModule { }
// Definicja serwisu który ma otrzymać "tagowane" serwisy import { IPermissionVoter } from '../definitions/security.interfaces'; export class PermissionCheckerService { /** * @type {IPermissionVoter[]} */ voters: Array<IPermissionVoter> = []; /** * @param {string} permission * @param resource * @returns {boolean} */ public isGranted = (permission: string, resource: any): boolean => { let positiveCheck = 0; let negativeCheck = 0; console.log(this.voters); this.voters.forEach((checker: IPermissionVoter) => { if (true === checker.supports(permission, resource)) { if (true === checker.isGranted(permission, resource)){ positiveCheck++; } else { negativeCheck++; } } }); return negativeCheck === 0 && positiveCheck > 0; } }
Mam świadomość, że nie wszystko jest tak, jak być powinno, wzorowałem się 3rd party libami i szczątkami dokumentacji które znalazłem.
Ktoś coś?