Ajout de dernière update dans le bin de la console module
TODO: créé les pages de blog (sommaire,news) permettant d'afficher les fichiers md
This commit is contained in:
parent
474ce8ded1
commit
7b52c58faf
84
console/skel/symfony-app/composer.json
Normal file
84
console/skel/symfony-app/composer.json
Normal file
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"type": "project",
|
||||
"license": "proprietary",
|
||||
"require": {
|
||||
"php": "^7.2.5",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"sensio/framework-extra-bundle": "^5.1",
|
||||
"symfony/asset": "5.0.*",
|
||||
"symfony/console": "5.0.*",
|
||||
"symfony/dotenv": "5.0.*",
|
||||
"symfony/expression-language": "5.0.*",
|
||||
"symfony/flex": "^1.3.1",
|
||||
"symfony/form": "5.0.*",
|
||||
"symfony/framework-bundle": "5.0.*",
|
||||
"symfony/http-client": "5.0.*",
|
||||
"symfony/intl": "5.0.*",
|
||||
"symfony/mailer": "5.0.*",
|
||||
"symfony/monolog-bundle": "^3.1",
|
||||
"symfony/notifier": "5.0.*",
|
||||
"symfony/orm-pack": "*",
|
||||
"symfony/process": "5.0.*",
|
||||
"symfony/security-bundle": "5.0.*",
|
||||
"symfony/serializer-pack": "*",
|
||||
"symfony/string": "5.0.*",
|
||||
"symfony/translation": "5.0.*",
|
||||
"symfony/twig-pack": "*",
|
||||
"symfony/validator": "5.0.*",
|
||||
"symfony/web-link": "5.0.*",
|
||||
"symfony/yaml": "5.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/debug-pack": "*",
|
||||
"symfony/maker-bundle": "^1.0",
|
||||
"symfony/profiler-pack": "^1.0",
|
||||
"symfony/test-pack": "*"
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": {
|
||||
"*": "dist"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"App\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"replace": {
|
||||
"paragonie/random_compat": "2.*",
|
||||
"symfony/polyfill-ctype": "*",
|
||||
"symfony/polyfill-iconv": "*",
|
||||
"symfony/polyfill-php72": "*",
|
||||
"symfony/polyfill-php71": "*",
|
||||
"symfony/polyfill-php70": "*",
|
||||
"symfony/polyfill-php56": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"auto-scripts": {
|
||||
"cache:clear": "symfony-cmd",
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||
},
|
||||
"post-install-cmd": [
|
||||
"@auto-scripts"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@auto-scripts"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/symfony": "*"
|
||||
},
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "5.0.*"
|
||||
}
|
||||
}
|
||||
}
|
6754
console/skel/symfony-app/composer.lock
generated
Normal file
6754
console/skel/symfony-app/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
23
console/skel/symfony-app/config/bootstrap.php
Normal file
23
console/skel/symfony-app/config/bootstrap.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
|
||||
require dirname(__DIR__).'/vendor/autoload.php';
|
||||
|
||||
// Load cached env vars if the .env.local.php file exists
|
||||
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
|
||||
if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
|
||||
foreach ($env as $k => $v) {
|
||||
$_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && 0 !== strpos($k, 'HTTP_') ? $_SERVER[$k] : $v);
|
||||
}
|
||||
} elseif (!class_exists(Dotenv::class)) {
|
||||
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
|
||||
} else {
|
||||
// load all the .env files
|
||||
(new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
|
||||
}
|
||||
|
||||
$_SERVER += $_ENV;
|
||||
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
|
||||
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
|
||||
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
|
45
console/skel/symfony-app/config/bundles.php
Normal file
45
console/skel/symfony-app/config/bundles.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
|
||||
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
/*App\Session\AuthBundle\SessionAuthBundle::class => ['all' => true],*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
];
|
19
console/skel/symfony-app/config/packages/cache.yaml
Normal file
19
console/skel/symfony-app/config/packages/cache.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
framework:
|
||||
cache:
|
||||
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||
#prefix_seed: your_vendor_name/app_name
|
||||
|
||||
# The "app" cache stores to the filesystem by default.
|
||||
# The data in this cache should persist between deploys.
|
||||
# Other options include:
|
||||
|
||||
# Redis
|
||||
#app: cache.adapter.redis
|
||||
#default_redis_provider: redis://localhost
|
||||
|
||||
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||
#app: cache.adapter.apcu
|
||||
|
||||
# Namespaced pools use the above "app" backend by default
|
||||
#pools:
|
||||
#my.dedicated.cache: null
|
4
console/skel/symfony-app/config/packages/dev/debug.yaml
Normal file
4
console/skel/symfony-app/config/packages/dev/debug.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
debug:
|
||||
# Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
|
||||
# See the "server:dump" command to start a new server.
|
||||
dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
|
|
@ -0,0 +1,16 @@
|
|||
services:
|
||||
EasyCorp\EasyLog\EasyLogHandler:
|
||||
public: false
|
||||
arguments: ['%kernel.logs_dir%/%kernel.environment%.log']
|
||||
|
||||
#// FIXME: How to add this configuration automatically without messing up with the monolog configuration?
|
||||
#monolog:
|
||||
# handlers:
|
||||
# buffered:
|
||||
# type: buffer
|
||||
# handler: easylog
|
||||
# channels: ['!event']
|
||||
# level: debug
|
||||
# easylog:
|
||||
# type: service
|
||||
# id: EasyCorp\EasyLog\EasyLogHandler
|
19
console/skel/symfony-app/config/packages/dev/monolog.yaml
Normal file
19
console/skel/symfony-app/config/packages/dev/monolog.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
channels: ["!event"]
|
||||
# uncomment to get logging in your browser
|
||||
# you may have to allow bigger header sizes in your Web server configuration
|
||||
#firephp:
|
||||
# type: firephp
|
||||
# level: info
|
||||
#chromephp:
|
||||
# type: chromephp
|
||||
# level: info
|
||||
console:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine", "!console"]
|
|
@ -0,0 +1,6 @@
|
|||
web_profiler:
|
||||
toolbar: true
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { only_exceptions: false }
|
18
console/skel/symfony-app/config/packages/doctrine.yaml
Normal file
18
console/skel/symfony-app/config/packages/doctrine.yaml
Normal file
|
@ -0,0 +1,18 @@
|
|||
doctrine:
|
||||
dbal:
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
|
||||
# IMPORTANT: You MUST configure your server version,
|
||||
# either here or in the DATABASE_URL env var (see .env file)
|
||||
#server_version: '5.7'
|
||||
orm:
|
||||
auto_generate_proxy_classes: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
auto_mapping: true
|
||||
mappings:
|
||||
App:
|
||||
is_bundle: false
|
||||
type: annotation
|
||||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
|
@ -0,0 +1,5 @@
|
|||
doctrine_migrations:
|
||||
dir_name: '%kernel.project_dir%/src/Migrations'
|
||||
# namespace is arbitrary but should be different from App\Migrations
|
||||
# as migrations classes should NOT be autoloaded
|
||||
namespace: DoctrineMigrations
|
3
console/skel/symfony-app/config/packages/mailer.yaml
Normal file
3
console/skel/symfony-app/config/packages/mailer.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
framework:
|
||||
mailer:
|
||||
dsn: '%env(MAILER_DSN)%'
|
16
console/skel/symfony-app/config/packages/notifier.yaml
Normal file
16
console/skel/symfony-app/config/packages/notifier.yaml
Normal file
|
@ -0,0 +1,16 @@
|
|||
framework:
|
||||
notifier:
|
||||
#chatter_transports:
|
||||
# slack: '%env(SLACK_DSN)%'
|
||||
# telegram: '%env(TELEGRAM_DSN)%'
|
||||
#texter_transports:
|
||||
# twilio: '%env(TWILIO_DSN)%'
|
||||
# nexmo: '%env(NEXMO_DSN)%'
|
||||
channel_policy:
|
||||
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
|
||||
urgent: ['email']
|
||||
high: ['email']
|
||||
medium: ['email']
|
||||
low: ['email']
|
||||
admin_recipients:
|
||||
- { email: admin@example.com }
|
20
console/skel/symfony-app/config/packages/prod/doctrine.yaml
Normal file
20
console/skel/symfony-app/config/packages/prod/doctrine.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
doctrine:
|
||||
orm:
|
||||
auto_generate_proxy_classes: false
|
||||
metadata_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.system_cache_pool
|
||||
query_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.system_cache_pool
|
||||
result_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.result_cache_pool
|
||||
|
||||
framework:
|
||||
cache:
|
||||
pools:
|
||||
doctrine.result_cache_pool:
|
||||
adapter: cache.app
|
||||
doctrine.system_cache_pool:
|
||||
adapter: cache.system
|
24
console/skel/symfony-app/config/packages/prod/monolog.yaml
Normal file
24
console/skel/symfony-app/config/packages/prod/monolog.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: fingers_crossed
|
||||
action_level: error
|
||||
handler: nested
|
||||
excluded_http_codes: [404, 405]
|
||||
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
|
||||
nested:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
console:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine"]
|
||||
deprecation:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log"
|
||||
deprecation_filter:
|
||||
type: filter
|
||||
handler: deprecation
|
||||
max_level: info
|
||||
channels: ["php"]
|
|
@ -0,0 +1,3 @@
|
|||
framework:
|
||||
router:
|
||||
strict_requirements: null
|
3
console/skel/symfony-app/config/packages/routing.yaml
Normal file
3
console/skel/symfony-app/config/packages/routing.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
framework:
|
||||
router:
|
||||
utf8: true
|
51
console/skel/symfony-app/config/packages/security.yaml
Normal file
51
console/skel/symfony-app/config/packages/security.yaml
Normal file
|
@ -0,0 +1,51 @@
|
|||
security:
|
||||
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
|
||||
providers:
|
||||
# the name of your user provider can be anything
|
||||
session_user_provider:
|
||||
id: App\Security\AuthUserProvider
|
||||
# secured_area:
|
||||
# id: session_auth.user_provider
|
||||
firewalls:
|
||||
|
||||
dev:
|
||||
stateless: true
|
||||
access_denied_handler: App\Security\AccessDeniedHandler
|
||||
guard:
|
||||
authenticators:
|
||||
- App\Security\SessionAuthenticator
|
||||
main:
|
||||
stateless: true
|
||||
access_denied_handler: App\Security\AccessDeniedHandler
|
||||
guard:
|
||||
authenticators:
|
||||
- App\Security\SessionAuthenticator
|
||||
# activate different ways to authenticate
|
||||
# https://symfony.com/doc/current/security.html#firewalls-authentication
|
||||
|
||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||
# switch_user: true
|
||||
|
||||
# secured_area:
|
||||
# guard:
|
||||
# authenticators:
|
||||
# - session_auth.authenticator
|
||||
# logout:
|
||||
# path: logout #nom de la route de déconnexion
|
||||
# target: /
|
||||
# success_handler: session_auth.authenticator
|
||||
|
||||
encoders:
|
||||
# use your user class name here
|
||||
App\Security\AuthUser:
|
||||
# Use native password encoder
|
||||
# This value auto-selects the best possible hashing algorithm
|
||||
# (i.e. Sodium when available).
|
||||
algorithm: auto
|
||||
# Easy way to control access for large sections of your site
|
||||
# Note: Only the *first* access control that matches will be used
|
||||
access_control:
|
||||
- { path: '^/admin-test/admin', roles: ROLE_ADMIN }
|
||||
- { path: '^/admin-test/unauthorized', roles: ROLE_USER }
|
||||
- { path: '^/admin-test/page1', roles: ROLE_USER_CONNECTED }
|
||||
- { path: '^/admin-test', roles: ROLE_USER }
|
42
console/skel/symfony-app/config/packages/session_auth.yaml
Executable file
42
console/skel/symfony-app/config/packages/session_auth.yaml
Executable file
|
@ -0,0 +1,42 @@
|
|||
#session_auth:
|
||||
# #Activation du user_provider interne
|
||||
# #par défaut TRUE
|
||||
# use_default_provider : false
|
||||
# #Le Provider doit implémenter Symfony\Component\Security\Core\User\UserProviderInterface
|
||||
# #par défaut est utilise Besancon\AuthBundle\Security\User\AuthUserProvider
|
||||
# #cette valeur n'est nécessaire que lorsque use_default_provider est a false
|
||||
# #provider: Besancon\AuthBundle\Security\User\AuthUserProvider
|
||||
# provider: App\Security\AuthUserProvider
|
||||
# #Namespace de l'entité utilisateur
|
||||
# #L'entité doit implémenter Symfony\Component\Security\Core\User\UserInterface
|
||||
# #par défaut est utilise Besancon\AuthBundle\Security\User\AuthUser
|
||||
# #user_entity: App\Besancon\AuthBundle\Security\User\AuthUser
|
||||
# user_entity: App\Classes\AuthUser
|
||||
# #nom de la route correspondant à la page d'accueil de l'application
|
||||
# #par défaut est à NULL
|
||||
# homepage: "index"
|
||||
# #tag du service personnalisé permettant de gérer l'authentification
|
||||
# #par défaut est à bes_auth.authentification (service par défaut)
|
||||
# authentication_service: App\Security\Authentification
|
||||
# #authentication_service: bes_auth.authentification
|
||||
# #Mode d'authentification Cas ou Rsa
|
||||
# #obligatoire pas de valeur par défaut
|
||||
# type_auth: '%type_auth%'
|
||||
# #Configuration pour le mode Cas
|
||||
# #obligatoire si mode Cas choisi
|
||||
# cas:
|
||||
# #Serveur Cas
|
||||
# hostname: "seshat25.ac-besancon.fr"
|
||||
# #Port Cas
|
||||
# port: 443
|
||||
# #Uri Cas
|
||||
# uri: ""
|
||||
# #Configuration pour le mode Rsa
|
||||
# #obligatoire si mode Rsa choisi
|
||||
# rsa :
|
||||
# #Url de déconnexion Rsa
|
||||
# logout_url: http://webphppreprod3.in.ac-besancon.fr:8383/login/ct_logout.jsp
|
||||
#
|
||||
#parameters:
|
||||
# type_auth: Session
|
||||
|
12
console/skel/symfony-app/config/packages/test/monolog.yaml
Normal file
12
console/skel/symfony-app/config/packages/test/monolog.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: fingers_crossed
|
||||
action_level: error
|
||||
handler: nested
|
||||
excluded_http_codes: [404, 405]
|
||||
channels: ["!event"]
|
||||
nested:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
2
console/skel/symfony-app/config/packages/test/twig.yaml
Normal file
2
console/skel/symfony-app/config/packages/test/twig.yaml
Normal file
|
@ -0,0 +1,2 @@
|
|||
twig:
|
||||
strict_variables: true
|
|
@ -0,0 +1,3 @@
|
|||
framework:
|
||||
validation:
|
||||
not_compromised_password: false
|
|
@ -0,0 +1,6 @@
|
|||
web_profiler:
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { collect: false }
|
|
@ -0,0 +1,6 @@
|
|||
framework:
|
||||
default_locale: en
|
||||
translator:
|
||||
default_path: '%kernel.project_dir%/translations'
|
||||
fallbacks:
|
||||
- en
|
2
console/skel/symfony-app/config/packages/twig.yaml
Normal file
2
console/skel/symfony-app/config/packages/twig.yaml
Normal file
|
@ -0,0 +1,2 @@
|
|||
twig:
|
||||
default_path: '%kernel.project_dir%/templates'
|
8
console/skel/symfony-app/config/packages/validator.yaml
Normal file
8
console/skel/symfony-app/config/packages/validator.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
framework:
|
||||
validation:
|
||||
email_validation_mode: html5
|
||||
|
||||
# Enables validator auto-mapping support.
|
||||
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
|
||||
#auto_mapping:
|
||||
# App\Entity\: []
|
7
console/skel/symfony-app/config/routes/annotations.yaml
Normal file
7
console/skel/symfony-app/config/routes/annotations.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
controllers:
|
||||
resource: ../../src/Controller/
|
||||
type: annotation
|
||||
|
||||
kernel:
|
||||
resource: ../../src/Kernel.php
|
||||
type: annotation
|
|
@ -0,0 +1,3 @@
|
|||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
|
||||
prefix: /_error
|
|
@ -0,0 +1,7 @@
|
|||
web_profiler_wdt:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
|
||||
prefix: /_wdt
|
||||
|
||||
web_profiler_profiler:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
|
||||
prefix: /_profiler
|
43
console/skel/symfony-app/config/services.yaml
Normal file
43
console/skel/symfony-app/config/services.yaml
Normal file
|
@ -0,0 +1,43 @@
|
|||
# This file is the entry point to configure your own services.
|
||||
# Files in the packages/ subdirectory configure your dependencies.
|
||||
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
|
||||
parameters:
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/*'
|
||||
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
|
||||
|
||||
# controllers are imported separately to make sure services can be injected
|
||||
# as action arguments even if you don't extend any base controller class
|
||||
App\Controller\:
|
||||
resource: '../src/Controller'
|
||||
tags: ['controller.service_arguments']
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
# App\Security\Authentification:
|
||||
# autowire: true
|
||||
# parent: App\Security\Abstracts\AuthFinal
|
||||
# public: false
|
||||
# autoconfigure: false
|
||||
# arguments:
|
||||
# $var: []
|
||||
#
|
||||
# session_auth.authenticator_factory:
|
||||
# class: App\Security\AuthentificatorFactory
|
||||
# public: false
|
||||
#
|
||||
# session_auth.user_provider:
|
||||
# class: App\Security\AuthUserProvider
|
||||
# public: false
|
||||
|
19
console/skel/symfony-app/src/Controller/AdminController.php
Executable file
19
console/skel/symfony-app/src/Controller/AdminController.php
Executable file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class AdminController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Route("/admin-test/admin", name="admin")
|
||||
*/
|
||||
public function adminAction()
|
||||
{
|
||||
// replace this example code with whatever you need
|
||||
return $this->render('default/page.html.twig', [
|
||||
'text' => 'admin',
|
||||
]);
|
||||
}
|
||||
}
|
45
console/skel/symfony-app/src/Controller/DefaultController.php
Executable file
45
console/skel/symfony-app/src/Controller/DefaultController.php
Executable file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class DefaultController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Route("/admin-test", name="homepage")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
print_r("<pre>");
|
||||
//print_r($this->get('session'));
|
||||
print_r($_COOKIE);
|
||||
print_r($_SESSION);
|
||||
print_r("</pre>");
|
||||
// replace this example code with whatever you need
|
||||
return $this->render('default/page.html.twig', [
|
||||
'text' => 'homepage',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/admin-test/page1", name="page1")
|
||||
*/
|
||||
public function page1Action()
|
||||
{
|
||||
// replace this example code with whatever you need
|
||||
return $this->render('default/page.html.twig', [
|
||||
'text' => 'page1',
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* @Route("/admin-test/page2", name="page2")
|
||||
*/
|
||||
public function page2Action()
|
||||
{
|
||||
// replace this example code with whatever you need
|
||||
return $this->render('default/page.html.twig', [
|
||||
'text' => 'page2',
|
||||
]);
|
||||
}
|
||||
}
|
24
console/skel/symfony-app/src/Controller/ErrorController.php
Executable file
24
console/skel/symfony-app/src/Controller/ErrorController.php
Executable file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class ErrorController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Route("/admin-test/unauthorized", name="unauthorized")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
print_r("<pre>");
|
||||
//print_r($this->get('session'));
|
||||
print_r($_COOKIE);
|
||||
print_r($_SESSION);
|
||||
print_r("</pre>");
|
||||
// replace this example code with whatever you need
|
||||
return $this->render('default/unauthorized.html.twig', [
|
||||
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
||||
class OnAuthenticationFailureEvent extends Event {
|
||||
|
||||
const NAME = "session_auth.event.on_authentication_failure";
|
||||
|
||||
public function __construct(Request $request, AuthenticationException $exception) {
|
||||
$this->request = $request;
|
||||
$this->exception = $exception;
|
||||
$this->response = new Response($exception->getMessage(), Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
public function getRequest() {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function getException() {
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
public function getResponse() {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function setResponse($response) {
|
||||
$this->response = $response;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
namespace App\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
class OnAuthenticationSuccessEvent extends Event {
|
||||
|
||||
const NAME = "session_auth.event.on_authentication_success";
|
||||
|
||||
public function __construct(Request $request, TokenInterface $token, $providerKey) {
|
||||
$this->request = $request;
|
||||
$this->token = $token;
|
||||
$this->providerKey = $providerKey;
|
||||
}
|
||||
|
||||
public function getRequest() {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function getToken() {
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
public function getProviderKey() {
|
||||
return $this->providerKey;
|
||||
}
|
||||
|
||||
}
|
54
console/skel/symfony-app/src/Kernel.php
Normal file
54
console/skel/symfony-app/src/Kernel.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
use Symfony\Component\Routing\RouteCollectionBuilder;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
|
||||
private const CONFIG_EXTS = '.{php,xml,yaml,yml}';
|
||||
|
||||
public function registerBundles(): iterable
|
||||
{
|
||||
$contents = require $this->getProjectDir().'/config/bundles.php';
|
||||
foreach ($contents as $class => $envs) {
|
||||
if ($envs[$this->environment] ?? $envs['all'] ?? false) {
|
||||
yield new $class();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getProjectDir(): string
|
||||
{
|
||||
return \dirname(__DIR__);
|
||||
}
|
||||
|
||||
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
|
||||
{
|
||||
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
|
||||
$container->setParameter('container.dumper.inline_class_loader', \PHP_VERSION_ID < 70400 || $this->debug);
|
||||
$container->setParameter('container.dumper.inline_factories', true);
|
||||
$confDir = $this->getProjectDir().'/config';
|
||||
|
||||
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
|
||||
$loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob');
|
||||
$loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
|
||||
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
|
||||
}
|
||||
|
||||
protected function configureRoutes(RouteCollectionBuilder $routes): void
|
||||
{
|
||||
$confDir = $this->getProjectDir().'/config';
|
||||
|
||||
$routes->import($confDir.'/{routes}/'.$this->environment.'/*'.self::CONFIG_EXTS, '/', 'glob');
|
||||
$routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob');
|
||||
$routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob');
|
||||
}
|
||||
}
|
0
console/skel/symfony-app/src/Repository/.gitkeep
Normal file
0
console/skel/symfony-app/src/Repository/.gitkeep
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
class AccessDeniedHandler implements AccessDeniedHandlerInterface
|
||||
{
|
||||
public $twig;
|
||||
public function __construct(Environment $twig)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
}
|
||||
public function handle(Request $request, AccessDeniedException $accessDeniedException)
|
||||
{
|
||||
$content = $this->twig->render(
|
||||
'default/unauthorized.html.twig', array()
|
||||
);
|
||||
$response = new Response($content, Response::HTTP_FORBIDDEN);
|
||||
return $response;
|
||||
}
|
||||
}
|
97
console/skel/symfony-app/src/Security/AuthUser.php
Normal file
97
console/skel/symfony-app/src/Security/AuthUser.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
class AuthUser implements UserInterface{
|
||||
|
||||
private $id;
|
||||
private $username;
|
||||
private $status;
|
||||
private $type;
|
||||
private $salt;
|
||||
private $credentials;
|
||||
private $roles = [];
|
||||
|
||||
public function __construct($id, $username,$credentials, array $roles = [])
|
||||
{
|
||||
$this->username = $username;
|
||||
$this->id = $id;
|
||||
$this->credentials = $credentials;
|
||||
$this->roles = $roles;
|
||||
$this->salt = sha1(microtime(true));
|
||||
}
|
||||
|
||||
public function getRoles()
|
||||
{
|
||||
$roles = $this->roles;
|
||||
// guarantee every user at least has ROLE_USER
|
||||
if($this->getId() == 1587184) {
|
||||
$roles[] = 'ROLE_ADMIN';
|
||||
}
|
||||
return array_unique($roles);
|
||||
}
|
||||
|
||||
public function setRoles($roles)
|
||||
{
|
||||
return $this->roles = $roles;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getUser(){
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCredentials()
|
||||
{
|
||||
return $this->credentials;
|
||||
}
|
||||
|
||||
public function eraseCredentials()
|
||||
{
|
||||
// TODO: Implement eraseCredentials() method.
|
||||
}
|
||||
|
||||
public function getPassword()
|
||||
{
|
||||
// TODO: Implement getPassword() method.
|
||||
}
|
||||
|
||||
public function getSalt()
|
||||
{
|
||||
return $this->salt;
|
||||
}
|
||||
|
||||
public function isEqualTo(UserInterface $user)
|
||||
{
|
||||
if (!$user instanceof AuthUser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->username !== $user->getUsername()) {
|
||||
return false;
|
||||
}
|
||||
if ($this->id !== $user->getId()) {
|
||||
return false;
|
||||
}
|
||||
if ($this->type !== $user->getType()) {
|
||||
return false;
|
||||
}
|
||||
if ($this->status !== $user->getStatus()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
77
console/skel/symfony-app/src/Security/AuthUserProvider.php
Normal file
77
console/skel/symfony-app/src/Security/AuthUserProvider.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Security\AuthUser;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
|
||||
|
||||
class AuthUserProvider implements UserProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Symfony calls this method if you use features like switch_user
|
||||
* or remember_me.
|
||||
*
|
||||
* If you're not using these features, you do not need to implement
|
||||
* this method.
|
||||
*
|
||||
* @return UserInterface
|
||||
*
|
||||
* @throws UsernameNotFoundException if the user is not found
|
||||
*/
|
||||
public function loadUserByUsername($username) {
|
||||
$entity_user = $this->entity_user;
|
||||
|
||||
return $this->authService->getUser($username);
|
||||
// Load a User object from your data source or throw UsernameNotFoundException.
|
||||
// The $username argument may not actually be a username:
|
||||
// it is whatever value is being returned by the getUsername()
|
||||
// method in your User class.
|
||||
// throw new \Exception('TODO: fill in loadUserByUsername() inside '.__FILE__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the user after being reloaded from the session.
|
||||
*
|
||||
* When a user is logged in, at the beginning of each request, the
|
||||
* User object is loaded from the session and then this method is
|
||||
* called. Your job is to make sure the user's data is still fresh by,
|
||||
* for example, re-querying for fresh User data.
|
||||
*
|
||||
* If your firewall is "stateless: true" (for a pure API), this
|
||||
* method is not called.
|
||||
*
|
||||
* @return UserInterface
|
||||
*/
|
||||
|
||||
public function refreshUser(UserInterface $user) {
|
||||
$user = $this->_ctrlInstanceUser($user);
|
||||
|
||||
return $this->loadUserByUsername($user->getUsername());
|
||||
}
|
||||
|
||||
private function _ctrlInstanceUser(UserInterface $user) {
|
||||
$entity_user = $this->entity_user;
|
||||
|
||||
if (!$user instanceof $entity_user) {
|
||||
throw new UnsupportedUserException(
|
||||
sprintf('Instances of "%s" are not supported.', get_class($user))
|
||||
);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells Symfony to use this provider for this User class.
|
||||
*/
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return AuthUser::class === $class;
|
||||
}
|
||||
}
|
152
console/skel/symfony-app/src/Security/SessionAuthenticator.php
Normal file
152
console/skel/symfony-app/src/Security/SessionAuthenticator.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use MVC\Classe\Dumper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
|
||||
use Twig\Environment;
|
||||
|
||||
|
||||
class SessionAuthenticator extends AbstractGuardAuthenticator
|
||||
{
|
||||
public $router;
|
||||
public $twig;
|
||||
|
||||
public function __construct(UrlGeneratorInterface $router,Environment $twig)
|
||||
{
|
||||
$this->router = $router;
|
||||
$this->twig = $twig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request to decide if this authenticator should be
|
||||
* used for the request. Returning `false` will cause this authenticator
|
||||
* to be skipped.
|
||||
*/
|
||||
public function supports(Request $request)
|
||||
{
|
||||
Dumper::dump("supports function");
|
||||
Dumper::dump($_SESSION);
|
||||
if (isset($_SESSION['id_utilisateur'])) {
|
||||
return true;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request. Return whatever credentials you want to
|
||||
* be passed to getUser() as $credentials.
|
||||
*/
|
||||
public function getCredentials(Request $request)
|
||||
{
|
||||
Dumper::dump("getCredentials");
|
||||
return "X-AUTH-TOKEN-SESSION-API";
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider)
|
||||
{
|
||||
Dumper::dump("getUser");
|
||||
if (!isset($_SESSION['id'])) {
|
||||
$user = new \App\Security\AuthUser('0','not-connected',$credentials,['ROLE_USER']);
|
||||
}else {
|
||||
$user = new \App\Security\AuthUser($_SESSION['id'], $_SESSION['username'], $credentials, ['ROLE_USER', 'ROLE_USER_CONNECTED']);
|
||||
}
|
||||
|
||||
Dumper::dump($user);
|
||||
|
||||
// if a User is returned, checkCredentials() is called
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user)
|
||||
{
|
||||
// Check credentials - e.g. make sure the password is valid.
|
||||
// In case of an API token, no credential check is needed.
|
||||
|
||||
// Return `true` to cause authentication success
|
||||
Dumper::dump("checkCredentials");
|
||||
if($user->getCredentials() === $credentials) {
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
|
||||
{
|
||||
// on success, let the request continue
|
||||
//return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
|
||||
{
|
||||
$data = [
|
||||
// you may want to customize or obfuscate the message first
|
||||
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
|
||||
|
||||
// or to translate this message
|
||||
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
|
||||
];
|
||||
|
||||
// return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
|
||||
// $url = $this->router->generate('unauthorized');
|
||||
// return new RedirectResponse($url);
|
||||
$content = $this->twig->render(
|
||||
'default/unauthorized.html.twig', array()
|
||||
);
|
||||
$response = new Response($content, Response::HTTP_FORBIDDEN);
|
||||
return $response;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when authentication is needed, but it's not sent
|
||||
*/
|
||||
public function start(Request $request, AuthenticationException $authException = null)
|
||||
{
|
||||
$data = [
|
||||
// you might translate this message
|
||||
'message' => 'Authentication Required'
|
||||
];
|
||||
|
||||
//return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
|
||||
|
||||
// $url = $this->router->generate('unauthorized');
|
||||
// return new RedirectResponse($url);
|
||||
|
||||
$content = $this->twig->render(
|
||||
'default/unauthorized.html.twig', array()
|
||||
);
|
||||
$response = new Response($content, Response::HTTP_FORBIDDEN);
|
||||
return $response;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function supportsRememberMe()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onLogoutSuccess(Request $request) {
|
||||
//$homepage = $this->config["homepage"];
|
||||
//return \phpCAS::logoutWithRedirectService($this->urlGenerator->generate($homepage, array(), UrlGeneratorInterface::ABSOLUTE_URL));
|
||||
header('Location: /index.php');
|
||||
return ;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
|
||||
/**
|
||||
* This is the class that validates and merges configuration from your app/config files.
|
||||
*
|
||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfigTreeBuilder() {
|
||||
$treeBuilder = new TreeBuilder('session_auth');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
$rootNode
|
||||
->children()
|
||||
->scalarNode('homepage')->defaultNull()->end()
|
||||
->scalarNode('authentication_service')->defaultNull()->end()
|
||||
->scalarNode('provider')->defaultNull()->end()
|
||||
->booleanNode('use_default_provider')->defaultTrue()->end()
|
||||
->scalarNode('user_entity')->defaultNull()->end()
|
||||
->scalarNode('type_auth')->isRequired()->cannotBeEmpty()
|
||||
->validate()
|
||||
->ifNotInArray(array('Rsa', 'Cas','Session'))
|
||||
->thenInvalid("La méthode d'authentification %s n'est pas gérée, seuls Rsa et Cas sont acceptés")
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('environment')->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
$rootNode
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
if(!is_null($v['user_entity'])){
|
||||
$class = $v['user_entity'];
|
||||
if(!class_exists($class)){
|
||||
return true;
|
||||
}
|
||||
return !array_key_exists("Symfony\Component\Security\Core\User\UserInterface", class_implements($class));
|
||||
}
|
||||
return false;
|
||||
})
|
||||
->thenInvalid("La classe renseignée pour 'entity' doit implémenter Symfony\Component\Security\Core\User\UserInterface")
|
||||
->end();
|
||||
|
||||
$this->_addCasConfig($rootNode);
|
||||
$this->_addRsaConfig($rootNode);
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
|
||||
private function _addCasConfig(ArrayNodeDefinition $node) {
|
||||
|
||||
$node
|
||||
->children()
|
||||
->arrayNode('cas')->info('A déclarer si authentification pas CAS.')
|
||||
->addDefaultsIfNotSet()
|
||||
->treatNullLike(['hostname' => null])
|
||||
->treatNullLike(['port' => null])
|
||||
->treatNullLike(['uri' => null])
|
||||
->children()
|
||||
->scalarNode('hostname')->defaultNull()->end()
|
||||
->scalarNode('port')->defaultNull()->end()
|
||||
->scalarNode('uri')->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
$node
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
$cas_config = $v['cas'];
|
||||
return ($v['type_auth']=="Cas" && (is_null($cas_config['hostname']) || is_null($cas_config['port']) || is_null($cas_config['uri'])) );
|
||||
})
|
||||
->thenInvalid("En utilisant le type d'authentification Cas vous devez renseigner la section 'cas' et ses clés 'hostname', 'port', 'uri'")
|
||||
->end();
|
||||
}
|
||||
|
||||
private function _addRsaConfig(ArrayNodeDefinition $node) {
|
||||
$node
|
||||
->children()
|
||||
->arrayNode('rsa')->addDefaultsIfNotSet()->info('A déclarer si authentification pas RSA.')
|
||||
->addDefaultsIfNotSet()
|
||||
->treatNullLike(['logout_url' => null])
|
||||
->children()
|
||||
->scalarNode('logout_url')->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
$node
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
$rsa_config = $v['rsa'];
|
||||
return ($v['type_auth']==="Rsa" && is_null($rsa_config['logout_url']));
|
||||
})
|
||||
->thenInvalid("En utilisant le type d'authentification Rsa vous devez renseigner la section 'rsa' et sa clé 'logout_url'")
|
||||
->end();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
|
||||
/**
|
||||
* This is the class that loads and manages your bundle configuration.
|
||||
*
|
||||
* @link http://symfony.com/doc/current/cookbook/bundles/extension.html
|
||||
*/
|
||||
class SessionAuthExtension extends Extension {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container) {
|
||||
|
||||
$configs[0]['environment'] = $container->getParameter("kernel.environment");
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
|
||||
//Chargement des parametres
|
||||
$loader->load('parameters.yml');
|
||||
//Chargement des services
|
||||
$loader->load('services.yml');
|
||||
|
||||
|
||||
//definition du service d'authentification par défaut dans le cas où ce ne serait pas un service
|
||||
// fraichement créé par l'utilisateur dans le fichiers services.yaml
|
||||
if(is_null($config["authentication_service"])){
|
||||
$authentication_service = "session_auth.authentification";
|
||||
}else{
|
||||
$authentication_service = $config["authentication_service"];
|
||||
}
|
||||
|
||||
if ($authentication_service == "session_auth.authentification") {
|
||||
$container->register($authentication_service, \App\Besancon\AuthBundle\Security\DefaultAuthentication::class)
|
||||
->addMethodCall('setGetterAttributes', array($config))
|
||||
->setPublic(false);
|
||||
}
|
||||
|
||||
//Creation du service @bes_auth.authenticator permettant la redirection sur le Cas ou le Rsa correspondant
|
||||
$container->register('session_auth.authenticator', \Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator::class)
|
||||
->setFactory(array(new Reference("session_auth.authenticator_factory"), 'getAuthenticator'))
|
||||
->addArgument(new Reference($authentication_service))
|
||||
->addArgument($config)
|
||||
->addArgument(new Reference("router"))
|
||||
->addArgument(new Reference("event_dispatcher"))
|
||||
->setPublic(false);
|
||||
|
||||
|
||||
//Création du service pour le provider par défaut ou pour le provider défini par l'utilisateur
|
||||
if ($config["use_default_provider"]) {
|
||||
//Creation du service @bes_auth.user_provider
|
||||
$container->register('session_auth.user_provider', \App\Besancon\AuthBundle\Security\User\AuthUserProvider::class)
|
||||
->addArgument(new Reference($authentication_service))
|
||||
->addArgument($config)
|
||||
->setPublic(false);
|
||||
}else{
|
||||
$container->register('session_auth.user_provider', $config["provider"])
|
||||
->addArgument(new Reference($authentication_service))
|
||||
->addArgument($config)
|
||||
->setPublic(false);
|
||||
}
|
||||
|
||||
$container->setDefinition('session_auth.configuration', new \Symfony\Component\DependencyInjection\Definition( \App\Besancon\AuthBundle\DependencyInjection\Configuration::class) )
|
||||
->setArguments([
|
||||
$config,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getNamespace() {
|
||||
return 'http://ac-besancon.fr/schema/dic/' . $this->getAlias();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
class CheckCredentialsEvent extends Event {
|
||||
|
||||
const NAME = "besancon_auth.event.check_credentials";
|
||||
private $access = true;
|
||||
|
||||
public function __construct($credentials, UserInterface $user_interface) {
|
||||
$this->credentials = $credentials;
|
||||
$this->user_interface = $user_interface;
|
||||
}
|
||||
|
||||
public function getCredentials() {
|
||||
return $this->credentials;
|
||||
}
|
||||
|
||||
public function getUserInterface() {
|
||||
return $this->user_interface;
|
||||
}
|
||||
|
||||
public function getAccess() {
|
||||
return $this->access;
|
||||
}
|
||||
public function setAccess($access) {
|
||||
$this->access = $access;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
||||
class OnAuthenticationFailureEvent extends Event {
|
||||
|
||||
const NAME = "session_auth.event.on_authentication_failure";
|
||||
|
||||
public function __construct(Request $request, AuthenticationException $exception) {
|
||||
$this->request = $request;
|
||||
$this->exception = $exception;
|
||||
$this->response = new Response($exception->getMessage(), Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
public function getRequest() {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function getException() {
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
public function getResponse() {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function setResponse($response) {
|
||||
$this->response = $response;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
namespace App\Session\AuthBundle\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
class OnAuthenticationSuccessEvent extends Event {
|
||||
|
||||
const NAME = "session_auth.event.on_authentication_success";
|
||||
|
||||
public function __construct(Request $request, TokenInterface $token, $providerKey) {
|
||||
$this->request = $request;
|
||||
$this->token = $token;
|
||||
$this->providerKey = $providerKey;
|
||||
}
|
||||
|
||||
public function getRequest() {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function getToken() {
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
public function getProviderKey() {
|
||||
return $this->providerKey;
|
||||
}
|
||||
|
||||
}
|
366
console/skel/symfony-app/src/Session/AuthBundle/README.md
Executable file
366
console/skel/symfony-app/src/Session/AuthBundle/README.md
Executable file
|
@ -0,0 +1,366 @@
|
|||
**AuthBundle**
|
||||
========================
|
||||
|
||||
# Configuration minimale requise
|
||||
|
||||
Le bundle est compatible à partir de la version 3.4 de Symfony.
|
||||
|
||||
# Installation
|
||||
|
||||
## Installation via composer (recommandé)
|
||||
|
||||
Dans un premier temps renseigner le "repository" via la commande :
|
||||
|
||||
```bash
|
||||
composer config repositories.authbundle git "ssh://git@gitlab1.in.ac-besancon.fr:1232/abelhadjali/authbundle.git"
|
||||
```
|
||||
|
||||
Ceci va ajouter dans votre fichier composer.json les lignes suivantes
|
||||
|
||||
```json
|
||||
...
|
||||
"repositories": {
|
||||
"authbundle": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@gitlab1.in.ac-besancon.fr:1232/abelhadjali/authbundle.git"
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
Puis ajouter la dépendance au bundle en précisant le tag de la version souhaitée ici à partir de la v0.1
|
||||
|
||||
```bash
|
||||
composer require ac-besancon/authbundle:^0.1
|
||||
```
|
||||
|
||||
Enfin activer le bundle en suivant les instructions de la section [[AuthBundle#Activation du bundle|Activation du bundle]]
|
||||
|
||||
## Installation sans composer
|
||||
|
||||
### Récupérer les sources
|
||||
|
||||
*Copier et coller* le dossier Besancon du Bundle dans le repertoire _*src/*_ de votre projet *Symfony*.
|
||||
|
||||
### Déclaration du namespace
|
||||
|
||||
Dans le fichier `composer.json` et dans la section "autoload" de votre projet ajouter:
|
||||
|
||||
```json
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
...
|
||||
"Besancon\\AuthBundle\\": "src/Besancon/AuthBundle",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Puis executer la commande composer suivante :
|
||||
|
||||
```bash
|
||||
composer dump-autoload
|
||||
```
|
||||
|
||||
|
||||
# Activation du bundle
|
||||
|
||||
Pour activer le Bundle, ouvrir le fichier app/AppKernel.php et y ajouter:
|
||||
|
||||
```php
|
||||
|
||||
// ...
|
||||
class AppKernel extends Kernel
|
||||
{
|
||||
public function registerBundles()
|
||||
{
|
||||
$bundles = array(
|
||||
// ...
|
||||
new Besancon\AuthBundle\BesanconAuthBundle(),
|
||||
);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# Configuration
|
||||
======================
|
||||
|
||||
## Liste complète des options de configuration
|
||||
|
||||
La configuration est à déclaré dans le fichier *app/config/config.yml* du projet Symfony.
|
||||
|
||||
```yaml
|
||||
besancon_auth:
|
||||
#Activation du user_provider interne
|
||||
#par défaut TRUE
|
||||
use_default_provider : true
|
||||
#Namespace de l'entité utilisateur
|
||||
#L'entité doit implémenter Symfony\Component\Security\Core\User\UserInterface
|
||||
#par défaut est utilise Besancon\AuthBundle\Security\User\AuthUser
|
||||
user_entity: Mon\Entite\User
|
||||
#nom de la route correspondant à la page d'accueil de l'application
|
||||
#par défaut est à NULL
|
||||
homepage: "homepage"
|
||||
#tag du service personnalisé permettant de gérer l'authentification
|
||||
#par défaut est à bes_auth.authentification (service par défaut)
|
||||
authentication_service: mon_service.authentification
|
||||
#Mode d'authentification Cas ou Rsa
|
||||
#obligatoire pas de valeur par défaut
|
||||
type_auth: Cas
|
||||
#Configuration pour le mode Cas
|
||||
#obligatoire si mode Cas choisi
|
||||
cas:
|
||||
#Serveur Cas
|
||||
hostname: "seshat23.ac-besancon.fr"
|
||||
#Port Cas
|
||||
port: 8443
|
||||
#Uri Cas
|
||||
uri: ""
|
||||
#Configuration pour le mode Rsa
|
||||
#obligatoire si mode Rsa choisi
|
||||
rsa :
|
||||
#Url de déconnexion Rsa
|
||||
logout_url: http://url.deconnexion.fr/login/ct_logout.jsp
|
||||
```
|
||||
|
||||
## Configuration dans le firewall
|
||||
|
||||
Ouvrir le fichier app/config/security.yml du projet Symfony.
|
||||
|
||||
Si utilisation du _user provider_ interne *bes_auth.user_provider* , alors le déclarer dans la section _*providers*_ :
|
||||
|
||||
```yaml
|
||||
...
|
||||
providers:
|
||||
app:
|
||||
id: bes_auth.user_provider
|
||||
...
|
||||
```
|
||||
|
||||
Sinon préciser votre propre user provider
|
||||
|
||||
Toujours dans le même fichier, dans la section des _*firewalls*_, déclarer le _guard_ *bes_auth.authenticator* dans la zone à sécurisée :
|
||||
|
||||
```yaml
|
||||
firewalls:
|
||||
...
|
||||
secured_area:
|
||||
logout_on_user_change: true
|
||||
...
|
||||
guard:
|
||||
authenticators:
|
||||
- bes_auth.authenticator
|
||||
logout:
|
||||
path: auth_cas_logout #nom de la route de déconnexion
|
||||
target: /
|
||||
success_handler: bes_auth.authenticator
|
||||
...
|
||||
```
|
||||
|
||||
Plus d'infos sur le user provider :
|
||||
* https://symfony.com/doc/current/security/entity_provider.html#using-a-custom-query-to-load-the-user
|
||||
|
||||
Il est donc important de définir la route de déconnexion dans le fichier *app/config/route.yml*
|
||||
|
||||
```yaml
|
||||
...
|
||||
|
||||
auth_cas_logout:
|
||||
path: /logout
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
## Configuration avancée
|
||||
|
||||
### Création d'un service d'authentification
|
||||
|
||||
Pour cela, créer un service qui hérite de *AuthAbstract* et implémente *AuthInterface*
|
||||
|
||||
```php
|
||||
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Security\Auth;
|
||||
|
||||
use Besancon\AuthBundle\Security\Interfaces\AuthInterface;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Besancon\AuthBundle\Security\Abstracts\AuthAbstract;
|
||||
|
||||
class MonService extends AuthAbstract implements AuthInterface {
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Il faut ensuite implémenter les méthodes suivantes :
|
||||
|
||||
```php
|
||||
|
||||
/**
|
||||
* Contrôle de l'accès à partir des attributs CAS ou RSA
|
||||
*
|
||||
* Vérifier les droits d'accès à l'application à partir des attributs récupérées des getters :
|
||||
* - CasAttributes
|
||||
* - RsaAttributes
|
||||
*
|
||||
* @param UserInterface $user
|
||||
* L'entité user récupéré par le provider
|
||||
*
|
||||
* @return bool
|
||||
* - true si accès autorisé
|
||||
* - false si accès refusé
|
||||
*/
|
||||
public function ctrlAccess(UserInterface $user);
|
||||
|
||||
/**
|
||||
* Calcule et retoune le(s) rôle(s) à partir des attributs CAS ou RSA
|
||||
*
|
||||
* Calculer le(s) rôle(s) à partir des attributs récupérées des getters :
|
||||
* - CasAttributes
|
||||
* - RsaAttributes
|
||||
* Doit retourner un tableau même vide
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRoles();
|
||||
|
||||
/**
|
||||
* Retourne un utilisateur pour la génération du token, si l'utilisateur n'existe pas en base de donnée
|
||||
*
|
||||
* ATTENTION : CETTE METHODE DOIT ÊTRE REDEFINIE SI UTILISATION D'UNE ENTITE UTILISTEUR
|
||||
* DIFFERENTE DE CELLE UTILISEE PAR DEFAUT
|
||||
*
|
||||
* @param String $username
|
||||
* uid de l'utilisateur récupéré de Cas ou Rsa
|
||||
*
|
||||
* @return UserInterface
|
||||
*/
|
||||
public function getUser($username);
|
||||
|
||||
/**
|
||||
* Traitement personnalisé après récupération du token
|
||||
*
|
||||
* Il est possible d'enrichir le token (attributs...) ou d'effectuer des contrôles supplémentaire
|
||||
*
|
||||
* @param $token
|
||||
* Token d'authification généré
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function onSuccess($token);
|
||||
|
||||
/**
|
||||
* Traitement personnalisé lorsque la connexion n'a pas abouti
|
||||
*
|
||||
* Vérifié l'exception généré et adapter l'action (redirection, déconnexion...)
|
||||
*
|
||||
* Doit retourner un objet de type Response
|
||||
*
|
||||
* Exemple :
|
||||
*
|
||||
* ```
|
||||
* public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception)
|
||||
* {
|
||||
* $content = $this->twig->render(
|
||||
* '@App/Test/forbiden.html.twig', array()
|
||||
* );
|
||||
* $response = new Response($content, Response::HTTP_FORBIDDEN);
|
||||
* return $response;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param AuthenticationException $exception
|
||||
* Exception générée par le provider
|
||||
*
|
||||
* @return Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
*/
|
||||
public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception);
|
||||
|
||||
```
|
||||
|
||||
Enfin lorsque le service est prêt, le déclarer, en le reliant à la classe parent Besancon\AuthBundle\Security\Abstracts\AuthAbstract:
|
||||
|
||||
```yaml
|
||||
|
||||
mon_service.authentification:
|
||||
class: AppBundle\Security\Auth\MonService
|
||||
parent: Besancon\AuthBundle\Security\Abstracts\AuthAbstract
|
||||
public: false
|
||||
|
||||
#OU si version Symfony >=3.4
|
||||
|
||||
AppBundle\Security\Auth\MonService:
|
||||
autowire: true
|
||||
parent: Besancon\AuthBundle\Security\Abstracts\AuthAbstract
|
||||
public: false
|
||||
autoconfigure: false
|
||||
|
||||
```
|
||||
|
||||
Puis déclarer dans la configuration ([[AuthBundle#Liste complète des options de configuration|Liste complète des options de configuration]]) du bundle le nom du service personnalisé :
|
||||
|
||||
```yaml
|
||||
besancon_auth:
|
||||
...
|
||||
authentication_service: mon_service.authentification
|
||||
|
||||
#OU si version Symfony >=3.4
|
||||
|
||||
authentication_service: AppBundle\Security\Auth\MonService
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
# Personnaliser la page en cas d'échec d'authentification
|
||||
|
||||
En cas d'échec lors de l'authentification (exemple ctrlAccess() retourne false) , par défaut, le bundle renvoie une page blanche avec le message renvoyé par l'exception qui a généré l'erreur.
|
||||
Afin de personnaliser cette page, il faut passer par la création d'un service comme indiqué dans le paragraphe [[AuthBundle#Création d'un service d'authentification|Création d'un service d'authentification]] et de redéfinir la méthode *onAuthenticationFailure*.
|
||||
|
||||
Voici un exemple :
|
||||
|
||||
```php
|
||||
|
||||
class MonService extends AuthAbstract implements AuthInterface
|
||||
{
|
||||
|
||||
|
||||
public function __construct(Twig_Environment $twig)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception)
|
||||
{
|
||||
|
||||
$content = $this->twig->render(
|
||||
'@App/Test/forbiden.html.twig', array()
|
||||
);
|
||||
$response = new Response($content, Response::HTTP_FORBIDDEN);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Nous pouvons remarquer que dans cet exemple, le service prend en paramètre dans le constructeur $twig qui est l'instance de Twig de notre applciation.
|
||||
Pour que cela fonctionne, il faut auparavant avoir passer le tag twig à notre service :
|
||||
|
||||
```php
|
||||
...
|
||||
AppBundle\Security\Auth\MonService:
|
||||
autowire: true
|
||||
parent: Besancon\AuthBundle\Security\Abstracts\AuthAbstract
|
||||
public: false
|
||||
autoconfigure: false
|
||||
arguments: ['@twig']
|
||||
...
|
||||
```
|
||||
|
||||
Ainsi lorsqu'une personne tentera de se connecter et qu'il n'aura, par exemple, pas les droits nécessaires le template @App/Test/forbiden.html.twig sera chargé.
|
|
@ -0,0 +1,40 @@
|
|||
parameters:
|
||||
#auth_cas devra s'appeler auth_multi
|
||||
#bes_auth.authentication_service: bes_auth.authentification
|
||||
session_auth:
|
||||
type_auth: Session
|
||||
environment: "%kernel.environment%"
|
||||
cas:
|
||||
#defini l'entité correspondant aux utilisateurs pour la création automatique des comptes
|
||||
server:
|
||||
cas_hostname: "seshat23.ac-besancon.fr"
|
||||
cas_port: 8443
|
||||
cas_uri: ""
|
||||
route:
|
||||
after_connect: "homepage"
|
||||
rsa :
|
||||
logout_url: http://webphppreprod.in.ac-besancon.fr/login/ct_logout.jsp
|
||||
login_url: ~
|
||||
route:
|
||||
after_connect: "homepage"
|
||||
#Gérer les droits d'accès à l'application en fonction des attributs CAS
|
||||
access:
|
||||
# allow:
|
||||
# attributes :
|
||||
# - ["[phpCAS][attributes][title]","[phpCAS][attributes][ABservice]"]
|
||||
# - "[phpCAS][attributes][FrEduRne]"
|
||||
# values : ["DIR|^DSS","^.*\\$TEC\\$"]
|
||||
#deny:
|
||||
#attributes : "title"
|
||||
#values : "ENS"
|
||||
#@TODO : Association profile CAS et Role de l'appli
|
||||
# profil:
|
||||
# cas:
|
||||
# ROLE_ADMIN:
|
||||
# key: "[phpCAS][attributes][typensi]"
|
||||
# value: "A"
|
||||
# ROLE_USER:
|
||||
# key: "[phpCAS][attributes][FrEduRne]"
|
||||
# value: "^0250069P"
|
||||
# control: "regex"
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
parameters:
|
||||
#auth_cas devra s'appeler auth_multi
|
||||
session_auth:
|
||||
environment: "%kernel.environment%"
|
||||
#defini l'entité correspondant aux utilisateurs pour la création automatique des comptes
|
||||
server:
|
||||
cas_hostname: "seshat23.ac-besancon.fr"
|
||||
cas_port: 8443
|
||||
cas_uri: ""
|
||||
route:
|
||||
after_connect: "homepage"
|
||||
#Gérer les droits d'accès à l'application en fonction des attributs CAS
|
||||
access:
|
||||
# allow:
|
||||
# attributes :
|
||||
# - ["[phpCAS][attributes][title]","[phpCAS][attributes][ABservice]"]
|
||||
# - "[phpCAS][attributes][FrEduRne]"
|
||||
# values : ["DIR|^DSS","^.*\\$TEC\\$"]
|
||||
deny:
|
||||
attributes : "title"
|
||||
values : "ENS"
|
||||
#@TODO : Association profile CAS et Role de l'appli
|
||||
# profil:
|
||||
# cas:
|
||||
# ROLE_ADMIN:
|
||||
# key: "[phpCAS][attributes][typensi]"
|
||||
# value: "A"
|
||||
# ROLE_USER:
|
||||
# key: "[phpCAS][attributes][FrEduRne]"
|
||||
# value: "^0250069P"
|
||||
# control: "regex"
|
||||
auth_rsa :
|
||||
environment: "%kernel.environment%"
|
||||
login_url: http://webphppreprod.in.ac-besancon.fr/login/ct_logon_mixte.jsp
|
||||
logout_url: http://webphppreprod.in.ac-besancon.fr/login/ct_logout.jsp
|
||||
route:
|
||||
after_connect: "homepage"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#besancon_auth_homepage:
|
||||
# path: /
|
||||
# defaults: { _controller: BesanconAuthBundle:Default:index }
|
|
@ -0,0 +1,11 @@
|
|||
services:
|
||||
|
||||
session_auth.authenticator_factory:
|
||||
class: App\Session\AuthBundle\Security\AuthenticatorFactory
|
||||
public: false
|
||||
|
||||
#bes_auth.authentification:
|
||||
# class: App\Besancon\AuthBundle\Security\Auth\Authentication
|
||||
# parent: App\Besancon\AuthBundle\Security\Abstracts\AuthFinal
|
||||
# public: false
|
||||
# autoconfigure: false
|
66
console/skel/symfony-app/src/Session/AuthBundle/Resources/doc/index.md
Executable file
66
console/skel/symfony-app/src/Session/AuthBundle/Resources/doc/index.md
Executable file
|
@ -0,0 +1,66 @@
|
|||
Installation
|
||||
============
|
||||
|
||||
1: Installation
|
||||
---------------------------
|
||||
|
||||
Copier et coller le dossier Besancon du Bundle dans src/
|
||||
|
||||
|
||||
2: Activer le Bundle
|
||||
-------------------------
|
||||
|
||||
Pour activer le Bundle, ouvrir le fichier `app/AppKernel.php` et y ajouter:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// app/AppKernel.php
|
||||
|
||||
// ...
|
||||
class AppKernel extends Kernel
|
||||
{
|
||||
public function registerBundles()
|
||||
{
|
||||
$bundles = array(
|
||||
// ...
|
||||
new Besancon\AuthBundle\BesanconAuthBundle(),
|
||||
);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Puis dans le fichier `composer.json` de votre projet ajouter:
|
||||
```json
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
...
|
||||
"Besancon\\AuthBundle\\": "src/Besancon/AuthBundle",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
3: Authentification Cas
|
||||
---------------------------
|
||||
|
||||
Si le Bundle est utilisé pour une athentification "Cas" alors télécharger la librairie phpCas dans votre projet
|
||||
|
||||
```console
|
||||
$ composer require jasig/phpcas
|
||||
```
|
||||
|
||||
Ouvrir le fichier `app/config/config.yml` et configurer :
|
||||
|
||||
```yml
|
||||
besancon_auth:
|
||||
homepage: "homepage" #nom de la route de l'accueil de l'application
|
||||
type_auth: Cas
|
||||
cas:
|
||||
hostname: "serveurcas.ac-academy.fr" #serveur cas
|
||||
port: 8443 #port cas
|
||||
uri: "" #uri
|
||||
|
||||
```
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* Abstract AuthAbstract
|
||||
*
|
||||
* @package Besancon\AuthBundle\Security\Abstracts
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*
|
||||
* @method setGetterAttributes()
|
||||
* @method getUser()
|
||||
* @abstract
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Abstracts;
|
||||
|
||||
use App\Session\AuthBundle\Utils\Config;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
abstract class AuthAbstract {
|
||||
|
||||
/**
|
||||
* @var App\Besancon\AuthBundle\Security\Interfaces\AttributesInterface $ai Instance de CasAttributes ou RsaAttributes
|
||||
*/
|
||||
protected $ai;
|
||||
|
||||
/**
|
||||
* Intancie le getters en fonction de la configuration
|
||||
*
|
||||
* Si dans la config le paramètre type_auth est défini à CAS alors
|
||||
* intanciation du getter CasAttributes,
|
||||
* Si la valeur est à RSA alors instanciation du getter RsaAttributes
|
||||
*
|
||||
* Cette instance peut ensuite être utilisée dans le service d'authentification
|
||||
* qui héritera de AuthAbstract, en passant faisant appel à $this->ai
|
||||
*
|
||||
* @final
|
||||
* @param $config
|
||||
* configuration du Bundle
|
||||
* @return void
|
||||
*
|
||||
* */
|
||||
abstract public function setGetterAttributes($config);
|
||||
|
||||
/**
|
||||
* Comportement par défaut lorsque l'authentification n'aboutie pas (accès non autorisé)
|
||||
*
|
||||
* il est possible de redéfinir cette méthode
|
||||
* mais elle doit renvoyer une réponse HTTP exemple:
|
||||
* - Symfony\Component\HttpFoundation\Response
|
||||
* - Symfony\Component\HttpFoundation\JsonResponse
|
||||
*
|
||||
* @param \Symfony\Component\Security\Core\Exception\AuthenticationException $exception
|
||||
* Exception généré par le guard
|
||||
* @return Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* */
|
||||
abstract public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception);
|
||||
|
||||
/**
|
||||
* Renvoie une instance de l'utilisateur
|
||||
*
|
||||
* Ceci correspond à la class Besancon\AuthBundle\Security\User\AuthUser,
|
||||
* il est possible de redéfinir cette méthode
|
||||
* mais elle doit renvoyer un objet implementant Symfony\Component\Security\Core\User\UserInterface
|
||||
*
|
||||
* Est utilisé dans le userprovider par défaut Besancon\AuthBundle\Security\User\AuthUserProvider
|
||||
*
|
||||
* @see \Symfony\Component\Security\Core\User\UserInterface
|
||||
* @see \Besancon\AuthBundle\Security\User\AuthUserProvider
|
||||
*
|
||||
* @param string $username
|
||||
* Identifiant de l'utilisateur
|
||||
* @return \Symfony\Component\Security\Core\User\UserInterface
|
||||
*
|
||||
*/
|
||||
abstract public function getUser($username);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* Abstract AuthAbstract
|
||||
*
|
||||
* @package Besancon\AuthBundle\Security\Abstracts
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*
|
||||
* @method setGetterAttributes()
|
||||
* @method getUser()
|
||||
* @abstract
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Abstracts;
|
||||
|
||||
use App\Session\AuthBundle\Utils\Config;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class AuthFinal extends AuthAbstract {
|
||||
|
||||
/**
|
||||
* Intancie le getters en fonction de la configuration
|
||||
*
|
||||
* Si dans la config le paramètre type_auth est défini à CAS alors
|
||||
* intanciation du getter CasAttributes,
|
||||
* Si la valeur est à RSA alors instanciation du getter RsaAttributes
|
||||
*
|
||||
* Cette instance peut ensuite être utilisée dans le service d'authentification
|
||||
* qui héritera de AuthAbstract, en passant faisant appel à $this->ai
|
||||
*
|
||||
* @final
|
||||
* @param $config
|
||||
* configuration du Bundle
|
||||
* @return void
|
||||
*
|
||||
* */
|
||||
public function setGetterAttributes($config) {
|
||||
$type_auth = Config::getDeclaredType($config);
|
||||
//dump('calls');
|
||||
$getters = "\App\Session\AuthBundle\Security\Getters\\" . $type_auth . "Attributes";
|
||||
$ai = new $getters();
|
||||
$this->ai = $ai;
|
||||
//dump($this->ai);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comportement par défaut lorsque l'authentification n'aboutie pas (accès non autorisé)
|
||||
*
|
||||
* il est possible de redéfinir cette méthode
|
||||
* mais elle doit renvoyer une réponse HTTP exemple:
|
||||
* - Symfony\Component\HttpFoundation\Response
|
||||
* - Symfony\Component\HttpFoundation\JsonResponse
|
||||
*
|
||||
* @param \Symfony\Component\Security\Core\Exception\AuthenticationException $exception
|
||||
* Exception généré par le guard
|
||||
* @return Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* */
|
||||
public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception) {
|
||||
return new Response($exception->getMessage(), Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renvoie une instance de l'utilisateur
|
||||
*
|
||||
* Ceci correspond à la class Besancon\AuthBundle\Security\User\AuthUser,
|
||||
* il est possible de redéfinir cette méthode
|
||||
* mais elle doit renvoyer un objet implementant Symfony\Component\Security\Core\User\UserInterface
|
||||
*
|
||||
* Est utilisé dans le userprovider par défaut Besancon\AuthBundle\Security\User\AuthUserProvider
|
||||
*
|
||||
* @see \Symfony\Component\Security\Core\User\UserInterface
|
||||
* @see \Besancon\AuthBundle\Security\User\AuthUserProvider
|
||||
*
|
||||
* @param string $username
|
||||
* Identifiant de l'utilisateur
|
||||
* @return \Symfony\Component\Security\Core\User\UserInterface
|
||||
*
|
||||
*/
|
||||
public function getUser($username) {
|
||||
$roles_service = $this->getRoles();
|
||||
$roles = (!is_null($roles_service) && is_array($roles_service)) ? $roles_service : array();
|
||||
$user = new \App\Besancon\AuthBundle\Security\User\AuthUser($username, md5("8sQaz87dPPsdanYakq86f" . $username), $roles);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Abstract class GetterAbstract
|
||||
*
|
||||
* @package Besancon\AuthBundle\Security\Abstracts
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Abstracts;
|
||||
|
||||
/**
|
||||
* Description of GetterAbstract
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
abstract class GetterAbstract {
|
||||
|
||||
public function isACP(){
|
||||
return $this->getFrEduFonctAdm() == "ACP";
|
||||
}
|
||||
|
||||
public function isDIR(){
|
||||
return $this->getFrEduFonctAdm() == "DIR";
|
||||
}
|
||||
|
||||
public function isDEC(){
|
||||
return $this->getFrEduFonctAdm() == "DEC";
|
||||
}
|
||||
|
||||
public function isDIR1D(){
|
||||
return $this->isDEC();
|
||||
}
|
||||
|
||||
public function isIEN1D (){
|
||||
return $this->getFrEduFonctAdm() == "IEN1D";
|
||||
}
|
||||
|
||||
public function isDIO(){
|
||||
return $this->getFrEduFonctAdm() == "IEN1D";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security;
|
||||
|
||||
use App\Session\AuthBundle\Security\Interfaces\AuthInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use App\Session\AuthBundle\Utils\Config;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class AuthenticatorFactory {
|
||||
|
||||
public static function getAuthenticator(AuthInterface $authService, Array $config, UrlGeneratorInterface $urlGenerator,EventDispatcherInterface $dispatcher) {
|
||||
$type_auth = Config::getDeclaredType($config);
|
||||
|
||||
$authenticator_class = "App\Session\AuthBundle\Security\\" . $type_auth . "Authenticator";
|
||||
$authenticator = new $authenticator_class($authService, $config, $urlGenerator, $dispatcher);
|
||||
|
||||
return $authenticator;
|
||||
}
|
||||
|
||||
}
|
114
console/skel/symfony-app/src/Session/AuthBundle/Security/CasAuthenticator.php
Executable file
114
console/skel/symfony-app/src/Session/AuthBundle/Security/CasAuthenticator.php
Executable file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of CasAuthenticator
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security;
|
||||
|
||||
use App\Session\AuthBundle\Security\Interfaces\AuthInterface;
|
||||
use App\Session\AuthBundle\Events\OnAuthenticationFailureEvent;
|
||||
use App\Session\AuthBundle\Events\OnAuthenticationSuccessEvent;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class CasAuthenticator extends AbstractFormLoginAuthenticator implements LogoutSuccessHandlerInterface, AuthenticatorInterface {
|
||||
|
||||
private $authService;
|
||||
private $urlGenerator;
|
||||
|
||||
public function __construct(AuthInterface $authService, Array $config, UrlGeneratorInterface $urlGenerator, EventDispatcherInterface $dispatcher) {
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
//Récupérer le service déaclaré authService
|
||||
$this->authService = $authService;
|
||||
$this->config = $config;
|
||||
$this->dispatcher = $dispatcher;
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
\phpCAS::client(CAS_VERSION_2_0, $this->config['cas']["hostname"], $this->config['cas']["port"], $this->config['cas']["uri"]);
|
||||
\phpCAS::setNoCasServerValidation();
|
||||
\phpCAS::forceAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request. Return whatever credentials you want,
|
||||
* or null to stop authentication.
|
||||
*/
|
||||
public function getCredentials(Request $request) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider) {
|
||||
$username = \phpCAS::getUser();
|
||||
$user = $userProvider->loadUserByUsername($username);
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user) {
|
||||
return $this->authService->ctrlAccess($user);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) {
|
||||
|
||||
$event = new OnAuthenticationSuccessEvent($request, $token, $providerKey);
|
||||
$this->dispatcher->dispatch(OnAuthenticationSuccessEvent::NAME, $event);
|
||||
|
||||
$this->authService->onSuccess($token);
|
||||
// on success, let the request continue
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
|
||||
|
||||
$event = new OnAuthenticationFailureEvent($request, $exception);
|
||||
$this->dispatcher->dispatch(OnAuthenticationFailureEvent::NAME, $event);
|
||||
|
||||
return $this->authService->onAuthenticationFailure($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when authentication is needed, but it's not sent
|
||||
*/
|
||||
// public function start(Request $request, AuthenticationException $authException = null) {
|
||||
// $url = $this->router->generate('login');
|
||||
// return new RedirectResponse($url);
|
||||
// }
|
||||
|
||||
public function supportsRememberMe() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//implementation LogoutSuccessHandlerInterface
|
||||
public function onLogoutSuccess(Request $request) {
|
||||
$homepage = $this->config["homepage"];
|
||||
return \phpCAS::logoutWithRedirectService($this->urlGenerator->generate($homepage, array(), UrlGeneratorInterface::ABSOLUTE_URL));
|
||||
}
|
||||
|
||||
protected function getLoginUrl() {
|
||||
return \phpCas::getServerLoginURL();
|
||||
}
|
||||
|
||||
public function supports(Request $request) {
|
||||
if (isset($this->config['environment']) && $this->config['environment'] == "test") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security;
|
||||
|
||||
use App\Session\AuthBundle\Security\Auth\Authentication;
|
||||
use App\Session\AuthBundle\Security\Auth\User;
|
||||
use App\Session\AuthBundle\Security\Auth\UserProvider;
|
||||
use App\Session\AuthBundle\Security\Interfaces\AuthInterface;
|
||||
use App\Session\AuthBundle\Security\Abstracts\AuthFinal;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager;
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider;
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
|
||||
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
|
||||
use Symfony\Component\Security\Core\User\InMemoryUserProvider;
|
||||
use Symfony\Component\Security\Core\User\UserChecker;
|
||||
|
||||
/**
|
||||
* Description of DefaultAuthentication
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
class DefaultAuthentication extends AuthFinal implements AuthInterface {
|
||||
|
||||
/**
|
||||
* @var string Uniquely identifies the secured area
|
||||
*/
|
||||
private $providerKey;
|
||||
|
||||
public function authentificate($token)
|
||||
{
|
||||
$username = $this->ai->getUsername();
|
||||
$password = "";
|
||||
|
||||
$unauthenticatedToken = new UsernamePasswordToken(
|
||||
$username,
|
||||
$password,
|
||||
'secured_area'
|
||||
);
|
||||
|
||||
$userProvider = new UserProvider( new Authentication(),
|
||||
array('user_entity' => 'App\Session\AuthBundle\Security\Auth\User',
|
||||
'type_auth' => 'Cas'));
|
||||
$userChecker = new UserChecker();
|
||||
|
||||
$defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000);
|
||||
|
||||
$encoders = [
|
||||
User::class => $defaultEncoder,
|
||||
];
|
||||
|
||||
$encoderFactory = new EncoderFactory($encoders);
|
||||
|
||||
$provider = new DaoAuthenticationProvider(
|
||||
$userProvider,
|
||||
$userChecker,
|
||||
'secured_area',
|
||||
$encoderFactory);
|
||||
|
||||
|
||||
$authenticatedToken = $provider
|
||||
->authenticate($unauthenticatedToken);
|
||||
|
||||
//$tokenStorage = new TokenStorage();
|
||||
|
||||
//$tokenStorage->setToken($authenticatedToken);
|
||||
}
|
||||
|
||||
public function getRoles() {
|
||||
return [];
|
||||
}
|
||||
|
||||
public function onSuccess($token) {
|
||||
|
||||
//dump($this->ai);
|
||||
//die('success');
|
||||
|
||||
//$this->authentificate($token);
|
||||
|
||||
$token->setAttribute("username", $this->ai->getUsername());
|
||||
$token->setAttribute("complet_name", $this->ai->getCompletName());
|
||||
$token->setAttribute("mail", $this->ai->getMail());
|
||||
$token->setAttribute("FreDuRne", $this->ai->getFreDuRne());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public function ctrlAccess(\Symfony\Component\Security\Core\User\UserInterface $user) {
|
||||
//die('ctrlAccess');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUser($username) {
|
||||
return parent::getUser($username);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* @package Besancon\AuthBundle\Security\Getters
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Getters;
|
||||
|
||||
use App\Session\AuthBundle\Security\Interfaces\AttributesInterface;
|
||||
|
||||
/**
|
||||
* Class CasAttributes
|
||||
*
|
||||
* Cette classe permet d'accèder aux informations (attributs) de l'utilisateur
|
||||
* renvoyé par CAS à partir des méthodes d'accès définies dans l'interface AttributesInterface
|
||||
*
|
||||
*/
|
||||
class CasAttributes implements AttributesInterface {
|
||||
|
||||
public function getFirstName() {
|
||||
return \phpCAS::getAttribute("prenom");
|
||||
}
|
||||
|
||||
public function getCompletName() {
|
||||
return \phpCAS::getAttribute("nomcomplet");
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return \phpCAS::getAttribute("nom");
|
||||
}
|
||||
|
||||
public function getDiscipline() {
|
||||
return \phpCAS::getAttribute("discipline");
|
||||
}
|
||||
|
||||
public function getFonctM() {
|
||||
return \phpCAS::getAttribute("fonctm");
|
||||
}
|
||||
|
||||
public function getRne() {
|
||||
return \phpCAS::getAttribute("rne");
|
||||
}
|
||||
|
||||
public function getFreDuRne() {
|
||||
return \phpCAS::getAttribute("FrEduRne");
|
||||
}
|
||||
|
||||
public function getFreDuRneResp() {
|
||||
return \phpCAS::getAttribute("FrEduRneResp");
|
||||
}
|
||||
|
||||
public function getMail() {
|
||||
return \phpCAS::getAttribute("mail");
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return \phpCAS::getAttribute("title");
|
||||
}
|
||||
|
||||
public function getUsername() {
|
||||
return \phpCAS::getUser();
|
||||
}
|
||||
|
||||
public function getFrEduResDel(){
|
||||
return \phpCAS::getAttribute("FrEduResDel");
|
||||
}
|
||||
|
||||
public function getFrEduFonctAdm() {
|
||||
return \phpCAS::getAttribute("FrEduFonctAdm");
|
||||
}
|
||||
|
||||
public function getGrade() {
|
||||
return \phpCAS::getAttribute("grade");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class RsaAttributes
|
||||
*
|
||||
* @package Besancon\AuthBundle\Security\Getters
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace App\Besancon\AuthBundle\Security\Getters;
|
||||
|
||||
use App\Besancon\AuthBundle\Security\Interfaces\AttributesInterface;
|
||||
|
||||
/**
|
||||
* Class RsaAttributes
|
||||
*
|
||||
* Cette classe permet d'accèder aux informations (entête HTTP) de l'utilisateur
|
||||
* renvoyé par RSA CT à partir des méthodes d'accès définies dans l'interface AttributesInterface
|
||||
*
|
||||
*/
|
||||
class RsaAttributes implements AttributesInterface {
|
||||
|
||||
public function getCompletName() {
|
||||
return (isset($_SERVER['HTTP_CN'])) ? $_SERVER['HTTP_CN'] : null;
|
||||
}
|
||||
|
||||
public function getDiscipline() {
|
||||
return (isset($_SERVER['HTTP_DISCIPLINE'])) ? $_SERVER['HTTP_DISCIPLINE'] : null;
|
||||
}
|
||||
|
||||
public function getFonctM() {
|
||||
return (isset($_SERVER['HTTP_FONCTM'])) ? $_SERVER['HTTP_FONCTM'] : null;
|
||||
}
|
||||
|
||||
public function getRne() {
|
||||
return (isset($_SERVER['HTTP_RNE'])) ? $_SERVER['HTTP_FREDURNE'] : null;
|
||||
}
|
||||
|
||||
public function getFreDuRne() {
|
||||
return (isset($_SERVER['HTTP_FREDURNE'])) ? explode(',', $_SERVER['HTTP_FREDURNE']) : null;
|
||||
}
|
||||
|
||||
public function getFreDuRneResp() {
|
||||
return (isset($_SERVER['HTTP_FREDURNERESP'])) ? explode(',', $_SERVER['HTTP_FREDURNERESP']) : null;
|
||||
}
|
||||
|
||||
public function getMail() {
|
||||
return (isset($_SERVER['HTTP_CTEMAIL'])) ? $_SERVER['HTTP_CTEMAIL'] : null;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return (isset($_SERVER['HTTP_TITLE'])) ? $_SERVER['HTTP_TITLE'] : null;
|
||||
}
|
||||
|
||||
public function getUsername() {
|
||||
return (isset($_SERVER['HTTP_CT_REMOTE_USER'])) ? $_SERVER['HTTP_CT_REMOTE_USER'] : null;
|
||||
}
|
||||
|
||||
public function getFrEduResDel() {
|
||||
return (isset($_SERVER['HTTP_FREDURESDEL'])) ? $_SERVER['HTTP_FREDURESDEL'] : null;
|
||||
}
|
||||
|
||||
public function getFrEduFonctAdm() {
|
||||
return (isset($_SERVER['HTTP_FREDUFONCTADM'])) ? $_SERVER['HTTP_FREDUFONCTADM'] : null;
|
||||
}
|
||||
|
||||
public function getFirstName() {
|
||||
return (isset($_SERVER['HTTP_CTFN'])) ? $_SERVER['HTTP_CTFN'] : null;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return (isset($_SERVER['HTTP_CTLN'])) ? $_SERVER['HTTP_CTLN'] : null;
|
||||
}
|
||||
|
||||
public function getGrade() {
|
||||
return (isset($_SERVER['HTTP_GRADE'])) ? $_SERVER['HTTP_GRADE'] : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* @package Besancon\AuthBundle\Security\Getters
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Getters;
|
||||
|
||||
use App\Session\AuthBundle\Security\Interfaces\AttributesInterface;
|
||||
|
||||
/**
|
||||
* Class CasAttributes
|
||||
*
|
||||
* Cette classe permet d'accèder aux informations (attributs) de l'utilisateur
|
||||
* renvoyé par CAS à partir des méthodes d'accès définies dans l'interface AttributesInterface
|
||||
*
|
||||
*/
|
||||
class SessionAttributes implements AttributesInterface {
|
||||
|
||||
public function getFirstName() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getCompletName() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getDiscipline() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getFonctM() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getRne() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getFreDuRne() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getFreDuRneResp() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getMail() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getUsername() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getFrEduResDel(){
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getFrEduFonctAdm() {
|
||||
return ;
|
||||
}
|
||||
|
||||
public function getGrade() {
|
||||
return ;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
/**
|
||||
* Interface AttributesInterface
|
||||
*
|
||||
* @package Besancon\AuthBundle\Security\Interfaces
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Interfaces;
|
||||
|
||||
/**
|
||||
* Interface AttributesInterface
|
||||
*
|
||||
*/
|
||||
interface AttributesInterface
|
||||
{
|
||||
|
||||
const NO_VALUE = "X";
|
||||
|
||||
const FREDURNE_OFFSET_RNE = 0;
|
||||
const FREDURNE_OFFSET_SECTEUR = 2;
|
||||
const FREDURNE_OFFSET_FONCTION_EXERCICE = 3;
|
||||
const FREDURNE_OFFSET_FONCTION_RNEUAJ = 4;
|
||||
const FREDURNE_OFFSET_1CODETNA = 5; // 1er chiffre code nature nomenclature
|
||||
const FREDURNE_OFFSET_CODETTY = 6; // code type etablissement nomenclature
|
||||
const FREDURNE_OFFSET_CODETNA = 7; // code nature etablissement nomenclature
|
||||
|
||||
|
||||
|
||||
const FREDURNERESP_OFFSET_RNE = 0;
|
||||
const FREDURNERESP_OFFSET_SECTEUR = 2; //PU ou PR
|
||||
const FREDURNERESP_OFFSET_AFFECTATION = 3; // A pour Affectation anticipé N pour affectation normale F pour affectation qui fini le 31/08
|
||||
const FREDURNERESP_OFFSET_1CODETNA = 4; // 1er chiffre code nature nomenclature
|
||||
const FREDURNERESP_OFFSET_CODETTY = 5; // code type etablissement nomenclature
|
||||
const FREDURNERESP_OFFSET_CODETNA = 6; // code nature nomenclature
|
||||
|
||||
|
||||
const TYPE_LYCEE_GENERAL = "LYC";
|
||||
const TYPE_LYCEE_PRO = "LP";
|
||||
const TYPE_COLLEGE = "CLG";
|
||||
const TYPE_SEGPA = "SES";
|
||||
|
||||
const CODE_NATURE_RECTORAT = ["802"];
|
||||
const CODE_NATURE_DSDEN = ["806"];
|
||||
const CODE_NATURE_INSPECTION = ["809"];
|
||||
const CODE_NATURE_LYCEE_GENERAL_ET_TECHNO = ["300"];
|
||||
const CODE_NATURE_LYCEE_TECHNO = ["301"];
|
||||
const CODE_NATURE_LYCEE_GENERAL = ["302", "306"];
|
||||
const CODE_NATURE_LYCEE_AGRICOLE = ["307"];
|
||||
const CODE_NATURE_LYCEE_PRO = ["320"];
|
||||
const CODE_NATURE_COLLEGE = ["340"];
|
||||
const CODE_COLLEGE_NATURE_SPE = ["352"];
|
||||
const CODE_NATURE_SEGPA = ["390"];
|
||||
|
||||
|
||||
const GRADES_IEN = ["1152", "1151"];
|
||||
|
||||
const GRADES_RECTEUR = ["0201"];
|
||||
const GRADES_SG = ["0211", "0911", "0912"];
|
||||
const GRADES_ASG = ["0981"];
|
||||
|
||||
const GRADES_DASEN = ["0921", "0922"];
|
||||
const GRADES_ADJOINT_DASEN = ["0971"];
|
||||
|
||||
const CODES_DISCIPLINE_ASH = ["N0006"];
|
||||
const CODES_DISCIPLINE_DIR = ["D0010"];
|
||||
const CODES_DISCIPLINE_ADJOINT_DIR = ["D0011"];
|
||||
/**
|
||||
* Renvoie le prénom de l'agent
|
||||
*
|
||||
* Correspond au champ "givenName" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* prénom de l'agent
|
||||
*/
|
||||
public function getFirstName();
|
||||
|
||||
/**
|
||||
* Renvoie l'identifiant LDAP de l'agent
|
||||
*
|
||||
* Correspond au champ "uid" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* uid de l'agent
|
||||
*/
|
||||
public function getUsername();
|
||||
|
||||
/**
|
||||
* Renvoie le nom de famille de l'agent
|
||||
*
|
||||
* Correspond au champ "sn" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* nom de l'agent
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Renvoie l'adresse mail de l'agent
|
||||
*
|
||||
* Correspond au champ "mail" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* adresse mail de l'agent
|
||||
*/
|
||||
public function getMail();
|
||||
|
||||
/**
|
||||
* Renvoie le nom complet de l'agent
|
||||
*
|
||||
* Correspond au champ "cn" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* nom complete de l'agent
|
||||
*/
|
||||
public function getCompletName();
|
||||
|
||||
/**
|
||||
* Renvoie le title de l'agent
|
||||
*
|
||||
* Correspond au champ "title" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* title de l'agent
|
||||
*/
|
||||
public function getTitle();
|
||||
|
||||
/**
|
||||
* Renvoie le code discipline de l'agent
|
||||
*
|
||||
* Correspond au champ "discipline" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* code discipline de l'agent
|
||||
*/
|
||||
public function getDiscipline();
|
||||
|
||||
/**
|
||||
* Renvoie l'établissements d'affectation de l'agent
|
||||
*
|
||||
* Correspond au champ "rne" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* * établissement d'affectation de l'agent
|
||||
*/
|
||||
public function getRne();
|
||||
|
||||
/**
|
||||
* Renvoie l'établissements d’exercice de l'agent
|
||||
*
|
||||
* Correspond au champ "FreDuRne" du LDAP
|
||||
*
|
||||
* @return array|null
|
||||
* établissement(s) d'exercice de l'agent
|
||||
*/
|
||||
public function getFreDuRne();
|
||||
|
||||
/**
|
||||
* Renvoie le(s) établissement(s) en responsabilité de l'agent
|
||||
*
|
||||
* Correspond au champ "FreDuRneResp" du LDAP
|
||||
*
|
||||
* @return array|null
|
||||
* établissement(s) en responsabalité de l'agent
|
||||
*/
|
||||
public function getFreDuRneResp();
|
||||
|
||||
/**
|
||||
* Renvoie le(s) déléguation(s)/attribution(s) de l'agent ouvrant des droits d'accès
|
||||
* à une ressource d'une application pour un ou des rne
|
||||
*
|
||||
* Correspond au champ "FreDuRneDel" du LDAP
|
||||
*
|
||||
* @return array|null
|
||||
* déléguation(s)/attribution(s) de l'agent
|
||||
*/
|
||||
public function getFrEduResDel();
|
||||
|
||||
/**
|
||||
* Renvoie la fonction administrative de l'agent
|
||||
* correspondant à un profil particulier
|
||||
*
|
||||
* Correspond au champ "FrEduFonctAdm" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* fonction administrative de l'agent
|
||||
*/
|
||||
public function getFrEduFonctAdm();
|
||||
|
||||
/**
|
||||
* Renvoie la fonction de l'agent
|
||||
* Attention : initialisé à la création de la fiche avec la même valeur que l’attribut fonction.
|
||||
* Puis, par l’application Annuaire, l’agent peut le modifier.
|
||||
*
|
||||
* Correspond au champ "fonctm" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* fonction de l'agent
|
||||
*/
|
||||
public function getFonctM();
|
||||
|
||||
/**
|
||||
* Renvoie le grade de l'agent
|
||||
* Alimenté à partir de la valeur agt.gradco
|
||||
* Se référer à la base des nomenclatures dans la table N_GRADE pour voir
|
||||
* les correspondances : http://infocentre.pleiade.education.fr/bcn/workspace/viewTable/n/N_GRADE
|
||||
*
|
||||
* Correspond au champ "grade" du LDAP
|
||||
*
|
||||
* @return string|null
|
||||
* fonction de l'agent
|
||||
*/
|
||||
public function getGrade();
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Interface AuthInterface
|
||||
*
|
||||
* Interface permettant de déclarer les méthodes incontournables pour l'authentification
|
||||
*
|
||||
*
|
||||
* @package Besancon\AuthBundle\Security\Interfaces
|
||||
* @author Amine BEL HADJ ALI <amine.belhadjali@ac-besancon.fr>
|
||||
*
|
||||
*/
|
||||
namespace App\Session\AuthBundle\Security\Interfaces;
|
||||
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
interface AuthInterface {
|
||||
|
||||
/**
|
||||
* Contrôle de l'accès à partir des attributs CAS ou RSA
|
||||
*
|
||||
* Vérifier les droits d'accès à l'application à partir des attributs récupérées des getters :
|
||||
* - CasAttributes
|
||||
* - RsaAttributes
|
||||
*
|
||||
* @param UserInterface $user
|
||||
* L'entité user récupéré par le provider
|
||||
*
|
||||
* @return bool
|
||||
* - true si accès autorisé
|
||||
* - false si accès refusé
|
||||
*/
|
||||
public function ctrlAccess(UserInterface $user);
|
||||
|
||||
/**
|
||||
* Calcule et retoune le(s) rôle(s) à partir des attributs CAS ou RSA
|
||||
*
|
||||
* Calculer le(s) rôle(s) à partir des attributs récupérées des getters :
|
||||
* - CasAttributes
|
||||
* - RsaAttributes
|
||||
* Doit retourner un tableau même vide
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRoles();
|
||||
|
||||
/**
|
||||
* Retourne un utilisateur pour la génération du token, si l'utilisateur n'existe pas en base de donnée
|
||||
*
|
||||
* ATTENTION : CETTE METHODE DOIT ÊTRE REDEFINIE SI UTILISATION D'UNE ENTITE UTILISTEUR
|
||||
* DIFFERENTE DE CELLE UTILISEE PAR DEFAUT
|
||||
*
|
||||
* @param String $username
|
||||
* uid de l'utilisateur récupéré de Cas ou Rsa
|
||||
*
|
||||
* @return UserInterface
|
||||
*/
|
||||
public function getUser($username);
|
||||
|
||||
/**
|
||||
* Traitement personnalisé après récupération du token
|
||||
*
|
||||
* Il est possible d'enrichir le token (attributs...) ou d'effectuer des contrôles supplémentaire
|
||||
*
|
||||
* @param $token
|
||||
* Token d'authification généré
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function onSuccess($token);
|
||||
|
||||
/**
|
||||
* Traitement personnalisé lorsque la connexion n'a pas abouti
|
||||
*
|
||||
* Vérifié l'exception généré et adapter l'action (redirection, déconnexion...)
|
||||
*
|
||||
* Doit retourner un objet de type Response
|
||||
*
|
||||
* Exemple :
|
||||
*
|
||||
* ```
|
||||
* public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception)
|
||||
* {
|
||||
* $content = $this->twig->render(
|
||||
* '@App/Test/forbiden.html.twig', array()
|
||||
* );
|
||||
* $response = new Response($content, Response::HTTP_FORBIDDEN);
|
||||
* return $response;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param AuthenticationException $exception
|
||||
* Exception générée par le provider
|
||||
*
|
||||
* @return Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
*/
|
||||
public function onAuthenticationFailure(\Symfony\Component\Security\Core\Exception\AuthenticationException $exception);
|
||||
}
|
120
console/skel/symfony-app/src/Session/AuthBundle/Security/RsaAuthenticator.php
Executable file
120
console/skel/symfony-app/src/Session/AuthBundle/Security/RsaAuthenticator.php
Executable file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of CasAuthenticator
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security;
|
||||
|
||||
use App\Session\AuthBundle\Security\Interfaces\AuthInterface;
|
||||
use App\Session\AuthBundle\Events\OnAuthenticationFailureEvent;
|
||||
use App\Session\AuthBundle\Events\OnAuthenticationSuccessEvent;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class RsaAuthenticator extends AbstractFormLoginAuthenticator implements LogoutSuccessHandlerInterface, AuthenticatorInterface {
|
||||
|
||||
private $authService;
|
||||
private $urlGenerator;
|
||||
private $dispatcher;
|
||||
|
||||
public function __construct(AuthInterface $authService, Array $config, UrlGeneratorInterface $urlGenerator, EventDispatcherInterface $dispatcher) {
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
//Récupérer le service déaclaré authService
|
||||
$this->authService = $authService;
|
||||
$this->config = $config;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request. Return whatever credentials you want,
|
||||
* or null to stop authentication.
|
||||
*/
|
||||
public function getCredentials(Request $request) {
|
||||
if (!isset($_SERVER['HTTP_CT_REMOTE_USER']) || empty($_SERVER['HTTP_CT_REMOTE_USER'])) {
|
||||
$this->returnRequest = $request->getUri();
|
||||
throw new \LogicException("Impossible de continuer sous RSA : L'entête HTTP_CT_REMOTE_USER est vide ou manquante");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider) {
|
||||
$username = $_SERVER['HTTP_CT_REMOTE_USER'];
|
||||
$user = $userProvider->loadUserByUsername($username);
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user) {
|
||||
$this->authService->ctrlAccess($user);
|
||||
// check credentials - e.g. make sure the password is valid
|
||||
// no credential check is needed in this case
|
||||
// return true to cause authentication success
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) {
|
||||
|
||||
$event = new OnAuthenticationSuccessEvent($request, $token, $providerKey);
|
||||
$this->dispatcher->dispatch(OnAuthenticationSuccessEvent::NAME, $event);
|
||||
|
||||
$this->authService->onSuccess($token);
|
||||
// on success, let the request continue
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
|
||||
|
||||
$event = new OnAuthenticationFailureEvent($request, $exception);
|
||||
$this->dispatcher->dispatch(OnAuthenticationFailureEvent::NAME, $event);
|
||||
|
||||
return $this->authService->onAuthenticationFailure($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when authentication is needed, but it's not sent
|
||||
*/
|
||||
// public function start(Request $request, AuthenticationException $authException = null) {
|
||||
// $url = $this->router->generate('login');
|
||||
// return new RedirectResponse($url);
|
||||
// }
|
||||
|
||||
public function supportsRememberMe() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//implementation LogoutSuccessHandlerInterface
|
||||
public function onLogoutSuccess(Request $request) {
|
||||
$redirect = (isset($_SERVER['HTTP_FREDUURLRETOUR'])) ? $_SERVER['HTTP_FREDUURLRETOUR'] : $this->config['rsa']['logout_url'];
|
||||
return new RedirectResponse($redirect);
|
||||
}
|
||||
|
||||
protected function getLoginUrl() {
|
||||
$return_request = urlencode($this->returnRequest);
|
||||
$params = "?CT_ORIG_URL=" . $return_request;
|
||||
return $this->config['rsa']['login_url'] . $params;
|
||||
}
|
||||
|
||||
public function supports(Request $request) {
|
||||
if (isset($this->config['environment']) && $this->config['environment'] == "test") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Session\AuthBundle\Security;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
|
||||
|
||||
class SessionAuthenticator extends AbstractGuardAuthenticator
|
||||
{
|
||||
public $router;
|
||||
|
||||
public function __construct(UrlGeneratorInterface $router)
|
||||
{
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request to decide if this authenticator should be
|
||||
* used for the request. Returning `false` will cause this authenticator
|
||||
* to be skipped.
|
||||
*/
|
||||
public function supports(Request $request)
|
||||
{
|
||||
if (isset($_SESSION['id_utilisateur'])) {
|
||||
return true;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every request. Return whatever credentials you want to
|
||||
* be passed to getUser() as $credentials.
|
||||
*/
|
||||
public function getCredentials(Request $request)
|
||||
{
|
||||
return "X-AUTH-TOKEN-SESSION-API";
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider)
|
||||
{
|
||||
if (!isset($_SESSION['id_utilisateur'])) {
|
||||
$user = new \App\Classes\AuthUser('','','','','',['ROLE_USER']);
|
||||
}else {
|
||||
$user = new \App\Classes\AuthUser($_SESSION['id_utilisateur'], $_SESSION['identifiant'], $_SESSION['status_compte'], $_SESSION['type_compte'],$credentials, ['ROLE_USER', 'ROLE_USER_CONNECTED']);
|
||||
}
|
||||
|
||||
// if a User is returned, checkCredentials() is called
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user)
|
||||
{
|
||||
// Check credentials - e.g. make sure the password is valid.
|
||||
// In case of an API token, no credential check is needed.
|
||||
|
||||
// Return `true` to cause authentication success
|
||||
if($user->getCredentials() === $credentials) {
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
|
||||
{
|
||||
// on success, let the request continue
|
||||
//return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
|
||||
{
|
||||
$data = [
|
||||
// you may want to customize or obfuscate the message first
|
||||
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
|
||||
|
||||
// or to translate this message
|
||||
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
|
||||
];
|
||||
|
||||
// return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
|
||||
$url = $this->router->generate('unauthorized');
|
||||
return new RedirectResponse($url);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when authentication is needed, but it's not sent
|
||||
*/
|
||||
public function start(Request $request, AuthenticationException $authException = null)
|
||||
{
|
||||
$data = [
|
||||
// you might translate this message
|
||||
'message' => 'Authentication Required'
|
||||
];
|
||||
|
||||
//return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
|
||||
|
||||
$url = $this->router->generate('unauthorized');
|
||||
return new RedirectResponse($url);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function supportsRememberMe()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onLogoutSuccess(Request $request) {
|
||||
//$homepage = $this->config["homepage"];
|
||||
//return \phpCAS::logoutWithRedirectService($this->urlGenerator->generate($homepage, array(), UrlGeneratorInterface::ABSOLUTE_URL));
|
||||
header('Location: /index.php');
|
||||
return ;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle\Security\Traits;
|
||||
|
||||
use App\Session\AuthBundle\Security\Interfaces\AttributesInterface;
|
||||
|
||||
trait ProfilsCalculator
|
||||
{
|
||||
//est recteur
|
||||
public function isRecteur()
|
||||
{
|
||||
return in_array($this->ai->getDiscipline(), AttributesInterface::GRADES_RECTEUR);
|
||||
}
|
||||
|
||||
//est secrétaire général d'académie
|
||||
public function isSG()
|
||||
{
|
||||
return in_array($this->ai->getDiscipline(), AttributesInterface::GRADES_SG);
|
||||
}
|
||||
|
||||
//est adjoint au secrétaire général d'académie
|
||||
public function isASG()
|
||||
{
|
||||
return in_array($this->ai->getDiscipline(), AttributesInterface::GRADES_ASG);
|
||||
}
|
||||
|
||||
//agent comptable
|
||||
public function isACP()
|
||||
{
|
||||
return $this->ai->getFrEduFonctAdm() == "ACP";
|
||||
}
|
||||
|
||||
//enseignant
|
||||
public function isENS()
|
||||
{
|
||||
return $this->ai->getFrEduFonctAdm() == AttributesInterface::NO_VALUE && $this->ai->getTitle() == "ENS" && $this->ai->getFrEduRneResp() == AttributesInterface::NO_VALUE;
|
||||
}
|
||||
|
||||
//agent issue d'AGAPE PRIVE
|
||||
public function isAgentPrive()
|
||||
{
|
||||
return $this->ai->getTypensi() == "R";
|
||||
}
|
||||
|
||||
//equipe de direction établissement
|
||||
public function isGroupeDIR()
|
||||
{
|
||||
return $this->ai->getFrEduFonctAdm() == "DIR";
|
||||
}
|
||||
|
||||
//directeur 2nd degré
|
||||
public function isDIR()
|
||||
{
|
||||
return $this->isGroupeDIR() && in_array($this->ai->getDiscipline(), AttributesInterface::CODES_DISCIPLINE_DIR);
|
||||
}
|
||||
|
||||
//directeur adjoint 2nd degré
|
||||
public function isAdjointDIR()
|
||||
{
|
||||
return $this->isGroupeDIR() && in_array($this->ai->getDiscipline(), AttributesInterface::CODES_DISCIPLINE_ADJOINT_DIR);
|
||||
}
|
||||
|
||||
//directeur d'ecole
|
||||
public function isDEC()
|
||||
{
|
||||
return $this->ai->getFrEduFonctAdm() == "DEC";
|
||||
}
|
||||
|
||||
//alias directeur d'ecole
|
||||
public function isDIR1D()
|
||||
{
|
||||
return $this->isDEC();
|
||||
}
|
||||
|
||||
//adaptation scolaire et de la scolarisation des élèves handicapé
|
||||
public function isASH()
|
||||
{
|
||||
return in_array($this->ai->getDiscipline(), AttributesInterface::CODES_DISCIPLINE_ASH);
|
||||
}
|
||||
//est inspecteur
|
||||
public function isIEN()
|
||||
{
|
||||
return (!is_null($this->ai->getGrade())) ? in_array($this->ai->getGrade(), AttributesInterface::GRADES_IEN) : $this->ai->getTitle() == "INS";
|
||||
}
|
||||
|
||||
//est inspecteur 1er degré
|
||||
public function isIEN1D()
|
||||
{
|
||||
return $this->isIEN() && $this->ai->getFrEduFonctAdm() == "IEN1D";
|
||||
}
|
||||
|
||||
//est inspecteur ASH
|
||||
public function isIENASH()
|
||||
{
|
||||
return $this->isASH() && $this->isIEN();
|
||||
}
|
||||
|
||||
//est DASEN
|
||||
public function isDASEN()
|
||||
{
|
||||
return in_array($this->ai->getGrade(), AttributesInterface::GRADES_DASEN);
|
||||
}
|
||||
|
||||
//est adjoint DASEN
|
||||
public function isAdjointDasen()
|
||||
{
|
||||
return in_array($this->ai->getGrade(), AttributesInterface::GRADES_ADJOINT_DASEN);
|
||||
}
|
||||
|
||||
//est directeur CIO
|
||||
public function isDIO()
|
||||
{
|
||||
return $this->ai->getFrEduFonctAdm() == "DIO";
|
||||
}
|
||||
|
||||
public function filterFrEduRneByType($type)
|
||||
{
|
||||
if ($this->ai->getFrEduRne() == AttributesInterface::NO_VALUE) {
|
||||
return [];
|
||||
}
|
||||
$FrEduRne = (!is_array($this->ai->getFrEduRne())) ? [$this->ai->getFrEduRne()] : $this->ai->getFrEduRne();
|
||||
|
||||
$uais = array_filter($FrEduRne, function ($value) use ($type) {
|
||||
$arr_value = explode("$", $value);
|
||||
if (!is_array($arr_value) || !array_key_exists(AttributesInterface::FREDURNE_OFFSET_CODETTY, $arr_value)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($type)) {
|
||||
return in_array($arr_value[AttributesInterface::FREDURNE_OFFSET_CODETTY], $type);
|
||||
}
|
||||
return $arr_value[AttributesInterface::FREDURNE_OFFSET_CODETTY] == $type;
|
||||
});
|
||||
|
||||
return $uais;
|
||||
}
|
||||
|
||||
public function filterFrEduRneByNature($nature)
|
||||
{
|
||||
if ($this->ai->getFrEduRne() == AttributesInterface::NO_VALUE) {
|
||||
return [];
|
||||
}
|
||||
$FrEduRne = (!is_array($this->ai->getFrEduRne())) ? [$this->ai->getFrEduRne()] : $this->ai->getFrEduRne();
|
||||
$uais = array_filter($FrEduRne, function ($value) use ($nature) {
|
||||
$arr_value = explode("$", $value);
|
||||
if (!is_array($arr_value) || !array_key_exists(AttributesInterface::FREDURNE_OFFSET_CODETNA, $arr_value)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($nature)) {
|
||||
return in_array($arr_value[AttributesInterface::FREDURNE_OFFSET_CODETNA], $nature);
|
||||
}
|
||||
return $arr_value[AttributesInterface::FREDURNE_OFFSET_CODETNA] == $nature;
|
||||
});
|
||||
|
||||
return $uais;
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespByNature($nature)
|
||||
{
|
||||
if ($this->ai->getFrEduRneResp() == AttributesInterface::NO_VALUE) {
|
||||
return [];
|
||||
}
|
||||
$FrEduRneResp = (!is_array($this->ai->getFrEduRneResp())) ? [$this->ai->getFrEduRneResp()] : $this->ai->getFrEduRneResp();
|
||||
|
||||
$uais = array_filter($FrEduRneResp, function ($value) use ($nature) {
|
||||
$arr_value = explode("$", $value);
|
||||
if (!is_array($arr_value) || !array_key_exists(AttributesInterface::FREDURNERESP_OFFSET_CODETNA, $arr_value)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($nature)) {
|
||||
return in_array($arr_value[AttributesInterface::FREDURNERESP_OFFSET_CODETNA], $nature);
|
||||
}
|
||||
return $arr_value[AttributesInterface::FREDURNERESP_OFFSET_CODETNA] == $nature;
|
||||
});
|
||||
|
||||
return $uais;
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespByType($type)
|
||||
{
|
||||
if ($this->ai->getFrEduRneResp() == AttributesInterface::NO_VALUE) {
|
||||
return [];
|
||||
}
|
||||
$FrEduRneResp = (!is_array($this->ai->getFrEduRneResp())) ? [$this->ai->getFrEduRneResp()] : $this->ai->getFrEduRneResp();
|
||||
|
||||
$uais = array_filter($FrEduRneResp, function ($value) use ($type) {
|
||||
$arr_value = explode("$", $value);
|
||||
if (!is_array($arr_value) || !array_key_exists(AttributesInterface::FREDURNERESP_OFFSET_CODETTY, $arr_value)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($type)) {
|
||||
return in_array($arr_value[AttributesInterface::FREDURNERESP_OFFSET_CODETTY], $type);
|
||||
}
|
||||
return $arr_value[AttributesInterface::FREDURNERESP_OFFSET_CODETTY] == $type;
|
||||
});
|
||||
|
||||
return $uais;
|
||||
}
|
||||
|
||||
// public function hasLYC()
|
||||
// {
|
||||
// return $this->findUaiRespByType(AttributesInterface::TYPE_LYCEE_GENERAL);
|
||||
// }
|
||||
|
||||
// public function hasLYCP()
|
||||
// {
|
||||
// return $this->findUaiRespByType(AttributesInterface::TYPE_LYCEE_PRO);
|
||||
// }
|
||||
|
||||
|
||||
public function isAffectedToRectorat()
|
||||
{
|
||||
$result = $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_RECTORAT);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isAffectedToDSDEN()
|
||||
{
|
||||
$result = $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_DSDEN);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isAffectedToLYC()
|
||||
{
|
||||
$result = $this->filterFrEduRneByType(AttributesInterface::TYPE_LYCEE_GENERAL);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isAffectedToLP()
|
||||
{
|
||||
$result = $this->filterFrEduRneByType(AttributesInterface::TYPE_LYCEE_PRO);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isAffectedToInspection()
|
||||
{
|
||||
$result = $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_INSPECTION);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isAffectedToSEGPA()
|
||||
{
|
||||
$result = $this->filterFrEduRneByType(AttributesInterface::TYPE_SEGPA);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isRespOfLYC()
|
||||
{
|
||||
$result = $this->filterFrEduRneRespByType(AttributesInterface::TYPE_LYCEE_GENERAL);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isRespOfLP()
|
||||
{
|
||||
$result = $this->filterFrEduRneRespByType(AttributesInterface::TYPE_LYCEE_PRO);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
public function isRespOfSEGPA()
|
||||
{
|
||||
$result = $this->filterFrEduRneRespByType(AttributesInterface::TYPE_SEGPA);
|
||||
return (count($result)) ? true : false;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Filtres sur FrEduRne
|
||||
***************************************************************************************/
|
||||
|
||||
public function filterFrEduRneByLYCG()
|
||||
{
|
||||
return $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_LYCEE_GENERAL);
|
||||
}
|
||||
|
||||
public function filterFrEduRneByLYCGT()
|
||||
{
|
||||
return $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_LYCEE_GENERAL_ET_TECHNO);
|
||||
}
|
||||
|
||||
public function filterFrEduRneByLP()
|
||||
{
|
||||
return $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_LYCEE_GENERAL_ET_TECHNO);
|
||||
}
|
||||
|
||||
public function filterFrEduRneByCLG()
|
||||
{
|
||||
return $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_COLLEGE);
|
||||
}
|
||||
|
||||
public function filterFrEduRneByLYCAG()
|
||||
{
|
||||
return $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_LYCEE_AGRICOLE);
|
||||
}
|
||||
|
||||
public function filterFrEduRneBySEGPA()
|
||||
{
|
||||
return $this->filterFrEduRneByNature(AttributesInterface::CODE_NATURE_SEGPA);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Filtres sur FrEduRneResp
|
||||
***************************************************************************************/
|
||||
|
||||
public function filterFrEduRneRespByLYCG()
|
||||
{
|
||||
return $this->filterFrEduRneRespByNature(AttributesInterface::CODE_NATURE_LYCEE_GENERAL);
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespByLYCGT()
|
||||
{
|
||||
return $this->filterFrEduRneRespByNature(AttributesInterface::CODE_NATURE_LYCEE_GENERAL_ET_TECHNO);
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespByLP()
|
||||
{
|
||||
return $this->filterFrEduRneRespByNature(AttributesInterface::CODE_NATURE_LYCEE_GENERAL_ET_TECHNO);
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespByCLG()
|
||||
{
|
||||
return $this->filterFrEduRneRespByNature(AttributesInterface::CODE_NATURE_COLLEGE);
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespByLYCAG()
|
||||
{
|
||||
return $this->filterFrEduRneRespByNature(AttributesInterface::CODE_NATURE_LYCEE_AGRICOLE);
|
||||
}
|
||||
|
||||
public function filterFrEduRneRespBySEGPA()
|
||||
{
|
||||
return $this->filterFrEduRneRespByNature(AttributesInterface::CODE_NATURE_SEGPA);
|
||||
}
|
||||
}
|
76
console/skel/symfony-app/src/Session/AuthBundle/Security/User/AuthUser.php
Executable file
76
console/skel/symfony-app/src/Session/AuthBundle/Security/User/AuthUser.php
Executable file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of AuthUser
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\User;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\EquatableInterface;
|
||||
|
||||
class AuthUser implements UserInterface, EquatableInterface {
|
||||
|
||||
private $username;
|
||||
private $salt;
|
||||
private $roles = [];
|
||||
|
||||
public function __construct($username, $salt, array $roles = []) {
|
||||
$this->username = $username;
|
||||
$this->salt = $salt;
|
||||
$this->roles = $roles;
|
||||
}
|
||||
|
||||
public function getRoles() {
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
public function setRoles($roles) {
|
||||
return $this->roles = $roles;
|
||||
}
|
||||
|
||||
public function addRole($role) {
|
||||
return $this->roles[] = $role;
|
||||
}
|
||||
|
||||
public function getPassword() {
|
||||
return;
|
||||
}
|
||||
|
||||
public function getSalt() {
|
||||
return $this->salt;
|
||||
}
|
||||
|
||||
public function getUsername() {
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function eraseCredentials() {
|
||||
|
||||
}
|
||||
|
||||
public function isEqualTo(UserInterface $user) {
|
||||
if (!$user instanceof AuthUser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->salt !== $user->getSalt()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->username !== $user->getUsername()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace App\Session\AuthBundle\Security\User;
|
||||
|
||||
use App\Besancon\AuthBundle\Security\Interfaces\AuthInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
|
||||
class AuthUserProvider implements UserProviderInterface {
|
||||
|
||||
public function __construct(AuthInterface $authService, Array $config) {
|
||||
$this->config = $config;
|
||||
|
||||
if (!is_null($this->config['user_entity'])) {
|
||||
$this->entity_user = "\\".$this->config['user_entity'];
|
||||
} else {
|
||||
$this->entity_user = "App\Session\AuthBundle\Security\User\AuthUser";
|
||||
}
|
||||
$this->authService = $authService;
|
||||
}
|
||||
|
||||
public function loadUserByUsername($username) {
|
||||
$entity_user = $this->entity_user;
|
||||
|
||||
return $this->authService->getUser($username);
|
||||
}
|
||||
|
||||
private function _ctrlInstanceUser(UserInterface $user) {
|
||||
$entity_user = $this->entity_user;
|
||||
|
||||
if (!$user instanceof $entity_user) {
|
||||
throw new UnsupportedUserException(
|
||||
sprintf('Instances of "%s" are not supported.', get_class($user))
|
||||
);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function refreshUser(UserInterface $user) {
|
||||
$user = $this->_ctrlInstanceUser($user);
|
||||
|
||||
return $this->loadUserByUsername($user->getUsername());
|
||||
}
|
||||
|
||||
public function supportsClass($class) {
|
||||
$entity_user = $this->entity_user;
|
||||
return $this->entity_class === $class;
|
||||
}
|
||||
|
||||
}
|
9
console/skel/symfony-app/src/Session/AuthBundle/SessionAuthBundle.php
Executable file
9
console/skel/symfony-app/src/Session/AuthBundle/SessionAuthBundle.php
Executable file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class SessionAuthBundle extends Bundle
|
||||
{
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Session\AuthBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class DefaultControllerTest extends WebTestCase
|
||||
{
|
||||
public function testIndex()
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$crawler = $client->request('GET', '/');
|
||||
|
||||
$this->assertContains('Hello World', $client->getResponse()->getContent());
|
||||
}
|
||||
}
|
39
console/skel/symfony-app/src/Session/AuthBundle/Utils/Config.php
Executable file
39
console/skel/symfony-app/src/Session/AuthBundle/Utils/Config.php
Executable file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace App\Session\AuthBundle\Utils;
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of Controls
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
class Config {
|
||||
|
||||
public static function getDeclaredType($config) {
|
||||
if (!isset($config['type_auth'])) {
|
||||
throw new \LogicException('Paramètre type_auth manquant');
|
||||
}
|
||||
|
||||
$type = $config['type_auth'];
|
||||
|
||||
self::typeIsSupported($type);
|
||||
|
||||
return self::formatType($type);
|
||||
}
|
||||
|
||||
public static function formatType($type) {
|
||||
return ucfirst(strtolower($type));
|
||||
}
|
||||
|
||||
public static function typeIsSupported($type) {
|
||||
$type_auth = self::formatType($type);
|
||||
if (!in_array($type_auth, ['Rsa', 'Cas'])) {
|
||||
throw new \LogicException('Seuls Cas et Rsa sont supportés pour le moment');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
12
console/skel/symfony-app/src/Session/AuthBundle/composer.json
Executable file
12
console/skel/symfony-app/src/Session/AuthBundle/composer.json
Executable file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "ac-besancon/authbundle",
|
||||
"description": "Bundle Symfony 3 permettant de mettre en palce une authentification CAS ou RSA à travers le système de Guard",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Amine Belhadjali",
|
||||
"email": "amine.belhadjali@ac-besancon.fr"
|
||||
}
|
||||
]
|
||||
}
|
44
console/skel/symfony-app/src/Utils/Config.php
Normal file
44
console/skel/symfony-app/src/Utils/Config.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of Controls
|
||||
*
|
||||
* @author belhadjali
|
||||
*/
|
||||
class Config {
|
||||
|
||||
public static function getDeclaredType($config) {
|
||||
// if (!isset($config['type_auth'])) {
|
||||
// throw new \LogicException('Paramètre type_auth manquant');
|
||||
// }
|
||||
//
|
||||
// $type = $config['type_auth'];
|
||||
//
|
||||
// self::typeIsSupported($type);
|
||||
//
|
||||
// return self::formatType($type);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function formatType($type) {
|
||||
// return ucfirst(strtolower($type));
|
||||
return;
|
||||
}
|
||||
|
||||
public static function typeIsSupported($type) {
|
||||
// $type_auth = self::formatType($type);
|
||||
// if (!in_array($type_auth, ['Rsa', 'Cas'])) {
|
||||
// throw new \LogicException('Seuls Cas et Rsa sont supportés pour le moment');
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
}
|
3
console/skel/symfony/cache-contracts/.gitignore
vendored
Normal file
3
console/skel/symfony/cache-contracts/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
57
console/skel/symfony/cache-contracts/CacheInterface.php
Normal file
57
console/skel/symfony/cache-contracts/CacheInterface.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Contracts\Cache;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Covers most simple to advanced caching needs.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface CacheInterface
|
||||
{
|
||||
/**
|
||||
* Fetches a value from the pool or computes it if not found.
|
||||
*
|
||||
* On cache misses, a callback is called that should return the missing value.
|
||||
* This callback is given a PSR-6 CacheItemInterface instance corresponding to the
|
||||
* requested key, that could be used e.g. for expiration control. It could also
|
||||
* be an ItemInterface instance when its additional features are needed.
|
||||
*
|
||||
* @param string $key The key of the item to retrieve from the cache
|
||||
* @param callable|CallbackInterface $callback Should return the computed value for the given key/item
|
||||
* @param float|null $beta A float that, as it grows, controls the likeliness of triggering
|
||||
* early expiration. 0 disables it, INF forces immediate expiration.
|
||||
* The default (or providing null) is implementation dependent but should
|
||||
* typically be 1.0, which should provide optimal stampede protection.
|
||||
* See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration
|
||||
* @param array &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()}
|
||||
*
|
||||
* @return mixed The value corresponding to the provided key
|
||||
*
|
||||
* @throws InvalidArgumentException When $key is not valid or when $beta is negative
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null);
|
||||
|
||||
/**
|
||||
* Removes an item from the pool.
|
||||
*
|
||||
* @param string $key The key to delete
|
||||
*
|
||||
* @throws InvalidArgumentException When $key is not valid
|
||||
*
|
||||
* @return bool True if the item was successfully removed, false if there was any error
|
||||
*/
|
||||
public function delete(string $key): bool;
|
||||
}
|
76
console/skel/symfony/cache-contracts/CacheTrait.php
Normal file
76
console/skel/symfony/cache-contracts/CacheTrait.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Contracts\Cache;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
trait CacheTrait
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
|
||||
{
|
||||
return $this->doGet($this, $key, $callback, $beta, $metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(string $key): bool
|
||||
{
|
||||
return $this->deleteItem($key);
|
||||
}
|
||||
|
||||
private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null)
|
||||
{
|
||||
if (0 > $beta = $beta ?? 1.0) {
|
||||
throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', \get_class($this), $beta)) extends \InvalidArgumentException implements InvalidArgumentException {
|
||||
};
|
||||
}
|
||||
|
||||
$item = $pool->getItem($key);
|
||||
$recompute = !$item->isHit() || INF === $beta;
|
||||
$metadata = $item instanceof ItemInterface ? $item->getMetadata() : [];
|
||||
|
||||
if (!$recompute && $metadata) {
|
||||
$expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false;
|
||||
$ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false;
|
||||
|
||||
if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, PHP_INT_MAX) / PHP_INT_MAX)) {
|
||||
// force applying defaultLifetime to expiry
|
||||
$item->expiresAt(null);
|
||||
$logger && $logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [
|
||||
'key' => $key,
|
||||
'delta' => sprintf('%.1f', $expiry - $now),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($recompute) {
|
||||
$save = true;
|
||||
$item->set($callback($item, $save));
|
||||
if ($save) {
|
||||
$pool->save($item);
|
||||
}
|
||||
}
|
||||
|
||||
return $item->get();
|
||||
}
|
||||
}
|
30
console/skel/symfony/cache-contracts/CallbackInterface.php
Normal file
30
console/skel/symfony/cache-contracts/CallbackInterface.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Contracts\Cache;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
|
||||
/**
|
||||
* Computes and returns the cached value of an item.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface CallbackInterface
|
||||
{
|
||||
/**
|
||||
* @param CacheItemInterface|ItemInterface $item The item to compute the value for
|
||||
* @param bool &$save Should be set to false when the value should not be saved in the pool
|
||||
*
|
||||
* @return mixed The computed value for the passed item
|
||||
*/
|
||||
public function __invoke(CacheItemInterface $item, bool &$save);
|
||||
}
|
65
console/skel/symfony/cache-contracts/ItemInterface.php
Normal file
65
console/skel/symfony/cache-contracts/ItemInterface.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Contracts\Cache;
|
||||
|
||||
use Psr\Cache\CacheException;
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Augments PSR-6's CacheItemInterface with support for tags and metadata.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface ItemInterface extends CacheItemInterface
|
||||
{
|
||||
/**
|
||||
* References the Unix timestamp stating when the item will expire.
|
||||
*/
|
||||
const METADATA_EXPIRY = 'expiry';
|
||||
|
||||
/**
|
||||
* References the time the item took to be created, in milliseconds.
|
||||
*/
|
||||
const METADATA_CTIME = 'ctime';
|
||||
|
||||
/**
|
||||
* References the list of tags that were assigned to the item, as string[].
|
||||
*/
|
||||
const METADATA_TAGS = 'tags';
|
||||
|
||||
/**
|
||||
* Reserved characters that cannot be used in a key or tag.
|
||||
*/
|
||||
const RESERVED_CHARACTERS = '{}()/\@:';
|
||||
|
||||
/**
|
||||
* Adds a tag to a cache item.
|
||||
*
|
||||
* Tags are strings that follow the same validation rules as keys.
|
||||
*
|
||||
* @param string|string[] $tags A tag or array of tags
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException When $tag is not valid
|
||||
* @throws CacheException When the item comes from a pool that is not tag-aware
|
||||
*/
|
||||
public function tag($tags): self;
|
||||
|
||||
/**
|
||||
* Returns a list of metadata info that were saved alongside with the cached value.
|
||||
*
|
||||
* See ItemInterface::METADATA_* consts for keys potentially found in the returned array.
|
||||
*/
|
||||
public function getMetadata(): array;
|
||||
}
|
19
console/skel/symfony/cache-contracts/LICENSE
Normal file
19
console/skel/symfony/cache-contracts/LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2018-2019 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
9
console/skel/symfony/cache-contracts/README.md
Normal file
9
console/skel/symfony/cache-contracts/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
Symfony Cache Contracts
|
||||
=======================
|
||||
|
||||
A set of abstractions extracted out of the Symfony components.
|
||||
|
||||
Can be used to build on semantics that the Symfony components proved useful - and
|
||||
that already have battle tested implementations.
|
||||
|
||||
See https://github.com/symfony/contracts/blob/master/README.md for more information.
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Contracts\Cache;
|
||||
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Allows invalidating cached items using tags.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface TagAwareCacheInterface extends CacheInterface
|
||||
{
|
||||
/**
|
||||
* Invalidates cached items using tags.
|
||||
*
|
||||
* When implemented on a PSR-6 pool, invalidation should not apply
|
||||
* to deferred items. Instead, they should be committed as usual.
|
||||
* This allows replacing old tagged values by new ones without
|
||||
* race conditions.
|
||||
*
|
||||
* @param string[] $tags An array of tags to invalidate
|
||||
*
|
||||
* @return bool True on success
|
||||
*
|
||||
* @throws InvalidArgumentException When $tags is not valid
|
||||
*/
|
||||
public function invalidateTags(array $tags);
|
||||
}
|
34
console/skel/symfony/cache-contracts/composer.json
Normal file
34
console/skel/symfony/cache-contracts/composer.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "symfony/cache-contracts",
|
||||
"type": "library",
|
||||
"description": "Generic abstractions related to caching",
|
||||
"keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.2.5",
|
||||
"psr/cache": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/cache-implementation": ""
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Contracts\\Cache\\": "" }
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
3
console/skel/symfony/cache/.gitattributes
vendored
Normal file
3
console/skel/symfony/cache/.gitattributes
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/Tests export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/.gitignore export-ignore
|
203
console/skel/symfony/cache/Adapter/AbstractAdapter.php
vendored
Normal file
203
console/skel/symfony/cache/Adapter/AbstractAdapter.php
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
|
||||
use Symfony\Component\Cache\Traits\ContractsTrait;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected const NS_SEPARATOR = ':';
|
||||
|
||||
use AbstractAdapterTrait;
|
||||
use ContractsTrait;
|
||||
|
||||
private static $apcuSupported;
|
||||
private static $phpFilesSupported;
|
||||
|
||||
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR;
|
||||
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
|
||||
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace));
|
||||
}
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) use ($defaultLifetime) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
$item->value = $v = $value;
|
||||
$item->isHit = $isHit;
|
||||
$item->defaultLifetime = $defaultLifetime;
|
||||
// Detect wrapped values that encode for their expiry and creation duration
|
||||
// For compactness, these values are packed in the key of an array using
|
||||
// magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
|
||||
if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = key($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
|
||||
$item->value = $v[$k];
|
||||
$v = unpack('Ve/Nc', substr($k, 1, -1));
|
||||
$item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
|
||||
$item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
|
||||
}
|
||||
|
||||
return $item;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$getId = \Closure::fromCallable([$this, 'getId']);
|
||||
$this->mergeByLifetime = \Closure::bind(
|
||||
static function ($deferred, $namespace, &$expiredIds) use ($getId) {
|
||||
$byLifetime = [];
|
||||
$now = microtime(true);
|
||||
$expiredIds = [];
|
||||
|
||||
foreach ($deferred as $key => $item) {
|
||||
$key = (string) $key;
|
||||
if (null === $item->expiry) {
|
||||
$ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;
|
||||
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
|
||||
$expiredIds[] = $getId($key);
|
||||
continue;
|
||||
}
|
||||
if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) {
|
||||
unset($metadata[CacheItem::METADATA_TAGS]);
|
||||
}
|
||||
// For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
|
||||
$byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item->value] : $item->value;
|
||||
}
|
||||
|
||||
return $byLifetime;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best possible adapter that your runtime supports.
|
||||
*
|
||||
* Using ApcuAdapter makes system caches compatible with read-only filesystems.
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param int $defaultLifetime
|
||||
* @param string $version
|
||||
* @param string $directory
|
||||
*
|
||||
* @return AdapterInterface
|
||||
*/
|
||||
public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
|
||||
{
|
||||
$opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true);
|
||||
if (null !== $logger) {
|
||||
$opcache->setLogger($logger);
|
||||
}
|
||||
|
||||
if (!self::$apcuSupported = self::$apcuSupported ?? ApcuAdapter::isSupported()) {
|
||||
return $opcache;
|
||||
}
|
||||
|
||||
$apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version);
|
||||
if ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN)) {
|
||||
$apcu->setLogger(new NullLogger());
|
||||
} elseif (null !== $logger) {
|
||||
$apcu->setLogger($logger);
|
||||
}
|
||||
|
||||
return new ChainAdapter([$apcu, $opcache]);
|
||||
}
|
||||
|
||||
public static function createConnection($dsn, array $options = [])
|
||||
{
|
||||
if (!\is_string($dsn)) {
|
||||
throw new InvalidArgumentException(sprintf('The %s() method expect argument #1 to be string, %s given.', __METHOD__, \gettype($dsn)));
|
||||
}
|
||||
if (0 === strpos($dsn, 'redis:') || 0 === strpos($dsn, 'rediss:')) {
|
||||
return RedisAdapter::createConnection($dsn, $options);
|
||||
}
|
||||
if (0 === strpos($dsn, 'memcached:')) {
|
||||
return MemcachedAdapter::createConnection($dsn, $options);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Unsupported DSN: %s.', $dsn));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$ok = true;
|
||||
$byLifetime = $this->mergeByLifetime;
|
||||
$byLifetime = $byLifetime($this->deferred, $this->namespace, $expiredIds);
|
||||
$retry = $this->deferred = [];
|
||||
|
||||
if ($expiredIds) {
|
||||
$this->doDelete($expiredIds);
|
||||
}
|
||||
foreach ($byLifetime as $lifetime => $values) {
|
||||
try {
|
||||
$e = $this->doSave($values, $lifetime);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
if (true === $e || [] === $e) {
|
||||
continue;
|
||||
}
|
||||
if (\is_array($e) || 1 === \count($values)) {
|
||||
foreach (\is_array($e) ? $e : array_keys($values) as $id) {
|
||||
$ok = false;
|
||||
$v = $values[$id];
|
||||
$type = \is_object($v) ? \get_class($v) : \gettype($v);
|
||||
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
|
||||
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $id => $v) {
|
||||
$retry[$lifetime][] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When bulk-save failed, retry each item individually
|
||||
foreach ($retry as $lifetime => $ids) {
|
||||
foreach ($ids as $id) {
|
||||
try {
|
||||
$v = $byLifetime[$lifetime][$id];
|
||||
$e = $this->doSave([$id => $v], $lifetime);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
if (true === $e || [] === $e) {
|
||||
continue;
|
||||
}
|
||||
$ok = false;
|
||||
$type = \is_object($v) ? \get_class($v) : \gettype($v);
|
||||
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
|
||||
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
|
||||
}
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
}
|
323
console/skel/symfony/cache/Adapter/AbstractTagAwareAdapter.php
vendored
Normal file
323
console/skel/symfony/cache/Adapter/AbstractTagAwareAdapter.php
vendored
Normal file
|
@ -0,0 +1,323 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
|
||||
use Symfony\Component\Cache\Traits\ContractsTrait;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
|
||||
/**
|
||||
* Abstract for native TagAware adapters.
|
||||
*
|
||||
* To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids
|
||||
* to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate().
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author André Rømcke <andre.romcke+symfony@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface
|
||||
{
|
||||
use AbstractAdapterTrait;
|
||||
use ContractsTrait;
|
||||
|
||||
private const TAGS_PREFIX = "\0tags\0";
|
||||
|
||||
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
|
||||
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
|
||||
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace));
|
||||
}
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) use ($defaultLifetime) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
$item->defaultLifetime = $defaultLifetime;
|
||||
$item->isTaggable = true;
|
||||
// If structure does not match what we expect return item as is (no value and not a hit)
|
||||
if (!\is_array($value) || !\array_key_exists('value', $value)) {
|
||||
return $item;
|
||||
}
|
||||
$item->isHit = $isHit;
|
||||
// Extract value, tags and meta data from the cache value
|
||||
$item->value = $value['value'];
|
||||
$item->metadata[CacheItem::METADATA_TAGS] = $value['tags'] ?? [];
|
||||
if (isset($value['meta'])) {
|
||||
// For compactness these values are packed, & expiry is offset to reduce size
|
||||
$v = unpack('Ve/Nc', $value['meta']);
|
||||
$item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
|
||||
$item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
|
||||
}
|
||||
|
||||
return $item;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$getId = \Closure::fromCallable([$this, 'getId']);
|
||||
$tagPrefix = self::TAGS_PREFIX;
|
||||
$this->mergeByLifetime = \Closure::bind(
|
||||
static function ($deferred, &$expiredIds) use ($getId, $tagPrefix) {
|
||||
$byLifetime = [];
|
||||
$now = microtime(true);
|
||||
$expiredIds = [];
|
||||
|
||||
foreach ($deferred as $key => $item) {
|
||||
$key = (string) $key;
|
||||
if (null === $item->expiry) {
|
||||
$ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;
|
||||
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
|
||||
$expiredIds[] = $getId($key);
|
||||
continue;
|
||||
}
|
||||
// Store Value and Tags on the cache value
|
||||
if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) {
|
||||
$value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]];
|
||||
unset($metadata[CacheItem::METADATA_TAGS]);
|
||||
} else {
|
||||
$value = ['value' => $item->value, 'tags' => []];
|
||||
}
|
||||
|
||||
if ($metadata) {
|
||||
// For compactness, expiry and creation duration are packed, using magic numbers as separators
|
||||
$value['meta'] = pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME]);
|
||||
}
|
||||
|
||||
// Extract tag changes, these should be removed from values in doSave()
|
||||
$value['tag-operations'] = ['add' => [], 'remove' => []];
|
||||
$oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? [];
|
||||
foreach (array_diff($value['tags'], $oldTags) as $addedTag) {
|
||||
$value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag);
|
||||
}
|
||||
foreach (array_diff($oldTags, $value['tags']) as $removedTag) {
|
||||
$value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag);
|
||||
}
|
||||
|
||||
$byLifetime[$ttl][$getId($key)] = $value;
|
||||
}
|
||||
|
||||
return $byLifetime;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists several cache items immediately.
|
||||
*
|
||||
* @param array $values The values to cache, indexed by their cache identifier
|
||||
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
|
||||
* @param array[] $addTagData Hash where key is tag id, and array value is list of cache id's to add to tag
|
||||
* @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag
|
||||
*
|
||||
* @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not
|
||||
*/
|
||||
abstract protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array;
|
||||
|
||||
/**
|
||||
* Removes multiple items from the pool and their corresponding tags.
|
||||
*
|
||||
* @param array $ids An array of identifiers that should be removed from the pool
|
||||
*
|
||||
* @return bool True if the items were successfully removed, false otherwise
|
||||
*/
|
||||
abstract protected function doDelete(array $ids);
|
||||
|
||||
/**
|
||||
* Removes relations between tags and deleted items.
|
||||
*
|
||||
* @param array $tagData Array of tag => key identifiers that should be removed from the pool
|
||||
*/
|
||||
abstract protected function doDeleteTagRelations(array $tagData): bool;
|
||||
|
||||
/**
|
||||
* Invalidates cached items using tags.
|
||||
*
|
||||
* @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
abstract protected function doInvalidate(array $tagIds): bool;
|
||||
|
||||
/**
|
||||
* Delete items and yields the tags they were bound to.
|
||||
*/
|
||||
protected function doDeleteYieldTags(array $ids): iterable
|
||||
{
|
||||
foreach ($this->doFetch($ids) as $id => $value) {
|
||||
yield $id => \is_array($value) && \is_array($value['tags'] ?? null) ? $value['tags'] : [];
|
||||
}
|
||||
|
||||
$this->doDelete($ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit(): bool
|
||||
{
|
||||
$ok = true;
|
||||
$byLifetime = $this->mergeByLifetime;
|
||||
$byLifetime = $byLifetime($this->deferred, $expiredIds);
|
||||
$retry = $this->deferred = [];
|
||||
|
||||
if ($expiredIds) {
|
||||
// Tags are not cleaned up in this case, however that is done on invalidateTags().
|
||||
$this->doDelete($expiredIds);
|
||||
}
|
||||
foreach ($byLifetime as $lifetime => $values) {
|
||||
try {
|
||||
$values = $this->extractTagData($values, $addTagData, $removeTagData);
|
||||
$e = $this->doSave($values, $lifetime, $addTagData, $removeTagData);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
if (true === $e || [] === $e) {
|
||||
continue;
|
||||
}
|
||||
if (\is_array($e) || 1 === \count($values)) {
|
||||
foreach (\is_array($e) ? $e : array_keys($values) as $id) {
|
||||
$ok = false;
|
||||
$v = $values[$id];
|
||||
$type = \is_object($v) ? \get_class($v) : \gettype($v);
|
||||
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
|
||||
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $id => $v) {
|
||||
$retry[$lifetime][] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When bulk-save failed, retry each item individually
|
||||
foreach ($retry as $lifetime => $ids) {
|
||||
foreach ($ids as $id) {
|
||||
try {
|
||||
$v = $byLifetime[$lifetime][$id];
|
||||
$values = $this->extractTagData([$id => $v], $addTagData, $removeTagData);
|
||||
$e = $this->doSave($values, $lifetime, $addTagData, $removeTagData);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
if (true === $e || [] === $e) {
|
||||
continue;
|
||||
}
|
||||
$ok = false;
|
||||
$type = \is_object($v) ? \get_class($v) : \gettype($v);
|
||||
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
|
||||
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
|
||||
}
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItems(array $keys): bool
|
||||
{
|
||||
if (!$keys) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ok = true;
|
||||
$ids = [];
|
||||
$tagData = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$ids[$key] = $this->getId($key);
|
||||
unset($this->deferred[$key]);
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($this->doDeleteYieldTags(array_values($ids)) as $id => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
$tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
try {
|
||||
if ((!$tagData || $this->doDeleteTagRelations($tagData)) && $ok) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
// When bulk-delete failed, retry each item individually
|
||||
foreach ($ids as $key => $id) {
|
||||
try {
|
||||
$e = null;
|
||||
if ($this->doDelete([$id])) {
|
||||
continue;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
$message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
|
||||
CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invalidateTags(array $tags)
|
||||
{
|
||||
if (empty($tags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tagIds = [];
|
||||
foreach (array_unique($tags) as $tag) {
|
||||
$tagIds[] = $this->getId(self::TAGS_PREFIX.$tag);
|
||||
}
|
||||
|
||||
if ($this->doInvalidate($tagIds)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts tags operation data from $values set in mergeByLifetime, and returns values without it.
|
||||
*/
|
||||
private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array
|
||||
{
|
||||
$addTagData = $removeTagData = [];
|
||||
foreach ($values as $id => $value) {
|
||||
foreach ($value['tag-operations']['add'] as $tag => $tagId) {
|
||||
$addTagData[$tagId][] = $id;
|
||||
}
|
||||
|
||||
foreach ($value['tag-operations']['remove'] as $tag => $tagId) {
|
||||
$removeTagData[$tagId][] = $id;
|
||||
}
|
||||
|
||||
unset($values[$id]['tag-operations']);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
46
console/skel/symfony/cache/Adapter/AdapterInterface.php
vendored
Normal file
46
console/skel/symfony/cache/Adapter/AdapterInterface.php
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
|
||||
/**
|
||||
* Interface for adapters managing instances of Symfony's CacheItem.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
interface AdapterInterface extends CacheItemPoolInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return CacheItem
|
||||
*/
|
||||
public function getItem($key);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return \Traversable|CacheItem[]
|
||||
*/
|
||||
public function getItems(array $keys = []);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(/*string $prefix = ''*/);
|
||||
}
|
27
console/skel/symfony/cache/Adapter/ApcuAdapter.php
vendored
Normal file
27
console/skel/symfony/cache/Adapter/ApcuAdapter.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\Traits\ApcuTrait;
|
||||
|
||||
class ApcuAdapter extends AbstractAdapter
|
||||
{
|
||||
use ApcuTrait;
|
||||
|
||||
/**
|
||||
* @throws CacheException if APCu is not enabled
|
||||
*/
|
||||
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
|
||||
{
|
||||
$this->init($namespace, $defaultLifetime, $version);
|
||||
}
|
||||
}
|
171
console/skel/symfony/cache/Adapter/ArrayAdapter.php
vendored
Normal file
171
console/skel/symfony/cache/Adapter/ArrayAdapter.php
vendored
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\ArrayTrait;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
|
||||
{
|
||||
use ArrayTrait;
|
||||
|
||||
private $createCacheItem;
|
||||
|
||||
/**
|
||||
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
|
||||
*/
|
||||
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
|
||||
{
|
||||
$this->storeSerialized = $storeSerialized;
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) use ($defaultLifetime) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
$item->value = $value;
|
||||
$item->isHit = $isHit;
|
||||
$item->defaultLifetime = $defaultLifetime;
|
||||
|
||||
return $item;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
|
||||
{
|
||||
$item = $this->getItem($key);
|
||||
$metadata = $item->getMetadata();
|
||||
|
||||
// ArrayAdapter works in memory, we don't care about stampede protection
|
||||
if (INF === $beta || !$item->isHit()) {
|
||||
$save = true;
|
||||
$this->save($item->set($callback($item, $save)));
|
||||
}
|
||||
|
||||
return $item->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
if (!$isHit = $this->hasItem($key)) {
|
||||
$this->values[$key] = $value = null;
|
||||
} else {
|
||||
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
|
||||
}
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
return $f($key, $value, $isHit);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (!\is_string($key) || !isset($this->expiries[$key])) {
|
||||
CacheItem::validateKey($key);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->generateItems($keys, microtime(true), $this->createCacheItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$this->deleteItem($key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
if (!$item instanceof CacheItem) {
|
||||
return false;
|
||||
}
|
||||
$item = (array) $item;
|
||||
$key = $item["\0*\0key"];
|
||||
$value = $item["\0*\0value"];
|
||||
$expiry = $item["\0*\0expiry"];
|
||||
|
||||
if (null !== $expiry && $expiry <= microtime(true)) {
|
||||
$this->deleteItem($key);
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
|
||||
return false;
|
||||
}
|
||||
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
|
||||
$expiry = microtime(true) + $item["\0*\0defaultLifetime"];
|
||||
}
|
||||
|
||||
$this->values[$key] = $value;
|
||||
$this->expiries[$key] = null !== $expiry ? $expiry : PHP_INT_MAX;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
return $this->save($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(string $key): bool
|
||||
{
|
||||
return $this->deleteItem($key);
|
||||
}
|
||||
}
|
332
console/skel/symfony/cache/Adapter/ChainAdapter.php
vendored
Normal file
332
console/skel/symfony/cache/Adapter/ChainAdapter.php
vendored
Normal file
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\ContractsTrait;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* Chains several adapters together.
|
||||
*
|
||||
* Cached items are fetched from the first adapter having them in its data store.
|
||||
* They are saved and deleted in all adapters at once.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
use ContractsTrait;
|
||||
|
||||
private $adapters = [];
|
||||
private $adapterCount;
|
||||
private $syncItem;
|
||||
|
||||
/**
|
||||
* @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
|
||||
* @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones
|
||||
*/
|
||||
public function __construct(array $adapters, int $defaultLifetime = 0)
|
||||
{
|
||||
if (!$adapters) {
|
||||
throw new InvalidArgumentException('At least one adapter must be specified.');
|
||||
}
|
||||
|
||||
foreach ($adapters as $adapter) {
|
||||
if (!$adapter instanceof CacheItemPoolInterface) {
|
||||
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class));
|
||||
}
|
||||
|
||||
if ($adapter instanceof AdapterInterface) {
|
||||
$this->adapters[] = $adapter;
|
||||
} else {
|
||||
$this->adapters[] = new ProxyAdapter($adapter);
|
||||
}
|
||||
}
|
||||
$this->adapterCount = \count($this->adapters);
|
||||
|
||||
$this->syncItem = \Closure::bind(
|
||||
static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifetime) {
|
||||
$sourceItem->isTaggable = false;
|
||||
$sourceMetadata = $sourceMetadata ?? $sourceItem->metadata;
|
||||
unset($sourceMetadata[CacheItem::METADATA_TAGS]);
|
||||
|
||||
$item->value = $sourceItem->value;
|
||||
$item->expiry = $sourceMetadata[CacheItem::METADATA_EXPIRY] ?? $sourceItem->expiry;
|
||||
$item->isHit = $sourceItem->isHit;
|
||||
$item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata;
|
||||
|
||||
if (0 < $sourceItem->defaultLifetime && $sourceItem->defaultLifetime < $defaultLifetime) {
|
||||
$defaultLifetime = $sourceItem->defaultLifetime;
|
||||
}
|
||||
if (0 < $defaultLifetime && ($item->defaultLifetime <= 0 || $defaultLifetime < $item->defaultLifetime)) {
|
||||
$item->defaultLifetime = $defaultLifetime;
|
||||
}
|
||||
|
||||
return $item;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
|
||||
{
|
||||
$lastItem = null;
|
||||
$i = 0;
|
||||
$wrap = function (CacheItem $item = null) use ($key, $callback, $beta, &$wrap, &$i, &$lastItem, &$metadata) {
|
||||
$adapter = $this->adapters[$i];
|
||||
if (isset($this->adapters[++$i])) {
|
||||
$callback = $wrap;
|
||||
$beta = INF === $beta ? INF : 0;
|
||||
}
|
||||
if ($adapter instanceof CacheInterface) {
|
||||
$value = $adapter->get($key, $callback, $beta, $metadata);
|
||||
} else {
|
||||
$value = $this->doGet($adapter, $key, $callback, $beta, $metadata);
|
||||
}
|
||||
if (null !== $item) {
|
||||
($this->syncItem)($lastItem = $lastItem ?? $item, $item, $metadata);
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
|
||||
return $wrap();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$syncItem = $this->syncItem;
|
||||
$misses = [];
|
||||
|
||||
foreach ($this->adapters as $i => $adapter) {
|
||||
$item = $adapter->getItem($key);
|
||||
|
||||
if ($item->isHit()) {
|
||||
while (0 <= --$i) {
|
||||
$this->adapters[$i]->save($syncItem($item, $misses[$i]));
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
$misses[$i] = $item;
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
return $this->generateItems($this->adapters[0]->getItems($keys), 0);
|
||||
}
|
||||
|
||||
private function generateItems(iterable $items, int $adapterIndex)
|
||||
{
|
||||
$missing = [];
|
||||
$misses = [];
|
||||
$nextAdapterIndex = $adapterIndex + 1;
|
||||
$nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null;
|
||||
|
||||
foreach ($items as $k => $item) {
|
||||
if (!$nextAdapter || $item->isHit()) {
|
||||
yield $k => $item;
|
||||
} else {
|
||||
$missing[] = $k;
|
||||
$misses[$k] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
if ($missing) {
|
||||
$syncItem = $this->syncItem;
|
||||
$adapter = $this->adapters[$adapterIndex];
|
||||
$items = $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex);
|
||||
|
||||
foreach ($items as $k => $item) {
|
||||
if ($item->isHit()) {
|
||||
$adapter->save($syncItem($item, $misses[$k]));
|
||||
}
|
||||
|
||||
yield $k => $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
foreach ($this->adapters as $adapter) {
|
||||
if ($adapter->hasItem($key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(/*string $prefix = ''*/)
|
||||
{
|
||||
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||
$cleared = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
while ($i--) {
|
||||
if ($this->adapters[$i] instanceof AdapterInterface) {
|
||||
$cleared = $this->adapters[$i]->clear($prefix) && $cleared;
|
||||
} else {
|
||||
$cleared = $this->adapters[$i]->clear() && $cleared;
|
||||
}
|
||||
}
|
||||
|
||||
return $cleared;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
$deleted = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
while ($i--) {
|
||||
$deleted = $this->adapters[$i]->deleteItem($key) && $deleted;
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
$deleted = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
while ($i--) {
|
||||
$deleted = $this->adapters[$i]->deleteItems($keys) && $deleted;
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
$saved = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
while ($i--) {
|
||||
$saved = $this->adapters[$i]->save($item) && $saved;
|
||||
}
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
$saved = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
while ($i--) {
|
||||
$saved = $this->adapters[$i]->saveDeferred($item) && $saved;
|
||||
}
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$committed = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
while ($i--) {
|
||||
$committed = $this->adapters[$i]->commit() && $committed;
|
||||
}
|
||||
|
||||
return $committed;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prune()
|
||||
{
|
||||
$pruned = true;
|
||||
|
||||
foreach ($this->adapters as $adapter) {
|
||||
if ($adapter instanceof PruneableInterface) {
|
||||
$pruned = $adapter->prune() && $pruned;
|
||||
}
|
||||
}
|
||||
|
||||
return $pruned;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
foreach ($this->adapters as $adapter) {
|
||||
if ($adapter instanceof ResetInterface) {
|
||||
$adapter->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
console/skel/symfony/cache/Adapter/DoctrineAdapter.php
vendored
Normal file
27
console/skel/symfony/cache/Adapter/DoctrineAdapter.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Doctrine\Common\Cache\CacheProvider;
|
||||
use Symfony\Component\Cache\Traits\DoctrineTrait;
|
||||
|
||||
class DoctrineAdapter extends AbstractAdapter
|
||||
{
|
||||
use DoctrineTrait;
|
||||
|
||||
public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
parent::__construct('', $defaultLifetime);
|
||||
$this->provider = $provider;
|
||||
$provider->setNamespace($namespace);
|
||||
}
|
||||
}
|
29
console/skel/symfony/cache/Adapter/FilesystemAdapter.php
vendored
Normal file
29
console/skel/symfony/cache/Adapter/FilesystemAdapter.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
|
||||
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\Traits\FilesystemTrait;
|
||||
|
||||
class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
|
||||
{
|
||||
use FilesystemTrait;
|
||||
|
||||
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
|
||||
{
|
||||
$this->marshaller = $marshaller ?? new DefaultMarshaller();
|
||||
parent::__construct('', $defaultLifetime);
|
||||
$this->init($namespace, $directory);
|
||||
}
|
||||
}
|
239
console/skel/symfony/cache/Adapter/FilesystemTagAwareAdapter.php
vendored
Normal file
239
console/skel/symfony/cache/Adapter/FilesystemTagAwareAdapter.php
vendored
Normal file
|
@ -0,0 +1,239 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||
use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\Traits\FilesystemTrait;
|
||||
|
||||
/**
|
||||
* Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author André Rømcke <andre.romcke+symfony@gmail.com>
|
||||
*/
|
||||
class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface
|
||||
{
|
||||
use FilesystemTrait {
|
||||
doClear as private doClearCache;
|
||||
doSave as private doSaveCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Folder used for tag symlinks.
|
||||
*/
|
||||
private const TAG_FOLDER = 'tags';
|
||||
|
||||
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
|
||||
{
|
||||
$this->marshaller = new TagAwareMarshaller($marshaller);
|
||||
parent::__construct('', $defaultLifetime);
|
||||
$this->init($namespace, $directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doClear($namespace)
|
||||
{
|
||||
$ok = $this->doClearCache($namespace);
|
||||
|
||||
if ('' !== $namespace) {
|
||||
return $ok;
|
||||
}
|
||||
|
||||
set_error_handler(static function () {});
|
||||
$chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
|
||||
try {
|
||||
foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) {
|
||||
if (rename($dir, $renamed = substr_replace($dir, bin2hex(random_bytes(4)), -8))) {
|
||||
$dir = $renamed.\DIRECTORY_SEPARATOR;
|
||||
} else {
|
||||
$dir .= \DIRECTORY_SEPARATOR;
|
||||
$renamed = null;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 38; ++$i) {
|
||||
if (!file_exists($dir.$chars[$i])) {
|
||||
continue;
|
||||
}
|
||||
for ($j = 0; $j < 38; ++$j) {
|
||||
if (!file_exists($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) {
|
||||
continue;
|
||||
}
|
||||
foreach (scandir($d, SCANDIR_SORT_NONE) ?: [] as $link) {
|
||||
if ('.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.\DIRECTORY_SEPARATOR.$link))) {
|
||||
unlink($d.\DIRECTORY_SEPARATOR.$link);
|
||||
}
|
||||
}
|
||||
null === $renamed ?: rmdir($d);
|
||||
}
|
||||
null === $renamed ?: rmdir($dir.$chars[$i]);
|
||||
}
|
||||
null === $renamed ?: rmdir($renamed);
|
||||
}
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array
|
||||
{
|
||||
$failed = $this->doSaveCache($values, $lifetime);
|
||||
|
||||
// Add Tags as symlinks
|
||||
foreach ($addTagData as $tagId => $ids) {
|
||||
$tagFolder = $this->getTagFolder($tagId);
|
||||
foreach ($ids as $id) {
|
||||
if ($failed && \in_array($id, $failed, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = $this->getFile($id);
|
||||
|
||||
if (!@symlink($file, $this->getFile($id, true, $tagFolder))) {
|
||||
@unlink($file);
|
||||
$failed[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unlink removed Tags
|
||||
foreach ($removeTagData as $tagId => $ids) {
|
||||
$tagFolder = $this->getTagFolder($tagId);
|
||||
foreach ($ids as $id) {
|
||||
if ($failed && \in_array($id, $failed, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@unlink($this->getFile($id, false, $tagFolder));
|
||||
}
|
||||
}
|
||||
|
||||
return $failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doDeleteYieldTags(array $ids): iterable
|
||||
{
|
||||
foreach ($ids as $id) {
|
||||
$file = $this->getFile($id);
|
||||
if (!file_exists($file) || !$h = @fopen($file, 'rb')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((\PHP_VERSION_ID >= 70300 || '\\' !== \DIRECTORY_SEPARATOR) && !@unlink($file)) {
|
||||
fclose($h);
|
||||
continue;
|
||||
}
|
||||
|
||||
$meta = explode("\n", fread($h, 4096), 3)[2] ?? '';
|
||||
|
||||
// detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
|
||||
if (13 < \strlen($meta) && "\x9D" === $meta[0] && "\0" === $meta[5] && "\x5F" === $meta[9]) {
|
||||
$meta[9] = "\0";
|
||||
$tagLen = unpack('Nlen', $meta, 9)['len'];
|
||||
$meta = substr($meta, 13, $tagLen);
|
||||
|
||||
if (0 < $tagLen -= \strlen($meta)) {
|
||||
$meta .= fread($h, $tagLen);
|
||||
}
|
||||
|
||||
try {
|
||||
yield $id => '' === $meta ? [] : $this->marshaller->unmarshall($meta);
|
||||
} catch (\Exception $e) {
|
||||
yield $id => [];
|
||||
}
|
||||
}
|
||||
|
||||
fclose($h);
|
||||
|
||||
if (\PHP_VERSION_ID < 70300 && '\\' === \DIRECTORY_SEPARATOR) {
|
||||
@unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doDeleteTagRelations(array $tagData): bool
|
||||
{
|
||||
foreach ($tagData as $tagId => $idList) {
|
||||
$tagFolder = $this->getTagFolder($tagId);
|
||||
foreach ($idList as $id) {
|
||||
@unlink($this->getFile($id, false, $tagFolder));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doInvalidate(array $tagIds): bool
|
||||
{
|
||||
foreach ($tagIds as $tagId) {
|
||||
if (!file_exists($tagFolder = $this->getTagFolder($tagId))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
set_error_handler(static function () {});
|
||||
|
||||
try {
|
||||
if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -9))) {
|
||||
$tagFolder = $renamed.\DIRECTORY_SEPARATOR;
|
||||
} else {
|
||||
$renamed = null;
|
||||
}
|
||||
|
||||
foreach ($this->scanHashDir($tagFolder) as $itemLink) {
|
||||
unlink(realpath($itemLink) ?: $itemLink);
|
||||
unlink($itemLink);
|
||||
}
|
||||
|
||||
if (null === $renamed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
|
||||
for ($i = 0; $i < 38; ++$i) {
|
||||
for ($j = 0; $j < 38; ++$j) {
|
||||
rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]);
|
||||
}
|
||||
rmdir($tagFolder.$chars[$i]);
|
||||
}
|
||||
rmdir($renamed);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getTagFolder(string $tagId): string
|
||||
{
|
||||
return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
37
console/skel/symfony/cache/Adapter/MemcachedAdapter.php
vendored
Normal file
37
console/skel/symfony/cache/Adapter/MemcachedAdapter.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||
use Symfony\Component\Cache\Traits\MemcachedTrait;
|
||||
|
||||
class MemcachedAdapter extends AbstractAdapter
|
||||
{
|
||||
use MemcachedTrait;
|
||||
|
||||
protected $maxIdLength = 250;
|
||||
|
||||
/**
|
||||
* Using a MemcachedAdapter with a TagAwareAdapter for storing tags is discouraged.
|
||||
* Using a RedisAdapter is recommended instead. If you cannot do otherwise, be aware that:
|
||||
* - the Memcached::OPT_BINARY_PROTOCOL must be enabled
|
||||
* (that's the default when using MemcachedAdapter::createConnection());
|
||||
* - tags eviction by Memcached's LRU algorithm will break by-tags invalidation;
|
||||
* your Memcached memory should be large enough to never trigger LRU.
|
||||
*
|
||||
* Using a MemcachedAdapter as a pure items store is fine.
|
||||
*/
|
||||
public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
|
||||
{
|
||||
$this->init($client, $namespace, $defaultLifetime, $marshaller);
|
||||
}
|
||||
}
|
156
console/skel/symfony/cache/Adapter/NullAdapter.php
vendored
Normal file
156
console/skel/symfony/cache/Adapter/NullAdapter.php
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
/**
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class NullAdapter implements AdapterInterface, CacheInterface
|
||||
{
|
||||
private $createCacheItem;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
function ($key) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
$item->isHit = false;
|
||||
|
||||
return $item;
|
||||
},
|
||||
$this,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
|
||||
{
|
||||
$save = true;
|
||||
|
||||
return $callback(($this->createCacheItem)($key), $save);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
return $f($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
return $this->generateItems($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(/*string $prefix = ''*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(string $key): bool
|
||||
{
|
||||
return $this->deleteItem($key);
|
||||
}
|
||||
|
||||
private function generateItems(array $keys)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
foreach ($keys as $key) {
|
||||
yield $key => $f($key);
|
||||
}
|
||||
}
|
||||
}
|
54
console/skel/symfony/cache/Adapter/PdoAdapter.php
vendored
Normal file
54
console/skel/symfony/cache/Adapter/PdoAdapter.php
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\Traits\PdoTrait;
|
||||
|
||||
class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
{
|
||||
use PdoTrait;
|
||||
|
||||
protected $maxIdLength = 255;
|
||||
|
||||
/**
|
||||
* You can either pass an existing database connection as PDO instance or
|
||||
* a Doctrine DBAL Connection or a DSN string that will be used to
|
||||
* lazy-connect to the database when the cache is actually used.
|
||||
*
|
||||
* When a Doctrine DBAL Connection is passed, the cache table is created
|
||||
* automatically when possible. Otherwise, use the createTable() method.
|
||||
*
|
||||
* List of available options:
|
||||
* * db_table: The name of the table [default: cache_items]
|
||||
* * db_id_col: The column where to store the cache id [default: item_id]
|
||||
* * db_data_col: The column where to store the cache data [default: item_data]
|
||||
* * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]
|
||||
* * db_time_col: The column where to store the timestamp [default: item_time]
|
||||
* * db_username: The username when lazy-connect [default: '']
|
||||
* * db_password: The password when lazy-connect [default: '']
|
||||
* * db_connection_options: An array of driver-specific connection options [default: []]
|
||||
*
|
||||
* @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null
|
||||
*
|
||||
* @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
|
||||
* @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
|
||||
* @throws InvalidArgumentException When namespace contains invalid characters
|
||||
*/
|
||||
public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
|
||||
{
|
||||
$this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller);
|
||||
}
|
||||
}
|
332
console/skel/symfony/cache/Adapter/PhpArrayAdapter.php
vendored
Normal file
332
console/skel/symfony/cache/Adapter/PhpArrayAdapter.php
vendored
Normal file
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\ContractsTrait;
|
||||
use Symfony\Component\Cache\Traits\PhpArrayTrait;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
/**
|
||||
* Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
|
||||
* Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
use PhpArrayTrait;
|
||||
use ContractsTrait;
|
||||
|
||||
private $createCacheItem;
|
||||
|
||||
/**
|
||||
* @param string $file The PHP file were values are cached
|
||||
* @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
|
||||
*/
|
||||
public function __construct(string $file, AdapterInterface $fallbackPool)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->pool = $fallbackPool;
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
static function ($key, $value, $isHit) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
$item->value = $value;
|
||||
$item->isHit = $isHit;
|
||||
|
||||
return $item;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This adapter takes advantage of how PHP stores arrays in its latest versions.
|
||||
*
|
||||
* @param string $file The PHP file were values are cached
|
||||
* @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit
|
||||
*
|
||||
* @return CacheItemPoolInterface
|
||||
*/
|
||||
public static function create($file, CacheItemPoolInterface $fallbackPool)
|
||||
{
|
||||
if (!$fallbackPool instanceof AdapterInterface) {
|
||||
$fallbackPool = new ProxyAdapter($fallbackPool);
|
||||
}
|
||||
|
||||
return new static($file, $fallbackPool);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
|
||||
{
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
if (!isset($this->keys[$key])) {
|
||||
get_from_pool:
|
||||
if ($this->pool instanceof CacheInterface) {
|
||||
return $this->pool->get($key, $callback, $beta, $metadata);
|
||||
}
|
||||
|
||||
return $this->doGet($this->pool, $key, $callback, $beta, $metadata);
|
||||
}
|
||||
$value = $this->values[$this->keys[$key]];
|
||||
|
||||
if ('N;' === $value) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if ($value instanceof \Closure) {
|
||||
return $value();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
unset($this->keys[$key]);
|
||||
goto get_from_pool;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
|
||||
}
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
if (!isset($this->keys[$key])) {
|
||||
return $this->pool->getItem($key);
|
||||
}
|
||||
|
||||
$value = $this->values[$this->keys[$key]];
|
||||
$isHit = true;
|
||||
|
||||
if ('N;' === $value) {
|
||||
$value = null;
|
||||
} elseif ($value instanceof \Closure) {
|
||||
try {
|
||||
$value = $value();
|
||||
} catch (\Throwable $e) {
|
||||
$value = null;
|
||||
$isHit = false;
|
||||
}
|
||||
}
|
||||
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
return $f($key, $value, $isHit);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
|
||||
}
|
||||
}
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->generateItems($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
|
||||
}
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return isset($this->keys[$key]) || $this->pool->hasItem($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
|
||||
}
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return !isset($this->keys[$key]) && $this->pool->deleteItem($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
$deleted = true;
|
||||
$fallbackKeys = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
|
||||
}
|
||||
|
||||
if (isset($this->keys[$key])) {
|
||||
$deleted = false;
|
||||
} else {
|
||||
$fallbackKeys[] = $key;
|
||||
}
|
||||
}
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
if ($fallbackKeys) {
|
||||
$deleted = $this->pool->deleteItems($fallbackKeys) && $deleted;
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return !isset($this->keys[$item->getKey()]) && $this->pool->save($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
return $this->pool->commit();
|
||||
}
|
||||
|
||||
private function generateItems(array $keys): \Generator
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$fallbackKeys = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (isset($this->keys[$key])) {
|
||||
$value = $this->values[$this->keys[$key]];
|
||||
|
||||
if ('N;' === $value) {
|
||||
yield $key => $f($key, null, true);
|
||||
} elseif ($value instanceof \Closure) {
|
||||
try {
|
||||
yield $key => $f($key, $value(), true);
|
||||
} catch (\Throwable $e) {
|
||||
yield $key => $f($key, null, false);
|
||||
}
|
||||
} else {
|
||||
yield $key => $f($key, $value, true);
|
||||
}
|
||||
} else {
|
||||
$fallbackKeys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fallbackKeys) {
|
||||
yield from $this->pool->getItems($fallbackKeys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException When $class is not found and is required
|
||||
*
|
||||
* @internal to be removed in Symfony 5.0
|
||||
*/
|
||||
public static function throwOnRequiredClass($class)
|
||||
{
|
||||
$e = new \ReflectionException("Class $class does not exist");
|
||||
$trace = debug_backtrace();
|
||||
$autoloadFrame = [
|
||||
'function' => 'spl_autoload_call',
|
||||
'args' => [$class],
|
||||
];
|
||||
$i = 1 + array_search($autoloadFrame, $trace, true);
|
||||
|
||||
if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
|
||||
switch ($trace[$i]['function']) {
|
||||
case 'get_class_methods':
|
||||
case 'get_class_vars':
|
||||
case 'get_parent_class':
|
||||
case 'is_a':
|
||||
case 'is_subclass_of':
|
||||
case 'class_exists':
|
||||
case 'class_implements':
|
||||
case 'class_parents':
|
||||
case 'trait_exists':
|
||||
case 'defined':
|
||||
case 'interface_exists':
|
||||
case 'method_exists':
|
||||
case 'property_exists':
|
||||
case 'is_callable':
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
38
console/skel/symfony/cache/Adapter/PhpFilesAdapter.php
vendored
Normal file
38
console/skel/symfony/cache/Adapter/PhpFilesAdapter.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\Exception\CacheException;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\Traits\PhpFilesTrait;
|
||||
|
||||
class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
|
||||
{
|
||||
use PhpFilesTrait;
|
||||
|
||||
/**
|
||||
* @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire.
|
||||
* Doing so is encouraged because it fits perfectly OPcache's memory model.
|
||||
*
|
||||
* @throws CacheException if OPcache is not enabled
|
||||
*/
|
||||
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false)
|
||||
{
|
||||
$this->appendOnly = $appendOnly;
|
||||
self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
|
||||
parent::__construct('', $defaultLifetime);
|
||||
$this->init($namespace, $directory);
|
||||
$this->includeHandler = static function ($type, $msg, $file, $line) {
|
||||
throw new \ErrorException($msg, 0, $type, $file, $line);
|
||||
};
|
||||
}
|
||||
}
|
269
console/skel/symfony/cache/Adapter/ProxyAdapter.php
vendored
Normal file
269
console/skel/symfony/cache/Adapter/ProxyAdapter.php
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\ContractsTrait;
|
||||
use Symfony\Component\Cache\Traits\ProxyTrait;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
use ProxyTrait;
|
||||
use ContractsTrait;
|
||||
|
||||
private $namespace;
|
||||
private $namespaceLen;
|
||||
private $createCacheItem;
|
||||
private $setInnerItem;
|
||||
private $poolHash;
|
||||
|
||||
public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
$this->pool = $pool;
|
||||
$this->poolHash = $poolHash = spl_object_hash($pool);
|
||||
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace);
|
||||
$this->namespaceLen = \strlen($namespace);
|
||||
$this->createCacheItem = \Closure::bind(
|
||||
static function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
|
||||
$item = new CacheItem();
|
||||
$item->key = $key;
|
||||
|
||||
if (null === $innerItem) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
$item->value = $v = $innerItem->get();
|
||||
$item->isHit = $innerItem->isHit();
|
||||
$item->innerItem = $innerItem;
|
||||
$item->defaultLifetime = $defaultLifetime;
|
||||
$item->poolHash = $poolHash;
|
||||
|
||||
// Detect wrapped values that encode for their expiry and creation duration
|
||||
// For compactness, these values are packed in the key of an array using
|
||||
// magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
|
||||
if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = key($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
|
||||
$item->value = $v[$k];
|
||||
$v = unpack('Ve/Nc', substr($k, 1, -1));
|
||||
$item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
|
||||
$item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
|
||||
} elseif ($innerItem instanceof CacheItem) {
|
||||
$item->metadata = $innerItem->metadata;
|
||||
}
|
||||
$innerItem->set(null);
|
||||
|
||||
return $item;
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
$this->setInnerItem = \Closure::bind(
|
||||
/**
|
||||
* @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix
|
||||
*/
|
||||
static function (CacheItemInterface $innerItem, array $item) {
|
||||
// Tags are stored separately, no need to account for them when considering this item's newly set metadata
|
||||
if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) {
|
||||
unset($metadata[CacheItem::METADATA_TAGS]);
|
||||
}
|
||||
if ($metadata) {
|
||||
// For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
|
||||
$item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
|
||||
}
|
||||
$innerItem->set($item["\0*\0value"]);
|
||||
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', $item["\0*\0expiry"])) : null);
|
||||
},
|
||||
null,
|
||||
CacheItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
|
||||
{
|
||||
if (!$this->pool instanceof CacheInterface) {
|
||||
return $this->doGet($this, $key, $callback, $beta, $metadata);
|
||||
}
|
||||
|
||||
return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) {
|
||||
$item = ($this->createCacheItem)($key, $innerItem);
|
||||
$item->set($value = $callback($item, $save));
|
||||
($this->setInnerItem)($innerItem, (array) $item);
|
||||
|
||||
return $value;
|
||||
}, $beta, $metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
$item = $this->pool->getItem($this->getId($key));
|
||||
|
||||
return $f($key, $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
if ($this->namespaceLen) {
|
||||
foreach ($keys as $i => $key) {
|
||||
$keys[$i] = $this->getId($key);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->generateItems($this->pool->getItems($keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
return $this->pool->hasItem($this->getId($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear(/*string $prefix = ''*/)
|
||||
{
|
||||
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||
|
||||
if ($this->pool instanceof AdapterInterface) {
|
||||
return $this->pool->clear($this->namespace.$prefix);
|
||||
}
|
||||
|
||||
return $this->pool->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
return $this->pool->deleteItem($this->getId($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
if ($this->namespaceLen) {
|
||||
foreach ($keys as $i => $key) {
|
||||
$keys[$i] = $this->getId($key);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->pool->deleteItems($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
return $this->doSave($item, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
return $this->doSave($item, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
return $this->pool->commit();
|
||||
}
|
||||
|
||||
private function doSave(CacheItemInterface $item, string $method)
|
||||
{
|
||||
if (!$item instanceof CacheItem) {
|
||||
return false;
|
||||
}
|
||||
$item = (array) $item;
|
||||
if (null === $item["\0*\0expiry"] && 0 < $item["\0*\0defaultLifetime"]) {
|
||||
$item["\0*\0expiry"] = microtime(true) + $item["\0*\0defaultLifetime"];
|
||||
}
|
||||
|
||||
if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) {
|
||||
$innerItem = $item["\0*\0innerItem"];
|
||||
} elseif ($this->pool instanceof AdapterInterface) {
|
||||
// this is an optimization specific for AdapterInterface implementations
|
||||
// so we can save a round-trip to the backend by just creating a new item
|
||||
$f = $this->createCacheItem;
|
||||
$innerItem = $f($this->namespace.$item["\0*\0key"], null);
|
||||
} else {
|
||||
$innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]);
|
||||
}
|
||||
|
||||
($this->setInnerItem)($innerItem, $item);
|
||||
|
||||
return $this->pool->$method($innerItem);
|
||||
}
|
||||
|
||||
private function generateItems(iterable $items)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
foreach ($items as $key => $item) {
|
||||
if ($this->namespaceLen) {
|
||||
$key = substr($key, $this->namespaceLen);
|
||||
}
|
||||
|
||||
yield $key => $f($key, $item);
|
||||
}
|
||||
}
|
||||
|
||||
private function getId($key): string
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
return $this->namespace.$key;
|
||||
}
|
||||
}
|
86
console/skel/symfony/cache/Adapter/Psr16Adapter.php
vendored
Normal file
86
console/skel/symfony/cache/Adapter/Psr16Adapter.php
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\ProxyTrait;
|
||||
|
||||
/**
|
||||
* Turns a PSR-16 cache into a PSR-6 one.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected const NS_SEPARATOR = '_';
|
||||
|
||||
use ProxyTrait;
|
||||
|
||||
private $miss;
|
||||
|
||||
public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0)
|
||||
{
|
||||
parent::__construct($namespace, $defaultLifetime);
|
||||
|
||||
$this->pool = $pool;
|
||||
$this->miss = new \stdClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doFetch(array $ids)
|
||||
{
|
||||
foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
|
||||
if ($this->miss !== $value) {
|
||||
yield $key => $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doHave($id)
|
||||
{
|
||||
return $this->pool->has($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doClear($namespace)
|
||||
{
|
||||
return $this->pool->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doDelete(array $ids)
|
||||
{
|
||||
return $this->pool->deleteMultiple($ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doSave(array $values, $lifetime)
|
||||
{
|
||||
return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
|
||||
}
|
||||
}
|
30
console/skel/symfony/cache/Adapter/RedisAdapter.php
vendored
Normal file
30
console/skel/symfony/cache/Adapter/RedisAdapter.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||
use Symfony\Component\Cache\Traits\RedisTrait;
|
||||
|
||||
class RedisAdapter extends AbstractAdapter
|
||||
{
|
||||
use RedisTrait;
|
||||
|
||||
/**
|
||||
* @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redisClient The redis client
|
||||
* @param string $namespace The default namespace
|
||||
* @param int $defaultLifetime The default lifetime
|
||||
*/
|
||||
public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
|
||||
{
|
||||
$this->init($redisClient, $namespace, $defaultLifetime, $marshaller);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue