Skip to content

Commit

Permalink
code for the course
Browse files Browse the repository at this point in the history
  • Loading branch information
codereviewvideos committed Apr 23, 2016
0 parents commit 6f49035
Show file tree
Hide file tree
Showing 123 changed files with 13,305 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.idea/
/app/config/parameters.yml
/build/
/phpunit.xml
/var/*
!/var/cache
/var/cache/*
!var/cache/.gitkeep
!/var/logs
/var/logs/*
!var/logs/.gitkeep
!/var/sessions
/var/sessions/*
!var/sessions/.gitkeep
!var/SymfonyRequirements.php
/vendor/
/web/bundles/
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Symfony 3 RESTful API Example
=============================

This is the code for the [Symfony 3 REST Tutorial][1] at CodeReviewVideos.com.

## About The Course

In this series we are going to take most of what has been taught on CodeReviewVideos so far, and use it to implement the foundation of a Symfony-based RESTful API.

This is not a good starting point if you have never used Symfony before. If you are a beginner, please try the [Symfony Tutorial for Beginners][2] before attempting to create a RESTful API.

Whilst very new, we are going to proceed with Symfony 3 for this project. However, if you are still using Symfony 2, you should have no trouble following along. If anything, your life may be that little bit easier ;)

By the end of this series you will have created a RESTful API with FOSRESTBundle, guided by tests using Behat 3 and PHPSpec 2. The API itself will exposes Users - via FOSUserBundle - along with Accounts, and File Uploading using Flysystem.

You will have gained an understanding into how to add further 'modules' to your API, allowing you to create custom end points to meet the needs of your specific application.

As with many things Symfony, there are multiple ways to achieve the goals in this series. We could switch out FOSRESTBundle for DunglasAPIBundle. We could switch Flysystem for Guafrette. You are entirely free to do so.

This API is going to be based on FOSRESTBundle. The main reasoning for this is that I have already covered this bundle in another dedicated tutorial series, so if you get stuck, there are plenty of lessons explaining the general setup.

You may be wondering about the difference between a User and an Account. The idea here is that every User would have their own User Profile, but may belong to one of more Accounts. This is pretty helpful in the real world, and opens up options for your app as it grows. Feel free to rip this part out if you don't need it.

Log in is going to be a little different here. When a User POST's in a valid username and password combo, they will receive a JSON Web Token / JWT (pronounced Jot), which they will then need to use as part of any future request. Don't worry, we will cover this in full, and you will see it's really not that difficult at all. The reasoning for doing this is that our front end will thank us for it.

To ensure stability, we will be using VirtualBox with an Ansible build script. This will - hopefully - mean getting from development to production is largely taken care of.

Lastly, we will cover how to interact with this API using ReactJS. You could switch this out for Angular, Ember, a mobile Application (e.g. Ionic, or a native app), or any other front end framework. That choice is entirely up to you. I am by far and away not the world's best JavaScript guy, so take this section as an example, rather than a defacto standard.

Hopefully you will find this exercise useful and practical. Please feel free to leave comments, ask questions, or get in touch if you would like to know more about a specific topic.



[1]: https://www.codereviewvideos.com/course/symfony-3-rest-tutorial
[2]: https://www.codereviewvideos.com/course/beginner-friendly-hands-on-symfony-3-tutorial
7 changes: 7 additions & 0 deletions app/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
7 changes: 7 additions & 0 deletions app/AppCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;

class AppCache extends HttpCache
{
}
60 changes: 60 additions & 0 deletions app/AppKernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
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 Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),

new FOS\RestBundle\FOSRestBundle(),
new Nelmio\CorsBundle\NelmioCorsBundle(),
new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
new FOS\UserBundle\FOSUserBundle(),
new Csa\Bundle\GuzzleBundle\CsaGuzzleBundle(),
new Oneup\FlysystemBundle\OneupFlysystemBundle(),
new Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle(),

new AppBundle\AppBundle(),
];

if (in_array($this->getEnvironment(), ['dev', 'test', 'acceptance'], true)) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
}

return $bundles;
}

public function getRootDir()
{
return __DIR__;
}

public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
}

public function getLogDir()
{
return dirname(__DIR__).'/var/logs';
}

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
}
}
13 changes: 13 additions & 0 deletions app/Resources/views/base.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
76 changes: 76 additions & 0 deletions app/Resources/views/default/index.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{% extends 'base.html.twig' %}

{% block body %}
<div id="wrapper">
<div id="container">
<div id="welcome">
<h1><span>Welcome to</span> Symfony {{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}</h1>
</div>

<div id="status">
<p>
<svg id="icon-status" width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http:https://www.w3.org/2000/svg"><path d="M1671 566q0 40-28 68l-724 724-136 136q-28 28-68 28t-68-28l-136-136-362-362q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 295 656-657q28-28 68-28t68 28l136 136q28 28 28 68z" fill="#759E1A"/></svg>

Your application is ready to start working on it at:
<code>{{ base_dir }}/</code>
</p>
</div>

<div id="next">
<h2>What's next?</h2>
<p>
<svg id="icon-book" version="1.1" xmlns="http:https://www.w3.org/2000/svg" x="0px" y="0px" viewBox="-12.5 9 64 64" enable-background="new -12.5 9 64 64" xml:space="preserve">
<path fill="#AAA" d="M6.8,40.8c2.4,0.8,4.5-0.7,4.9-2.5c0.2-1.2-0.3-2.1-1.3-3.2l-0.8-0.8c-0.4-0.5-0.6-1.3-0.2-1.9
c0.4-0.5,0.9-0.8,1.8-0.5c1.3,0.4,1.9,1.3,2.9,2.2c-0.4,1.4-0.7,2.9-0.9,4.2l-0.2,1c-0.7,4-1.3,6.2-2.7,7.5
c-0.3,0.3-0.7,0.5-1.3,0.6c-0.3,0-0.4-0.3-0.4-0.3c0-0.3,0.2-0.3,0.3-0.4c0.2-0.1,0.5-0.3,0.4-0.8c0-0.7-0.6-1.3-1.3-1.3
c-0.6,0-1.4,0.6-1.4,1.7s1,1.9,2.4,1.8c0.8,0,2.5-0.3,4.2-2.5c2-2.5,2.5-5.4,2.9-7.4l0.5-2.8c0.3,0,0.5,0.1,0.8,0.1
c2.4,0.1,3.7-1.3,3.7-2.3c0-0.6-0.3-1.2-0.9-1.2c-0.4,0-0.8,0.3-1,0.8c-0.1,0.6,0.8,1.1,0.1,1.5c-0.5,0.3-1.4,0.6-2.7,0.4l0.3-1.3
c0.5-2.6,1-5.7,3.2-5.8c0.2,0,0.8,0,0.8,0.4c0,0.2,0,0.2-0.2,0.5c-0.2,0.3-0.3,0.4-0.2,0.7c0,0.7,0.5,1.1,1.2,1.1
c0.9,0,1.2-1,1.2-1.4c0-1.2-1.2-1.8-2.6-1.8c-1.5,0.1-2.8,0.9-3.7,2.1c-1.1,1.3-1.8,2.9-2.3,4.5c-0.9-0.8-1.6-1.8-3.1-2.3
c-1.1-0.7-2.3-0.5-3.4,0.3c-0.5,0.4-0.8,1-1,1.6c-0.4,1.5,0.4,2.9,0.8,3.4l0.9,1c0.2,0.2,0.6,0.8,0.4,1.5c-0.3,0.8-1.2,1.3-2.1,1
c-0.4-0.2-1-0.5-0.9-0.9c0.1-0.2,0.2-0.3,0.3-0.5s0.1-0.3,0.1-0.3c0.2-0.6-0.1-1.4-0.7-1.6c-0.6-0.2-1.2,0-1.3,0.8
C4.3,38.4,4.7,40,6.8,40.8z M46.1,20.9c0-4.2-3.2-7.5-7.1-7.5h-3.8C34.8,10.8,32.7,9,30.2,9L-2.3,9.1c-2.8,0.1-4.9,2.4-4.9,5.4
L-7,58.6c0,4.8,8.1,13.9,11.6,14.1l34.7-0.1c3.9,0,7-3.4,7-7.6L46.1,20.9z M-0.3,36.4c0-8.6,6.5-15.6,14.5-15.6
c8,0,14.5,7,14.5,15.6S22.1,52,14.2,52C6.1,52-0.3,45-0.3,36.4z M42.1,65.1c0,1.8-1.5,3.1-3.1,3.1H4.6c-0.7,0-3-1.8-4.5-4.4h30.4
c2.8,0,5-2.4,5-5.4V17.9h3.7c1.6,0,2.9,1.4,2.9,3.1V65.1L42.1,65.1z"/>
</svg>

Read Symfony documentation to learn
<a href="http:https://symfony.com/doc/{{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION')[:3] }}/book/page_creation.html">
How to create your first page in Symfony
</a>
</p>
</div>

</div>
</div>
{% endblock %}

{% block stylesheets %}
<style>
body { background: #F5F5F5; font: 18px/1.5 sans-serif; }
h1, h2 { line-height: 1.2; margin: 0 0 .5em; }
h1 { font-size: 36px; }
h2 { font-size: 21px; margin-bottom: 1em; }
p { margin: 0 0 1em 0; }
a { color: #0000F0; }
a:hover { text-decoration: none; }
code { background: #F5F5F5; max-width: 100px; padding: 2px 6px; word-wrap: break-word; }
#wrapper { background: #FFF; margin: 1em auto; max-width: 800px; width: 95%; }
#container { padding: 2em; }
#welcome, #status { margin-bottom: 2em; }
#welcome h1 span { display: block; font-size: 75%; }
#icon-status, #icon-book { float: left; height: 64px; margin-right: 1em; margin-top: -4px; width: 64px; }
#icon-book { display: none; }
@media (min-width: 768px) {
#wrapper { width: 80%; margin: 2em auto; }
#icon-book { display: inline-block; }
#status a, #next a { display: block; }
@-webkit-keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
@keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
.sf-toolbar { opacity: 0; -webkit-animation: fade-in 1s .2s forwards; animation: fade-in 1s .2s forwards;}
}
</style>
{% endblock %}
13 changes: 13 additions & 0 deletions app/autoload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

use Doctrine\Common\Annotations\AnnotationRegistry;
use Composer\Autoload\ClassLoader;

/**
* @var ClassLoader $loader
*/
$loader = require __DIR__.'/../vendor/autoload.php';

AnnotationRegistry::registerLoader([$loader, 'loadClass']);

return $loader;
Loading

0 comments on commit 6f49035

Please sign in to comment.