I want to create my own restful API using symfony php framework.
of cause, i use
- FOSRestBundle
- FOSUserBundle
- LexikJWTAuthenticationBundle
- JMSSerializerBundle
After the configuration of all bundles my API return empty objects.
[{}{}{}{}{}{}{}]
In my controller i write
class ChantController extends Controller
{
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$chants = $em->getRepository(Chant::class)->findAll();
return new JsonResponse($chants);
}
}
The login api create by LexikJWTAuthenticationBundle work fine, but my own routes don't work.
Here is my configurations files
app/config/config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
- { resource: "#ChantBundle/Resources/config/services.yml" }
- { resource: "#UserBundle/Resources/config/services.yml" }
- { resource: "#AdminBundle/Resources/config/services.yml" }
- { resource: "#JsonApiBundle/Resources/config/services.yml" }
- { resource: "#AjaxApiBundle/Resources/config/services.yml" }
# 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:
locale: fr
jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy
framework:
#esi: ~
translator: { fallbacks: ['%locale%'] }
secret: '%secret%'
router:
resource: '%kernel.project_dir%/app/config/routing.yml'
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
#serializer: { enable_annotations: true }
default_locale: '%locale%'
trusted_hosts: ~
session:
# https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
handler_id: session.handler.native_file
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
fragments: ~
http_method_override: true
assets: ~
php_errors:
log: true
templating:
engines: ['twig']
serializer:
enabled: false
# Twig Configuration
twig:
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
# Doctrine Configuration
doctrine:
dbal:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
charset: UTF8
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: '%kernel.project_dir%/var/data/data.sqlite'
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
#path: '%database_path%'
orm:
auto_generate_proxy_classes: '%kernel.debug%'
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
# Swiftmailer Configuration
swiftmailer:
transport: '%mailer_transport%'
host: '%mailer_host%'
username: '%mailer_user%'
password: '%mailer_password%'
spool: { type: memory }
# FOSUserbundle Configuration
fos_user:
db_driver: orm # Le type de BDD à utiliser, nous utilisons l'ORM Doctrine depuis le début
firewall_name: main # Le nom du firewall derrière lequel on utilisera ces utilisateurs
user_class: Root\ModelsBundle\Entity\User\User # La classe de l'entité User que nous utilisons
# group:
# group_class: Root\ModelsBundle\Entity\User\Group
# form:
# type: Root\UserBundle\Form\Type\GroupType
# registration:
# confirmation:
# enabled: true
# template: UserBundle:Registration:email.html.twig
# form:
# type: Root\UserBundle\Form\RegistrationType
# validation_groups: [public_registration, Registration]
# profile:
# form:
# type: Root\UserBundle\Form\Type\ProfileFormType
# validation_groups: [public_edit, Default]
# resetting:
# email:
# template: UserBundle:Resetting:email.html.twig
from_email:
address: "%mailer_user%"
sender_name: CHORISTER_USER
# service:
# mailer: fos_user.mailer.twig_swift
nelmio_api_doc: ~
# JMS Serializer
jms_serializer:
metadata:
auto_detection: true
handlers:
datetime:
default_format: "Y-m-d\\TH:i:sP"
default_timezone: "UTC"
fos_rest:
body_converter:
enabled: true
format_listener:
rules:
- { path: '^/api', priorities: ['json'], fallback_format: json, prefer_extension: false }
- { path: '^/', priorities: ['html'], fallback_format: html, prefer_extension: false }
view:
view_response_listener: force
formats:
json: true
xml: false
routing_loader:
default_format: json
serializer:
serialize_null: true
param_fetcher_listener: true
body_listener: true
access_denied_listener:
json: true
# Lexik JWT Auth
lexik_jwt_authentication:
private_key_path: '%jwt_private_key_path%'
public_key_path: '%jwt_public_key_path%'
pass_phrase: '%jwt_key_pass_phrase%'
token_ttl: '%jwt_token_ttl%'
app/config/security.yml
# To get started with security, check out the documentation:
# https://symfony.com/doc/current/security.html
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
api_docs:
pattern: ^/doc
anonymous: true
login:
pattern: ^/api/login
stateless: true
anonymous: true
form_login:
check_path: /api/login_check
require_previous_session: false
username_parameter: username
password_parameter: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
anonymous: true
lexik_jwt:
authorization_header:
enabled: true
prefix: Bearer
query_parameter:
enabled: true
name: bearer
main:
pattern: ^/
logout_on_user_change: true
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
remember_me:
secret: "%secret%" # %secret% est un paramètre de parameter
# pour que l'user restz connecté longtemps
lifetime: 31536000 # 365 days in seconds
path: /
domain: ~ # Defaults to the current domain from $_SERVER
always_remember_me: true
remember_me_parameter: _remember_me
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# - { path: ^/, role: ROLE_USER }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Please any help ?
UPDATED
I change my code for this:
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$chants = $em->getRepository(Chant::class)->findAll();
$data = $this->get('jms_serializer')->serialize($chants, 'json', SerializationContext::create()->setGroups(array('list')));
$response = new Response($data);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
Things to do :
Your class should extend FOSRestController to use REST functionalities.
class ChantController extends FOSRestController
You can serialize and return response like this:
public function listAction(ParamFetcherInterface $paramFetcher, Request $request)
{
//...your code...//
$yourObjectifiedResult = $getRepository('yourentity')->findBy(['var' => $var]);
$yourNormalizedResult = $this->normalizeWithCircularHandler(
$yourObjectifiedResult,
['groups']);
//Serializer will convert your result from Object to Json Array automatically. To get a specific set of data, you can use groups.
$response = new JsonResponse(['success' => true, 'data' => $yourNormalizedResult ]);
$response->setStatusCode(Response::HTTP_OK);
return $response;
}
public function normalizeWithCircularHandler($data, $displayGroups, $normalizerCallbacks = false)
{
$encoder = new JsonEncoder();
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new ObjectNormalizer($classMetadataFactory);
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getId();
});
if(false != $normalizerCallbacks && is_array($normalizerCallbacks)) {
$normalizer->setCallbacks($normalizerCallbacks);
}
$serializer = new Serializer([$normalizer], [$encoder]);
return $serializer->normalize($data , null, ['groups' => $displayGroups]);
}
Information about serialization : http://symfony.com/doc/current/components/serializer.html
Information about serialization groups : https://symfony.com/blog/new-in-symfony-2-7-serialization-groups
Related
I don't know why but since today Status labels just gone...
I can change Status but there is no labels so I don't what I'm doing ;-)
app\config\config.yml
imports:
- { resource: #MyProductBundle/Resources/config/parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
- { resource: #MyProductBundle/Resources/config/admin.yml }
- { resource: ../../vendor/knplabs/doctrine-behaviors/config/orm-services.yml }
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
framework:
#esi: ~
translator: { fallbacks: ["%locale%"] }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
default_locale: "%locale%"
trusted_hosts: ~
trusted_proxies: ~
session:
# handler_id set to null will use default session handler from php.ini
handler_id: ~
fragments: ~
http_method_override: true
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
form:
resources: ['bootstrap_3_layout.html.twig']
# resources: ['bootstrap_3_horizontal_layout.html.twig]
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
# Assetic Configuration
assetic:
debug: "%kernel.debug%"
use_controller: false
bundles: [ ]
#java: /usr/bin/java
filters:
cssrewrite: ~
#closure:
# jar: "%kernel.root_dir%/Resources/java/compiler.jar"
#yui_css:
# jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
# Doctrine Configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
types:
json: Sonata\Doctrine\Types\JsonType
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
auto_mapping: true
mappings:
gedmo_translatable:
type: annotation
prefix: Gedmo\Translatable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
alias: GedmoTranslatable # this one is optional and will default to the name set for the mapping
is_bundle: false
gedmo_translator:
type: annotation
prefix: Gedmo\Translator\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translator/Entity"
alias: GedmoTranslator # this one is optional and will default to the name set for the mapping
is_bundle: false
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
# Swiftmailer Configuration
swiftmailer:
transport: "%mailer_transport%"
host: "%mailer_host%"
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
# FOSUserBundle Configuration
fos_user:
db_driver: orm
firewall_name: main
user_class: Application\Sonata\UserBundle\Entity\User
group:
group_class: Application\Sonata\UserBundle\Entity\Group
group_manager: sonata.user.orm.group_manager
service:
user_manager: sonata.user.orm.user_manager
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
# Sonata Configuration
sonata_user:
security_acl: true
table:
user_group: fos_user_user_group
manager_type: orm
profile:
form:
type: sonata_user_profile
handler: sonata.user.profile.form.handler.default
name: sonata_user_profile_form
validation_groups:
# Defaults:
- Profile
- Default
dashboard:
blocks:
- { position: left, type: sonata.block.service.text, settings: { content: "<h2>Welcome!</h2> This is a sample user profile dashboard, feel free to override it in the configuration! Want to make this text dynamic? For instance display the user's name? Create a dedicated block and edit the configuration!"} }
# - { position: right, type: sonata.news.block.recent_comments, settings: { title: Recent Comments, number: 5, mode: public }}
# Customize user portal menu by setting links
menu:
- { route: 'sonata_user_profile_show', label: 'sonata_profile_title', domain: 'SonataUserBundle'}
- { route: 'sonata_user_profile_edit', label: 'link_edit_profile', domain: 'SonataUserBundle'}
- { route: 'sonata_user_profile_edit_authentication', label: 'link_edit_authentication', domain: 'SonataUserBundle'}
sonata_admin:
security:
handler: sonata.admin.security.handler.noop
title: JustShop (-;
title_logo: img/logo.png
dashboard:
blocks:
# display a dashboard block
-
position: left
type: sonata.admin.block.admin_list
# Customize this part to add new block configuration
-
position: right,
type: sonata.block.service.text,
settings:
content: "<h2>Welcome to the Sonata Admin</h2> <p>This is a <code>sonata.block.service.text</code> from the Block Bundle, you can create and add new block in these area by configuring the <code>sonata_admin</code> section.</p> <br /> For instance, here a RSS feed parser (<code>sonata.block.service.rss</code>):"
-
position: right
type: sonata.block.service.rss
settings:
title: Sonata Projects Feeds
url: http://sonata-project.org/blog/archive.rss
persist_filters: true
sonata_block:
default_contexts: [cms]
blocks:
# Enable the SonataAdminBundle block
sonata.admin.block.admin_list:
contexts: [admin]
sonata.admin.block.search_result:
contexts: [admin]
sonata.user.block.menu: # used to display the menu in profile pages
sonata.user.block.account: # used to display menu option (login option)
sonata.block.service.text: # used to if you plan to use Sonata user routes
sonata.block.service.rss:
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
stof_doctrine_extensions:
default_locale: en_US
translation_fallback: true
orm:
default:
sluggable: true
timestampable: true
translatable: true
#-------------------------------------------------------------------------------------------------------------------------------------------------------------
a2lix_translation_form:
locale_provider: default
locales: [en, pl]
default_locale: en
required_locales: [en]
manager_registry: doctrine
templating: "A2lixTranslationFormBundle::default.html.twig"
app\config\security.yml
# you can read more about security in the related section of the documentation
# http://symfony.com/doc/current/book/security.html
security:
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
encoders:
FOS\UserBundle\Model\UserInterface: sha512
# http://symfony.com/doc/current/book/security.html#hierarchical-roles
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
SONATA:
- ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT # if you are using acl then this line must be commented
providers:
# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
fos_userbundle:
id: fos_user.user_manager
# the main part of the security, where you can set up firewalls
# for specific sections of your app
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# -> custom firewall for the admin area of the URL
admin:
switch_user: true
context: user
pattern: /admin(.*)
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /admin/login_check
failure_path: null
use_referer: true
logout:
path: /logout
target: /login
anonymous: true
remember_me:
key: 9034895c8e6816cad3f8fc4d3171bce10
lifetime: 3600
path: /
domain: ~
# -> end custom configuration
# defaut login area for standard users
main:
switch_user: true
context: user
pattern: .*
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /login_check
failure_path: null
logout: true
anonymous: true
remember_me:
key: 9034895c8e6816cad3f8fc4d3171bce10
lifetime: 3600
path: /
domain: ~
acl:
connection: default
# with these settings you can restrict or allow access for different parts
# of your application based on roles, ip, host or methods
# http://symfony.com/doc/current/cookbook/security/access_control.html
access_control:
# URL of FOSUserBundle which need to be available to anonymous users
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Admin login page needs to be access without credential
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Secured part of the site
# This config requires being logged for the whole site and having the admin role for the admin part.
# Change these rules to adapt them to your needs
- { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
- { path: ^/product/, role: IS_AUTHENTICATED_FULLY }
- { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
It's a bug in symfony(?) bootstrap defaults configuration
changed from
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
form:
resources: ['bootstrap_3_layout.html.twig']
# resources: ['bootstrap_3_horizontal_layout.html.twig]
to
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
form:
# resources: ['bootstrap_3_layout.html.twig']
# resources: ['bootstrap_3_horizontal_layout.html.twig]
I'm beginner. I installed FOSUserBundle on Symfony 2.6.3 fallowing instruction in book im learning (book is based on Symfony 2.0.10. I'm on 407 page, and no biger problems till now).
Excercise i stuck is about run and test new Symfony-with-FOSUserBundle-version.
Following errors dipslay while im running command doctrine:schema:update --force
[Doctrine\DBAL\Exception\ConnectionException] An exception occured in driver: SQLSTATE[HY000] [1049] Base 'symfony' inconnue
[Doctrine\DBAL\Driver\PDOException]SQLSTATE[HY000] [1049] Base 'symfony' inconnue
[PDOException]SQLSTATE[HY000] [1049] Base 'symfony' inconnue
Here are files I changed while configured new Symfony-with-FOSUserBundle-version
1.
#\app\config\parameters.yml
parameters:
database_driver: pdo_mysql
database_host: localhost
database_port: null
database_name: symfony2sandbox
database_user: editor
database_password: secretPASSWORD
mailer_transport: smtp
mailer_host: localhost
mailer_user: null
mailer_password: null
locale: en
secret: ThisTokenIsNotSoSecretChangeIt
2.
#\src\My\UserBundle\Entity\User.php
<?php
namespace My\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
}
3.
#\app\config\security.yml
security:
providers:
fos_userbundle:
id: fos_user.user_manager
encoders:
FOS\UserBundle\Model\UserInterface: sha512
firewalls:
main:
pattern: ^/
logout: true
anonymous: true
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
use_forward: false
check_path: /login_check
post_only: true
always_use_default_target_path: false
default_target_path: /
target_path_parameter: _target_path
use_referer: false
failure_path: null
failure_forward: false
username_parameter: _username
password_parameter: _password
csrf_parameter: _csrf_token
intention: authenticate
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
4.
#\app\config\config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
framework:
#esi: ~
translator: ~
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
default_locale: "%locale%"
trusted_hosts: ~
trusted_proxies: ~
session:
default_locale: pl
# handler_id set to null will use default session handler from php.ini
handler_id: ~
fragments: ~
http_method_override: true
# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
# Assetic Configuration
assetic:
debug: "%kernel.debug%"
use_controller: false
bundles: [ ]
#java: /usr/bin/java
filters:
cssrewrite: ~
#closure:
# jar: "%kernel.root_dir%/Resources/java/compiler.jar"
#yui_css:
# jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"
# Doctrine Configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: "%kernel.root_dir%/data/data.db3"
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
# path: "%database_path%"
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
# Swiftmailer Configuration
swiftmailer:
transport: "%mailer_transport%"
host: "%mailer_host%"
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
stof_doctrine_extensions:
default_locale: en_US
orm:
default:
tree: false
loggable: false
timestampable: false
sluggable: false
translatable: false
fos_user:
db_driver: orm
firewall_name: main
user_class: My\UserBundle\Entity\User
5.
#\app\config\routing.yml
fos_user_security:
resource: "#FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
resource: "#FOSUserBundle/Resources/config/routing/profile.xml"
prefix: /profile
fos_user_register:
resource: "#FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /register
fos_user_resetting:
resource: "#FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /resetting
fos_user_change_password:
resource: "#FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /profile
Important thing:
not relevant content of \config\parameters.yml. These errors occurs also on parameters.yml settings from earlier version of Symfony-without-FOS, that worked fine.
database from sql command:
drop schema if exists symfony2sandbox;
create schema symfony2sandbox default character set utf8 collate utf8_polish_ci;
grant all on symfony2sandbox.* to editor#localhost identified by 'secretPASSWORD';
flush privileges;
solved by:
in config.yml comment line
# default_locale: pl
in \src\My\UserBundle\Entity\User.php changing line use FOS\UserBundle\Entity\User as BaseUser; to use FOS\UserBundle\Model\User as BaseUser;
Maybe typo in my book, maybe difference by outdate. (book from 2012 y.)
Recently, I started working with Symfony2. Now I want to add a user management engine to my site.
But I'm facing a problem. This is what I'm doing:
In terms of creating/installing a basic Symfony2 project:
$ composer create-project symfony/framework-standard-edition path/ "2.5.*"
$ mv path/* ./
$ rm -r path/
Ok, so much for Symfony 2.5.5. Next, download the FOSUserBundle and create a custom bundle:
$ composer require friendsofsymfony/user-bundle '~2.0#dev'
$ php app/console generate:bundle --namespace=Meiblorn/CoreBundle --format=yml
Create the User class in the Meiblorn\CoreBundle\Framework\Domain namespace
/**
* User: Meiblorn
* Date: 15/10/14
* Time: 20:17
*/
namespace Meiblorn\CoreBundle\Framework\Domain;
use FOS\UserBundle\Model\User as FOSUserBundleUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(
* name = "users"
* )
*/
class User extends FOSUserBundleUser {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct() {
parent::__construct();
// your own logic
}
}
?>
Configure the security.yml and config.yml. Finally, I got this:
AppKernel.php
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Symfony\Bundle\AsseticBundle\AsseticBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new FOS\UserBundle\FOSUserBundle(),
new Meiblorn\CoreBundle\MeiblornCoreBundle(),
);
config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }
framework:
#esi: ~
translator: { fallback: "%locale%" }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
default_locale: "%locale%"
trusted_hosts: ~
trusted_proxies: ~
session:
# handler_id set to null will use default session handler from php.ini
handler_id: ~
fragments: ~
http_method_override: true
# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
# Assetic Configuration
assetic:
debug: "%kernel.debug%"
use_controller: false
bundles: [ ]
#java: /usr/bin/java
filters:
cssrewrite: ~
#closure:
# jar: "%kernel.root_dir%/Resources/java/compiler.jar"
#yui_css:
# jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"
# Doctrine Configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
# Swiftmailer Configuration
swiftmailer:
transport: "%mailer_transport%"
host: "%mailer_host%"
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
fos_user:
db_driver: orm
firewall_name: prod
user_class: Meiblorn\CoreBundle\Framework\Domain\User
security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
prod:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
THIS IS THE PROBLEM
In browser: http://localhost/test.meiblorn.com/web/app_dev.php/
MappingException: The class 'Meiblorn\CoreBundle\Framework\Domain\User' was not found in the chain configured namespaces FOS\UserBundle\Model
in /Library/WebServer/Documents/test.meiblorn.com/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php line 37
at MappingException::classNotFoundInNamespaces('Meiblorn\CoreBundle\Framework\Domain\User', array('FOS\UserBundle\Model')) in /Library/WebServer/Documents/test.meiblorn.com/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php line 113
at MappingDriverChain->loadMetadataForClass('Meiblorn\CoreBundle\Framework\Domain\User', object(ClassMetadata)) in /Library/WebServer/Documents/test.meiblorn.com/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php line 117
at ClassMetadataFactory->doLoadMetadata(object(ClassMetadata), object(ClassMetadata), false, array()) in /Library/WebServer/Documents/test.meiblorn.com/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php line 318
Also Doctrine doesn't create tables for this mapping when calling doctrine:schema:update
Please, help me to fix this exception
UPDATE! How to fix
Final configuration for my namespace
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: false
mappings:
FOSUserBundle: ~
MeiblornCoreBundle:
type: annotation
dir: %kernel.root_dir%/../src/Meiblorn/CoreBundle/Framework/Entity
prefix: Meiblorn\CoreBundle\Framework\Entity
# alias: MyModels
# is_bundle: true
First you need to configure psr-4 autoload in your composer.js, for example
"autoload": {
"psr-4": {
"Meiblorn\\CoreBundle\\": "src/Meiblorn/CoreBundle/"
}
},
Then call composer dumpautoload.
Secondly, I believe Doctrine expects the entities to live in a folder Entity/, so try to move you model: src/Meiblorn/CoreBundle/Framework/Domain/User.php to src/Meiblorn/CoreBundle/Entity/User.php or How do I change symfony 2 doctrine mapper to use my custom directory instead of my Entity Directory under the bundle
I am trying to implement HWIOAuthBundle with FOSUserBundle for having both standard (login and registration) and OAuth (login and registration).
I don't know how to finalise this.
Here is my config files:
config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }
framework:
#esi: ~
translator: { fallback: "%locale%" }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
default_locale: "%locale%"
trusted_hosts: ~
trusted_proxies: ~
session:
# handler_id set to null will use default session handler from php.ini
handler_id: ~
fragments: ~
http_method_override: true
# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
globals:
title: %app_title%
contact: %app_contact%
# Assetic Configuration
assetic:
debug: "%kernel.debug%"
use_controller: false
bundles: [ ]
#java: /usr/bin/java
filters:
cssrewrite: ~
#closure:
# jar: "%kernel.root_dir%/Resources/java/compiler.jar"
#yui_css:
# jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"
# Doctrine Configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
# if using pdo_sqlite as your database driver, add the path in parameters.yml
# e.g. database_path: "%kernel.root_dir%/data/data.db3"
# path: "%database_path%"
#config.yml
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
# Swiftmailer Configuration
swiftmailer:
transport: "%mailer_transport%"
host: "%mailer_host%"
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
fos_user:
db_driver: orm
firewall_name: main
user_class: IService\MyFuckingBundles\UserBundle\Entity\User
registration:
confirmation:
enabled: false #change to true for production use!
hwi_oauth:
# name of the firewall in which this bundle is active, this setting MUST be set
firewall_name: social
connect:
confirmation: false
#account_connector: hwi_oauth.user.provider.fosub_bridge
#registration_form_handler: hwi_oauth.registration.form.handler.fosub_bridge
#registration_form: fos_user.registration.form
resource_owners:
facebook:
type: facebook
client_id: 11111111111111111
client_secret: abcdefg
scope: "email"
options:
display: popup
fosub:
# try 30 times to check if a username is available (foo, foo1, foo2 etc)
username_iterations: 30
# mapping between resource owners (see below) and properties
properties:
facebook: facebookID
security.yml
# app/config/security.yml
jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
remember_me:
key: %secret%
social:
pattern: ^/c
oauth:
failure_path: /c/connect
login_path: /c/connect
check_path: /c/connect
provider: fos_userbundle
resource_owners:
facebook: "/c/connect/check-facebook"
oauth_user_provider:
service: hwi_oauth.user.provider.fosub_bridge
anonymous: true
logout: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/c/connect, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
routing.yml
i_service_score_it_page:
resource: "#IServiceMyFuckingBundlesPageBundle/Controller/"
type: annotation
prefix: /
i_service_score_it_user:
resource: "#IServiceMyFuckingBundlesUserBundle/Controller/"
type: annotation
prefix: /
fos_user_security:
resource: "#FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
resource: "#FOSUserBundle/Resources/config/routing/profile.xml"
prefix: /profile
fos_user_register:
resource: "#FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /register
fos_user_resetting:
resource: "#FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /resetting
fos_user_change_password:
resource: "#FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /profile
hwi_oauth_redirect:
resource: "#HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /c/connect
hwi_oauth_login:
resource: "#HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /c/connect
hwi_oauth_connect:
resource: "#HWIOAuthBundle/Resources/config/routing/connect.xml"
prefix: /c/connect
#HERE ADD FACEBOOK, TWITTER AND LINKEDIN SSO
hwi_facebook_login:
pattern: /c/connect/check-facebook
and finally my User.php
<?php
/**
* Users
*
*/
namespace IService\MyFuckingBundles\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="c_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/** #ORM\Column(name="facebook_id", type="string", length=255, nullable=true) */
protected $facebookID;
/** #ORM\Column(name="facebook_access_token", type="string", length=255, nullable=true) */
protected $facebookAcessToken;
/** #ORM\Column(name="google_id", type="string", length=255, nullable=true) */
protected $googleID;
/** #ORM\Column(name="google_access_token", type="string", length=255, nullable=true) */
protected $googleAccessToken;
public function __construct()
{
parent::__construct();
// your own logic
}
public function getId(){
return $this->id;
}
/**
* Get Facebook_id
*/
public function getFacebookID(){
return $this->facebook_id;
}
/**
* set facebook Id
* #return User
*/
public function setFacebookID($facebook_id){
$this->facebook_id = $facebook_id;
return $this;
}
}
When I am trying the authentication with the following steps:
* url -> /c/connect I have the facebook connect link
* Click on it and then accept the facebook login
* Finally returning on the website and I am having this error: No resource owner with name 'check-facebook'
First off you might be disappointed with the registration process. I found it to be quite byzantine and finally gave up. It requires two different redirect urls (one for login and one for connecting) which not all oauth servers support. Facebook and Google do so you should be okay. I don't think twitter support multiple callback or if it does then I could not get it to work.
In any event, I found I had to use named routes for the check login stuff (which is different than the connect stuff)
security.yml
...
oauth:
resource_owners:
facebook: facebook_login_check
google: google_login_check
routing.yml
facebook_login_check:
pattern: /login/check-facebook
google_login_check:
pattern: /login/check-google
I never tracked down why but I think the "%resource_owner%_login_check" is hard coded somewhere and used to match the callback route to a specific resource owner.
In any event, give named routes a shot and see if that get's you passed the error. If it does then I suspect your fun will just be beginning.
============================================================
Update 1
I remember that I also had to add these named routes. Not sure but you could try it.
routing.yml
github_connect:
pattern: /connect/github
google_connect:
pattern: /connect/google
twitter_connect:
pattern: /connect/twitter
my check box is missing from addnew user /management tab, when i was trying to create a new user in sonata user (means i can't access any role for assigning it to any user or for creating a role group
here is my
config.yml:
imports:
- { resource: parameters.yml }
- { resource: security.yml }
framework:
#esi: ~
translator: { fallback: %locale% }
secret: %secret%
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
default_locale: "%locale%"
trusted_proxies: ~
session: ~
fragments: ~
http_method_override: true
# Twig Configuration
twig:
debug: %kernel.debug%
strict_variables: %kernel.debug%
# Assetic Configuration
# Doctrine Configuration
doctrine:
dbal:
driver: %database_driver%
host: %database_host%
port: %database_port%
dbname: %database_name%
user: %database_user%
password: %database_password%
charset: UTF8
# if using pdo_sqlite as your database driver, add the path in parameters.yml
# e.g. database_path: %kernel.root_dir%/data/data.db3
# path: %database_path%
types:
json: Sonata\Doctrine\Types\JsonType
orm:
auto_generate_proxy_classes: %kernel.debug%
entity_managers:
default:
mappings:
ApplicationSonataUserBundle: ~
SonataUserBundle: ~
FOSUserBundle: ~
# Swiftmailer Configuration
swiftmailer:
transport: %mailer_transport%
host: %mailer_host%
username: %mailer_user%
password: %mailer_password%
spool: { type: memory }
bc_bootstrap:
less_filter: less
assets_dir: %kernel.root_dir%/../vendor/twitter/bootstrap
jquery_path: %kernel.root_dir%/../vendor/jquery/jquery/jquery-1.9.1.js
sonata_block:
default_contexts: [cms]
blocks:
# Enable the SonataAdminBundle block
sonata.admin.block.admin_list:
contexts: [admin]
sonata.block.service.text:
sonata.block.service.rss:
sonata.user.block.menu: # used to display the menu in profile pages
sonata.user.block.account: # used to display menu option (login option)
sonata_admin:
title: Admin
#title_logo: bundles/acmedemo/img/fancy_acme_logo.png
security:
handler: sonata.admin.security.handler.role
#acl_user_manager: fos_user.user_manager
# Name of the user manager service used to retrieve ACL users
options:
html5_validate: false
# does not use html5 validation
confirm_exit: false
# disable confirmation when quitting with unsaved changes
# set to true to persist filter settings per admin module in the user's session
#persist_filters: false
templates:
dashboard: SonataAdminBundle:Core:dashboard.html.twig
search: SonataAdminBundle:Core:search.html.twig
search_result_block: SonataAdminBundle:Block:block_search_result.html.twig
dashboard:
blocks:
-
position: left
type: sonata.admin.block.admin_list
-
position: right
type: sonata.block.service.text
settings:
content: >
<h2>Welcome Admin</h2>
sonata_user:
security_acl: false
manager_type: orm
# can be orm or mongodb
table:
user_group: "my_custom_user_group_association_table_name"
#impersonating:
# route: page_slug
# parameters: { path: / }
class: # Entity Classes
user: Application\Sonata\UserBundle\Entity\User
group: Application\Sonata\UserBundle\Entity\Group
admin: # Admin Classes
user:
class: Sonata\UserBundle\Admin\Entity\UserAdmin
controller: SonataAdminBundle:CRUD
translation: SonataUserBundle
group:
class: Sonata\UserBundle\Admin\Entity\GroupAdmin
controller: SonataAdminBundle:CRUD
translation: SonataUserBundle
profile:
menu:
- { route: 'sonata_user_profile_show', label: 'sonata_profile_title', domain: 'SonataUserBundle'}
- { route: 'sonata_user_profile_edit', label: 'link_edit_profile', domain: 'SonataUserBundle'}
#- { route: 'sonata_customer_addresses', label: 'link_list_addresses', domain: 'SonataCustomerBundle'}
- { route: 'sonata_user_profile_edit_authentication', label: 'link_edit_authentication', domain: 'SonataUserBundle'}
#- { route: 'sonata_order_index', label: 'order_list', domain: 'SonataOrderBundle'}
# This allows you to specify where you want your user redirected once he activated his account
form:
type: sonata_user_profile
handler: sonata.user.profile.form.handler.default
name: sonata_user_profile_form
validation_groups: [Profile]
google_authenticator:
enabled: true
server: yourserver.com
fos_user:
db_driver: orm
# other valid values are 'mongodb', 'couchdb' and 'propel'
firewall_name: main
user_class: Application\Sonata\UserBundle\Entity\User
group:
group_class: Application\Sonata\UserBundle\Entity\Group
profile:
# Authentication Form
form:
type: fos_user_profile
handler: fos_user.profile.form.handler.default
name: fos_user_profile_form
validation_groups: [Authentication]
# Please note : this is not the default value
And here is my security.yml:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
ROLE_USER: ROLE_MY_CUSTOM
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
context: user
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /login_check
failure_path: null
logout: true
anonymous: true
admin:
pattern: /admin(.*)
context: user
form_login:
provider: fos_userbundle
login_path: /admin/login
use_forward: false
check_path: /admin/login_check
failure_path: null
logout:
path: /admin/logout
anonymous: true
acl:
connection: default
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/demo/secured/hello/admin/, roles: ROLE_ADMIN }
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
access_decision_manager:
# Strategy can be: affirmative, unanimous or consensus
strategy: unanimous
And here is my routing.yml:
admin:
resource: '#SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
prefix: /admin
_sonata_admin:
resource: .
type: sonata_admin
prefix: /admin
sonata_user:
resource: '#SonataUserBundle/Resources/config/routing/admin_security.xml'
prefix: /
fos_user_security:
resource: "#FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
resource: "#SonataUserBundle/Resources/config/routing/profile.xml"
prefix: /profile
fos_user_register:
resource: "#FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /register
fos_user_resetting:
resource: "#FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /resetting
fos_user_change_password:
resource: "#FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /profile
Thank you in advance
Your connected user must have the ROLE_SUPER_ADMIN role
do a
php app/console fos:user:promote [username] ROLE_SUPER_ADMIN
and make sure to call this in your UserAdmin
->add('realRoles', 'sonata_security_roles', array(
'expanded' => true,
'multiple' => true,
'required' => false
))
For symfony 4, use this:
use Sonata\UserBundle\Form\Type\SecurityRolesType;
protected function configureFormFields(FormMapper $formMapper): void
{
$formMapper
->add('roles', SecurityRolesType::class, [
'expanded' => true,
'multiple' => true,
'required' => false,
]);
}