8000 first commit · gistol/symfony-vuejs@2304b95 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2304b95

Browse files
author
Julien Neuhart
committed
first commit
0 parents  commit 2304b95

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+14042
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 TheCodingMachine
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Source code of the tutorial [thecodingmachine.io/building-a-single-page-application-with-symfony-4-and-vuejs](https://thecodingmachine.io/building-a-single-page-application-with-symfony-4-and-vuejs).

app/.env.dist

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# This file is a "template" of which env vars need to be defined for your application
2+
# Copy this file to .env file for development, create environment variables when deploying to production
3+
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
4+
5+
###> symfony/framework-bundle ###
6+
APP_ENV=dev
7+
APP_SECRET=8d2a5c935d8ef1c0e2b751147382bc75
8+
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
9+
#TRUSTED_HOSTS=localhos B41A t,example.com
10+
###< symfony/framework-bundle ###
11+
12+
###> doctrine/doctrine-bundle ###
13+
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
14+
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
15+
# Configure your db driver and server_version in config/packages/doctrine.yaml
16+
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
17+
###< doctrine/doctrine-bundle ###
18+
19+
###> symfony/swiftmailer-bundle ###
20+
# For Gmail as a transport, use: "gmail://username:password@localhost"
21+
# For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode="
22+
# Delivery is disabled by default via "null://localhost"
23+
MAILER_URL=null://localhost
24+
###< symfony/swiftmailer-bundle ###

app/.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
###> symfony/framework-bundle ###
3+
/.env
4+
/public/bundles/
5+
/var/
6+
/vendor/
7+
###< symfony/framework-bundle ###
8+
9+
###> symfony/phpunit-bridge ###
10+
.phpunit
11+
/phpunit.xml
12+
###< symfony/phpunit-bridge ###
13+
14+
###> symfony/web-server-bundle ###
15+
/.web-server-pid
16+
###< symfony/web-server-bundle ###
17+
18+
###> symfony/webpack-encore-pack ###
19+
/node_modules/
20+
/public/build/
21+
npm-debug.log
22+
yarn-error.log
23+
###< symfony/webpack-encore-pack ###

app/assets/.gitignore

Whitespace-only changes.

app/assets/vue/App.vue

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<template>
2+
<div class="container">
3+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
4+
<router-link class="navbar-brand" to="/home">App</router-link>
5+
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
6+
<span class="navbar-toggler-icon"></span>
7+
</button>
8+
<div class="collapse navbar-collapse" id="navbarNav">
9+
<ul class="navbar-nav">
10+
<router-link class="nav-item" tag="li" to="/home" active-class="active">
11+
<a class="nav-link">Home</a>
12+
</router-link>
13+
<router-link class="nav-item" tag="li" to="/posts" active-class="active">
14+
<a class="nav-link">Posts</a>
15+
</router-link>
16+
<li class="nav-item">
17+
<a class="nav-link" href="/api/security/logout">Logout</a>
18+
</li>
19+
</ul>
20+
</div>
21+
</nav>
22+
23+
<router-view></router-view>
24+
</div>
25+
</template>
26+
27+
<script>
28+
import axios from 'axios';
29+
import router from './router';
30+
31+
export default {
32+
name: 'app',
33+
created () {
34+
axios.interceptors.response.use(undefined, (err) => {
35+
return new Promise(() => {
36+
if (err.response.status === 403) {
37+
this.$router.push({path: '/login'})
38+
}
39+
throw err;
40+
});
41+
});
42+
},
43+
beforeMount () {
44+
let vueRouting = this.$parent.$el.attributes['data-vue-routing'].value,
45+
queryParameters = JSON.parse(this.$parent.$el.attributes['data-query-parameters'].value);
46+
47+
router.push({path: vueRouting, query: queryParameters});
48+
},
49+
}
50+
</script>

app/assets/vue/api/post.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import axios from 'axios';
2+
3+
export default {
4+
create (message) {
5+
return axios.post(
6+
'/api/post/create',
7+
{
8+
message: message,
9+
}
10+
);
11+
},
12+
getAll () {
13+
return axios.get('/api/posts');
14+
},
15+
}

app/assets/vue/api/security.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import axios from 'axios';
2+
3+
export default {
4+
login (login, password) {
5+
return axios.post(
6+
'/api/security/login',
7+
{
8+
username: login,
9+
password: password
10+
}
11+
);
12+
},
13+
isAuthenticated () {
14+
return axios.get('/api/security/is-authenticated');
15+
},
16+
}

app/assets/vue/components/Post.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<div class="card w-100 mt-2">
3+
<div class="card-body">
4+
{{ message }}
5+
</div>
6+
</div>
7+
</template>
8+
9+
<script>
10+
export default {
11+
name: 'post',
12+
props: ['message'],
13+
}
14+
</script>

app/assets/vue/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Vue from 'vue';
2+
import App from './App';
3+
import router from './router';
4+
import store from './store';
5+
6+
new Vue({
7+
template: '<App/>',
8+
components: { App },
9+
router,
10+
store,
11+
}).$mount('#app');

app/assets/vue/router/index.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Vue from 'vue';
2+
import VueRouter from 'vue-router';
3+
import store from '../store';
4+
import Home from '../views/Home';
5+
import Login from '../views/Login';
6+
import Posts from '../views/Posts';
7+
8+
Vue.use(VueRouter);
9+
10+
let router = new VueRouter({
11+
mode: 'history',
12+
routes: [
13+
{ path: '/home', component: Home },
14+
{ path: '/login', component: Login },
15+
{ path: '/posts', component: Posts, meta: { requiresAuth: true } },
16+
{ path: '*', redirect: '/home' }
17+
],
18+
});
19+
20+
router.beforeEach((to, from, next) => {
21+
if (to.matched.some(record => record.meta.requiresAuth)) {
22+
// this route requires auth, check if logged in
23+
// if not, redirect to login page.
24+
store.dispatch('security/isAuthenticated')
25+
.then(() => {
26+
next();
27+
})
28+
.catch(() => {
29+
next({
30+
path: '/login',
31+
query: { redirect: to.fullPath }
32+
});
33+
});
34+
} else {
35+
next(); // make sure to always call next()!
36+
}
37+
});
38+
39+
export default router;

app/assets/vue/store/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Vue from 'vue';
2+
import Vuex from 'vuex';
3+
import SecurityModule from './security';
4+
import PostModule from './post';
5+
6+
Vue.use(Vuex);
7+
8+
export default new Vuex.Store({
9+
modules: {
10+
security: SecurityModule,
11+
post: PostModule,
12+
},
13+
});

app/assets/vue/store/post.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import PostAPI from '../api/post';
2+
3+
export default {
4+
namespaced: true,
5+
state: {
6+
isLoading: false,
7+
error: null,
8+
posts: [],
9+
},
10+
getters: {
11+
isLoading (state) {
12+
return state.isLoading;
13+
},
14+
hasError (state) {
15+
return state.error !== null;
16+
},
17+
error (state) {
18+
return state.error;
19+
},
20+
hasPosts (state) {
21+
return state.posts.length > 0;
22+
},
23+
posts (state) {
24+
return state.posts;
25+
},
26+
},
27+
mutations: {
28+
['CREATING_POST'](state) {
29+
state.isLoading = true;
30+
state.error = null;
31+
},
32+
['CREATING_POST_SUCCESS'](state, post) {
33+
state.isLoading = false;
34+
state.error = null;
35+
state.posts.unshift(post);
36+
},
37+
['CREATING_POST_ERROR'](state, error) {
38+
state.isLoading = false;
39+
state.error = error;
40+
state.posts = [];
41+
},
42+
['FETCHING_POSTS'](state) {
43+
state.isLoading = true;
44+
state.error = null;
45+
state.posts = [];
46+
},
47+
['FETCHING_POSTS_SUCCESS'](state, posts) {
48+
state.isLoading = false;
49+
state.error = null;
50+
state.posts = posts;
51+
},
52+
['FETCHING_POSTS_ERROR'](state, error) {
53+
state.isLoading = false;
54+
state.error = error;
55+
state.posts = [];
56+
},
57+
},
58+
actions: {
59+
createPost ({commit}, message) {
60+
commit('CREATING_POST');
61+
return PostAPI.create(message)
62+
.then(res => commit('CREATING_POST_SUCCESS', res.data))
63+
.catch(err => commit('CREATING_POST_ERROR', err));
64+
},
65+
fetchPosts ({commit}) {
66+
commit('FETCHING_POSTS');
67+
return PostAPI.getAll()
68+
.then(res => commit('FETCHING_POSTS_SUCCESS', res.data))
69+
.catch(err => commit('FETCHING_POSTS_ERROR', err));
70+
},
71+
},
72+
}

app/assets/vue/store/security.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import SecurityAPI from '../api/security';
2+
3+
export default {
4+
namespaced: true,
5+
state: {
6+
isLoading: false,
7+
error: null,
8+
},
9+
getters: {
10+
isLoading (state) {
11+
return state.isLoading;
12+
},
13+
hasError (state) {
14+
return state.error !== null;
15+
},
16+
error (state) {
17+
return state.error;
18+
},
19+
},
20+
mutations: {
21+
['AUTHENTICATING'](state) {
22+
state.isLoading = true;
23+
state.error = null;
24+
},
25+
['AUTHENTICATING_SUCCESS'](state) {
26+
state.isLoading = false;
27+
state.error = null;
28+
},
29+
['AUTHENTICATING_ERROR'](state, error) {
30+
state.isLoading = false;
31+
state.error = error;
32+
},
33+
},
34+
actions: {
35+
login ({commit}, payload) {
36+
commit('AUTHENTICATING');
37+
return SecurityAPI.login(payload.login, payload.password)
38+
.then(() => commit('AUTHENTICATING_SUCCESS'))
39+
.catch(err => commit('AUTHENTICATING_ERROR', err));
40+
},
41+
isAuthenticated () {
42+
re D8A0 turn SecurityAPI.isAuthenticated();
43+
},
44+
},
45+
}

app/assets/vue/views/Home.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<template>
2+
<div>
3+
<div class="row col">
4+
<h1>Homepage</h1>
5+
</div>
6+
7+
<div class="row col">
8+
<p>This is the homepage of our Vue.js application.</p>
9+
</div>
10+
</div>
11+
</template>
12+
13+
<script>
14+
export default {
15+
name: 'home'
16+
}
17+
</script>

0 commit comments

Comments
 (0)
0