{"id":16768774,"url":"https://github.com/phptuts/starterbundleforsymfony","last_synced_at":"2026-04-27T20:31:37.230Z","repository":{"id":57059219,"uuid":"109935312","full_name":"phptuts/StarterBundleForSymfony","owner":"phptuts","description":"Startkit Bundle For Symfony Projects","archived":false,"fork":false,"pushed_at":"2018-05-04T22:49:04.000Z","size":11007,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-15T22:15:07.292Z","etag":null,"topics":["guard","security","symfony"],"latest_commit_sha":null,"homepage":"https://skbfsp.info","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phptuts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/security.md","support":null}},"created_at":"2017-11-08T06:13:19.000Z","updated_at":"2019-03-16T14:17:17.000Z","dependencies_parsed_at":"2022-08-24T14:53:26.893Z","dependency_job_id":null,"html_url":"https://github.com/phptuts/StarterBundleForSymfony","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phptuts%2FStarterBundleForSymfony","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phptuts%2FStarterBundleForSymfony/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phptuts%2FStarterBundleForSymfony/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phptuts%2FStarterBundleForSymfony/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phptuts","download_url":"https://codeload.github.com/phptuts/StarterBundleForSymfony/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254430325,"owners_count":22069909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["guard","security","symfony"],"created_at":"2024-10-13T06:12:30.760Z","updated_at":"2026-04-27T20:31:37.183Z","avatar_url":"https://github.com/phptuts.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Setup Guide and Project Overview\n\n[![Build Status](https://travis-ci.org/phptuts/starterkitforsymfony.svg?branch=master)](https://travis-ci.org/phptuts/starterkitforsymfony)  \n\n[![codecov](https://codecov.io/gh/phptuts/StarterBundleForSymfony/branch/master/graph/badge.svg)](https://codecov.io/gh/phptuts/StarterBundleForSymfony)\n\n- [Example Website Using Symfony 4](https://skbfsp.info)\n- [Example Code Using Symfony 4](https://github.com/phptuts/starter-bundle-example-symfony-4) \n- [Example Code Using Symfony 3](https://github.com/phptuts/starter-bundle-example) \n\n\n## Setup Guide Symfony 4\n\n\n1) Install the bundle, don't do the recipe at this time. \n\n``` \ncomposer require start-kit-symfony/start-bundle\n\n```\n\n2) Add the api routes to the bundle in the config -\u003e routes.yaml\n\n``` \nstarter_kit_start:\n    resource: \"@StarterKitStartBundle/Resources/config/routing.yml\"\n```\n\n3) Add  NelmioApiDocBundle to bundles.php in -\u003e config folder\n\n```\nNelmio\\ApiDocBundle\\NelmioApiDocBundle::class =\u003e ['all' =\u003e true],\n```\n\n4) Add a nelmio_api_doc.yaml to the config folder and paste this in there.\n\n``` \nnelmio_api_doc:\n    routes:\n        path_patterns: # an array of regexps\n            - ^/(api(?!-docs))\n            - ^/oauth\n            - ^/login_check\n            - ^/access-tokens\n\n\n    models: { use_jms: false }\n    documentation:\n        info:\n            title: 'Symfony Starter Api'\n            description: 'Our Symfony Starter Kit Api Documentation.'\n            version: 1.0.0\n\n```\n\n5) Add the service alias to services.yaml file.  This is a temporary hack.\n\n``` \nNelmio\\ApiDocBundle\\ApiDocGenerator: '@nelmio_api_doc.generator'\n```\n\n6) Add A controller class called ApiDocController and add method called apiDoc\n\n``` \n\u003c?php\n\nnamespace App\\Controller;\n\nuse Nelmio\\ApiDocBundle\\ApiDocGenerator;\nuse Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\nclass ApiDocController extends Controller\n{\n    /**\n     * @var ApiDocGenerator\n     */\n    private $apiDocGenerator;\n\n    public function __construct(ApiDocGenerator $apiDocGenerator)\n    {\n        $this-\u003eapiDocGenerator = $apiDocGenerator;\n    }\n\n    /**\n     * @Route(name=\"api_docs\", path=\"api-docs\", methods={\"GET\"})\n     *\n     * @param Request $request\n     * @return Response\n     */\n    public function apiDoc(Request $request)\n    {\n        $spec = $this-\u003eapiDocGenerator-\u003egenerate()-\u003etoArray();\n        if ('' !== $request-\u003egetBaseUrl()) {\n            $spec['basePath'] = $request-\u003egetBaseUrl();\n        }\n\n        return $this-\u003erender('@NelmioApiDoc/SwaggerUi/index.html.twig', ['swagger_data' =\u003e ['spec' =\u003e $spec]]);\n    }\n}\n```\n\n7) Create a jwt directory in your var folder\n``` \nmkdir var/jwt\n```\n8) Create your private key with and write down the pass phrase you used.\n\n``` \nopenssl genrsa -out var/jwt/private.pem -aes256 4096\n```\n9) Create your public key, you will need the pass phrase here and in the composer install step\n\n``` \nopenssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem\n```\n\n10) In your App -\u003e Entity folder create a User class that extends the [BaseUser](https://github.com/phptuts/StarterBundleForSymfony/blob/master/Entity/BaseUser.php).\n\n11) When u create your s3 Bucket you will need to a folder for each environment you have. In that folder you will need to add another folder called profile_pics which is where the personal pictures are stored. Say you have dev and prod.  You can over ride this or not use s3 if you want to.\n\n    prod -\u003e profile_pics\n    dev -\u003e profile_pics\n\n12) Fill out all the information for setting up service parameters in your .env file.\n\n``` \n###\u003e start-kit-symfony/start-bundle ###\n\n# The Secret Pass\nJWS_PASS_PHRASE=secret_change\nJWS_TTL=5184000\nREFRESH_TOKEN_TTL=10368000\n\n# Facebook Config\nFACEBOOK_APP_SECRET=facebook_secret\nFACEBOOK_APP_ID=facebook_app_id\nFACEBOOK_API_VERSION=2.10\n# Google\nGOOGLE_CLIENT_ID=google_client_id\n\n# Amazon\nAWS_KEY=amazon_key\nAWS_SECRET=amazon_secret\nAWS_REGION=us-west-2\nAWS_BUCKET=fake-bucket\nAWS_VERSION=2006-03-01\n\n# Slack\nSLACK_CLIENT_KEY=slack_client_key\nSLACK_CLIENT_ID=slack_client_id\n\n###\u003c start-kit-symfony/start-bundle ###\n\nAPP_EMAIL=fake_email@gmail.com\n```\n\n14) Create a folder in your App called \"Entity\" and in that folder create an Entity Class called User. \n\n``` \n\u003c?php\nnamespace AppBundle\\Entity;\nuse StarterKit\\StartBundle\\Entity\\BaseUser;\nuse Doctrine\\ORM\\Mapping as ORM;\nuse StarterKit\\StartBundle\\Entity\\FacebookTrait;\nuse StarterKit\\StartBundle\\Entity\\GoogleTrait;\nuse StarterKit\\StartBundle\\Entity\\ImageTrait;\nuse StarterKit\\StartBundle\\Entity\\RefreshTokenTrait;\nuse StarterKit\\StartBundle\\Entity\\SlackTrait;\n/**\n * @ORM\\Entity(repositoryClass=\"StarterKit\\StartBundle\\Repository\\UserRepository\")\n * @ORM\\Table(name=\"User\")\n * @ORM\\HasLifecycleCallbacks()\n * @ORM\\Table(name=\"User\", indexes={\n *     @ORM\\Index(name=\"idk_email\", columns={\"email\"}),\n *     @ORM\\Index(name=\"idk_google_user_id\", columns={\"google_user_id\"}),\n *     @ORM\\Index(name=\"idk_slack_user_Id\", columns={\"slack_user_id\"}),\n *     @ORM\\Index(name=\"idk_facebook_user_id\", columns={\"facebook_user_id\"}),\n *     @ORM\\Index(name=\"idk_forget_password_token\", columns={\"forget_password_token\"}),\n *     @ORM\\Index(name=\"idk_refresh_token\", columns={\"refresh_token\"})\n * })\n * Class User\n * @package AppBundle\\Entity\n */\nclass User extends BaseUser\n{\n    use ImageTrait;\n    use GoogleTrait;\n    use FacebookTrait;\n    use SlackTrait;\n    use RefreshTokenTrait;\n}\n```\n\n\n15) Register Firewalls and Security Providers config -\u003e packages -\u003e security.yaml for symfony 4.\n\n\n``` \nsecurity:\n\n    encoders:\n        AppBundle\\Entity\\User:\n            algorithm: bcrypt\n            cost: 12\n\n    # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded\n    providers:\n        email:\n            id: StarterKit\\StartBundle\\Security\\Provider\\EmailProviderInterface\n        slack:\n            id: StarterKit\\StartBundle\\Security\\Provider\\SlackProviderInterface\n        token:\n            id: StarterKit\\StartBundle\\Security\\Provider\\TokenProviderInterface\n        facebook:\n            id: StarterKit\\StartBundle\\Security\\Provider\\FacebookProviderInterface\n        google:\n            id: StarterKit\\StartBundle\\Security\\Provider\\GoogleProviderInterface\n        refresh:\n            id: StarterKit\\StartBundle\\Security\\Provider\\RefreshTokenProviderInterface\n\n    role_hierarchy:\n        ROLE_ADMIN:  [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]\n\n\n    firewalls:\n        # disables authentication for assets and the profiler, adapt it according to your needs\n        dev:\n            pattern: ^/(_(profiler|wdt)|css|images|js)/\n            security: false\n\n        facebook:\n            pattern: ^/access-tokens/facebook\n            stateless: true\n            provider: facebook\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        google:\n            pattern: ^/access-tokens/google\n            stateless: true\n            provider: google\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        slack:\n            pattern: ^/oauth/slack*\n            stateless: true\n            provider: slack\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\OAuthGuardInterface\n\n        refresh:\n            pattern: ^/access-tokens/refresh\n            stateless: true\n            provider: refresh\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        login:\n            pattern: ^/login_check\n            stateless: true\n            provider: email\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        api:\n            pattern: ^/api*\n            anonymous: ~\n            stateless: true\n            provider: token\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\StateLess\\ApiGuardInterface\n\n        main:\n            pattern: ^/*\n            anonymous: ~\n            provider: token\n            stateless: true\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\StateLess\\WebsiteGuardInterface\n\n    access_control:\n        - { path: ^/admin, roles: ROLE_ADMIN }\n\n```\n\n## Setup Guide Symfony 3 \n \n\n1) Install the bundle\n``` \ncomposer require start-kit-symfony/start-bundle\n```\n\n2) Add to Bundle class to the app kernel.\n\n``` \n    new StarterKit\\StartBundle\\StarterKitStartBundle(),\n```\n\n3) cd into the directory where your project is\n\n4) Create a jwt directory in your var folder\n``` \nmkdir var/jwt\n```\n5) Create your private key with and write down the pass phrase you used.\n\n``` \nopenssl genrsa -out var/jwt/private.pem -aes256 4096\n```\n6) Create your public key, you will need the pass phrase here and in the composer install step\n\n``` \nopenssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem\n```\n\n7) In your AppBundle -\u003e Entity folder create a User class that extends the [BaseUser](https://github.com/phptuts/StarterBundleForSymfony/blob/master/Entity/BaseUser.php).\n\n8) When u create your s3 Bucket you will need to a folder for each environment you have. In that folder you will need to add another folder called profile_pics which is where the personal pictures are stored. Say you have dev and prod.  You can over ride this or not use s3 if you want to.\n\n    prod -\u003e profile_pics\n    dev -\u003e profile_pics\n\n9) Create a folder in your App called \"Entity\" and in that folder create an Entity Class called User. \n\n``` \n\u003c?php\nnamespace AppBundle\\Entity;\nuse StarterKit\\StartBundle\\Entity\\BaseUser;\nuse Doctrine\\ORM\\Mapping as ORM;\nuse StarterKit\\StartBundle\\Entity\\FacebookTrait;\nuse StarterKit\\StartBundle\\Entity\\GoogleTrait;\nuse StarterKit\\StartBundle\\Entity\\ImageTrait;\nuse StarterKit\\StartBundle\\Entity\\RefreshTokenTrait;\nuse StarterKit\\StartBundle\\Entity\\SlackTrait;\n/**\n * @ORM\\Entity(repositoryClass=\"StarterKit\\StartBundle\\Repository\\UserRepository\")\n * @ORM\\Table(name=\"User\")\n * @ORM\\HasLifecycleCallbacks()\n * @ORM\\Table(name=\"User\", indexes={\n *     @ORM\\Index(name=\"idk_email\", columns={\"email\"}),\n *     @ORM\\Index(name=\"idk_google_user_id\", columns={\"google_user_id\"}),\n *     @ORM\\Index(name=\"idk_slack_user_Id\", columns={\"slack_user_id\"}),\n *     @ORM\\Index(name=\"idk_facebook_user_id\", columns={\"facebook_user_id\"}),\n *     @ORM\\Index(name=\"idk_forget_password_token\", columns={\"forget_password_token\"}),\n *     @ORM\\Index(name=\"idk_refresh_token\", columns={\"refresh_token\"})\n * })\n * Class User\n * @package AppBundle\\Entity\n */\nclass User extends BaseUser\n{\n    use ImageTrait;\n    use GoogleTrait;\n    use FacebookTrait;\n    use SlackTrait;\n    use RefreshTokenTrait;\n}\n```\n\n10) Configure the Bundle, in the app -\u003e config -\u003e config.yml file.\n\n``` \nstarter_kit_start:\n\n    login_url: '%app.login_url%' # this is the path that your login screen is.  This where website guard will nagivate people if login is required and the user is not logged in.\n\n    jws_ttl: '%app.jws_ttl%' # This the number of seconds the jwt token will live\n    jws_pass_phrase: '%app.jws_pass_phrase%' # This the pass phrased you used to create jwt private / public keys.\n    refresh_token_ttl: '%app.refresh_token_ttl%' # This how long the refresh token will live.\n\n    user_class: '%app.user_class%' # This is concrete class that extends the base user\n\n    facebook_app_secret: '%app.facebook_app_secret%' # This is client secret that you get when you register your website with facebook\n    facebook_api_version: '%app.facebook_api_version%' # Facebook Api Version\n    facebook_app_id: '%app.facebook_app_id%' # This is your facebook app id\n\n    google_client_id: '%app.google_client_id%' # This is your google client id\n \n\n    # All this information is found when you create the bucket\n    aws_api_version: '%app.aws_api_version%' \n    aws_key: '%app.aws_key%'\n    aws_secret: '%app.aws_secret%'\n    aws_region: '%app.aws_region%' \n    aws_s3_bucket_name: '%app.aws_region%'\n\n    # This client secret / client are found when u register your app with slack\n    slack_client_secret: '%app.slack_client_secret%'\n    slack_client_id: '%app.slack_client_id%'\n\n```\n\n11) Register Firewalls and Security Providers. This will be in the app -\u003e config -\u003e security.yml.\n\n\n``` \nsecurity:\n\n    encoders:\n        AppBundle\\Entity\\User:\n            algorithm: bcrypt\n            cost: 12\n\n    # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded\n    providers:\n        email:\n            id: StarterKit\\StartBundle\\Security\\Provider\\EmailProviderInterface\n        slack:\n            id: StarterKit\\StartBundle\\Security\\Provider\\SlackProviderInterface\n        token:\n            id: StarterKit\\StartBundle\\Security\\Provider\\TokenProviderInterface\n        facebook:\n            id: StarterKit\\StartBundle\\Security\\Provider\\FacebookProviderInterface\n        google:\n            id: StarterKit\\StartBundle\\Security\\Provider\\GoogleProviderInterface\n        refresh:\n            id: StarterKit\\StartBundle\\Security\\Provider\\RefreshTokenProviderInterface\n\n    role_hierarchy:\n        ROLE_ADMIN:  [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]\n\n\n    firewalls:\n        # disables authentication for assets and the profiler, adapt it according to your needs\n        dev:\n            pattern: ^/(_(profiler|wdt)|css|images|js)/\n            security: false\n\n        facebook:\n            pattern: ^/access-tokens/facebook\n            stateless: true\n            provider: facebook\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        google:\n            pattern: ^/access-tokens/google\n            stateless: true\n            provider: google\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        slack:\n            pattern: ^/oauth/slack*\n            stateless: true\n            provider: slack\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\OAuthGuardInterface\n\n        refresh:\n            pattern: ^/access-tokens/refresh\n            stateless: true\n            provider: refresh\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        login:\n            pattern: ^/login_check\n            stateless: true\n            provider: email\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\LoginGuardInterface\n\n        api:\n            pattern: ^/api*\n            anonymous: ~\n            stateless: true\n            provider: token\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\StateLess\\ApiGuardInterface\n\n        main:\n            pattern: ^/*\n            anonymous: ~\n            provider: token\n            stateless: true\n            guard:\n                authenticators:\n                    - StarterKit\\StartBundle\\Security\\Guard\\StateLess\\WebsiteGuardInterface\n\n    access_control:\n        - { path: ^/admin, roles: ROLE_ADMIN }\n\n```\n\n\n## Project Overview\n\n### Services and Interfaces\n\nEvery service has an interface that is registered as a service.  This bundle only uses interfaces in the constructor of the classes.  This means that all you have to do to over ride a service is find the interface it is implementing and register the interface as a service in the app bundle.  \n\nHere is an example.  Say you wanted to use tokens stored in the database instead of jwt / jws tokens.  All you would have to do is create a service that implemented the [AuthTokenServiceInterface](https://github.com/phptuts/StarterBundleForSymfony/blob/master/src/Service/AuthResponseServiceInterface.php) and register it in the app bundle.  \n\n#### [Service Registration](https://github.com/phptuts/starter-bundle-example/blob/database-token-example/app/config/services.yml#L38) \n\n``` \nAppBundle\\Service\\DatabaseTokenService:\n    class: AppBundle\\Service\\DatabaseTokenService\n    arguments:\n        $ttl: '%app.jws_ttl%'\n\nStarterKit\\StartBundle\\Service\\AuthTokenServiceInterface: '@AppBundle\\Service\\DatabaseTokenService'\n```\nYou can find the actual class implementation [here](https://github.com/phptuts/starter-bundle-example/blob/database-token-example/src/AppBundle/Service/DatabaseTokenService.php).\n\nHere is where services are registered for the bundle. [services.yml](https://github.com/phptuts/StarterBundleForSymfony/blob/master/Resources/config/services.yml)\n\n\n### No JMS Serializer, Symfony Serializer, FOS Rest Bundles\n\nHere are some reasons we decided not to use theses. \n\n1) Using a serializer is slower then just outputting an array\n2) Using arrays and putting them in JsonResponse is way easier to test and unit test.\n3) FOS Rest Bundle is confusing to configure and most projects will use json and not xml so you can bias your apis based on that.\n4) You can always add theses if you want, I think the authors have done an amazing job with these bundles. ;)\n\n### Stateless Authentication\n\nI feel that php sessions are confusing and vary too much from version to version of php.  It's easier to understand authentication if every request has a token / string that represents who the user is.  I believe this also helps separate concerns in the sense that client is responsible for storing the auth token and server is responsible for validating it.  \n\n\n### Ajax Login\n\nI think it's better to do ajax login and just have the request contain a cookie that the client stores for authentication.  This means that you don't have to work about getting the last username and refreshing the page.  It's also makes  the guard logic simpler because every login response will have an auth cookie and authenticated response.\n\n\n### Response Envelopes\n\nI think that every response should be wrap around envelope that describes what it how to parse it.  The response fields this project uses are meta, and data.  Meta will have a type that will clients to build parsers based on those types.\n\n``` \n{\n    \"meta\":...,\n    \"data\":...\n}\n```\n\n### Email Only Login\n\nI feel that email are the best approach to login and not username.  Mainly because they are unique for sites to be able to be merged if one site buys another.\n\n## Table of Contents\n\n- [Services](docs/services.md)\n- [Response / Serialization](docs/serialize-response.md)\n- [Forms](docs/forms.md)\n- [Security](docs/security.md)    \n- [User Entity \u0026 Traits](docs/user-entity.md)    \n    \n## How To / Examples\n\n- [How to use Auth Tokens Stored In the database](docs/examples/auth-db-tokens.md)\n- [How to add Linked In Login (OAuth Provider)](docs/examples/ad-linked-oauth.md)\n- [How to add EasyAdmin Bundle For User Management](docs/examples/easy-admin.md)\n- [How to log the user in after they have registered](docs/examples/register-login.md)\n- [How to send an email after the user registers](docs/examples/register-email.md)\n\n\n## How to run tests\n\nBe sure that sqlite is install our your system.  That is what we use for the test database.\n\n1) git clone https://github.com/phptuts/StarterBundleForSymfony.git\n\n2) cd into the directory you cloned the repo in.\n\n3) Run this in the command in the command line.\n``` \nsh run_tests.sh\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphptuts%2Fstarterbundleforsymfony","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphptuts%2Fstarterbundleforsymfony","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphptuts%2Fstarterbundleforsymfony/lists"}