Last active
November 19, 2015 16:22
-
-
Save manchuck/5326ffe164ceddfd8a02 to your computer and use it in GitHub Desktop.
PHPWorld SPA with Angular and Apigility
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "php_world_spa", | |
"main": "dist/ads-admin/index.html", | |
"keywords": [], | |
"license": "MIT", | |
"private": true, | |
"ignore": [ | |
"**/.*", | |
"dist", | |
"node_modules", | |
"bower_components", | |
"vendor", | |
"test", | |
"tests" | |
], | |
"dependencies": { | |
"angular": "1.2.10", | |
"angular-route": "~1.2", | |
"angular-ui-bootstrap-bower": "~0.10", | |
"angular-ui-router": "0.2.8-bowratic-tedium", | |
"angular-resource": "~1.2", | |
"bootstrap": "~3.1", | |
"jquery": "~2.0", | |
"lodash": "~2.4", | |
"ng-tags-input": "~1.1", | |
"angular-loading-bar": "~0.4", | |
"restangular": "~1.5", | |
"angularjs-gravatardirective": "~1.3", | |
"fuelux": "~3.5" | |
}, | |
"devDependencies": { | |
"angular-mocks": "1.2.10", | |
"angular-scenario": "1.2.10" | |
}, | |
"resolutions": { | |
"angular": "1.2.10" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"require": { | |
"php": ">=5.4", | |
"zfcampus/zf-apigility": "~1.0", | |
"zfcampus/zf-apigility-documentation": "^1.0.5", | |
"zendframework/zendframework": "~2.5" | |
}, | |
"require-dev": { | |
"zendframework/zftool": "dev-master", | |
"zendframework/zend-developer-tools": "dev-master", | |
"zfcampus/zf-apigility-admin": "~1.0", | |
"zfcampus/zf-deploy": "~1.0", | |
"zfcampus/zf-development-mode": "~2.0" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('ads-admin') | |
.config(['$stateProvider', | |
function ($stateProvider) { | |
$stateProvider.state('ads.product', { | |
url: '/product', | |
abstract: true | |
}); | |
$stateProvider.state('ads.product.list', { | |
url: '/list', | |
data: { | |
page_title: 'Products', | |
breadcrumbs: ['Products'] | |
}, | |
views: { | |
'content@': { | |
templateUrl: 'html/product/list.html', | |
controller: 'ProductListController' | |
} | |
} | |
}); | |
$stateProvider.state('ads.product.create', { | |
url: '/add', | |
data: { | |
page_title: 'Product', | |
breadcrumbs: ['Product', 'Create'] | |
}, | |
views: { | |
'content@': { | |
templateUrl: 'html/product/form.html', | |
controller: 'ProductFormController' | |
} | |
} | |
}); | |
$stateProvider.state('ads.product.edit', { | |
url: '/edit/:product_id', | |
data: { | |
page_title: 'Product', | |
breadcrumbs: ['Product', 'Edit'] | |
}, | |
views: { | |
'content@': { | |
templateUrl: 'html/product/form.html', | |
controller: 'ProductFormController' | |
} | |
} | |
}); | |
$stateProvider.state('ads.product.view', { | |
url: '/view/:product_id', | |
data: { | |
page_title: 'Product', | |
breadcrumbs: ['Product', 'View'] | |
}, | |
views: { | |
'content@': { | |
templateUrl: 'html/product/view.html', | |
controller: 'ProductViewController' | |
} | |
} | |
}); | |
}]) | |
.controller('ProductListController', ['$scope', '$rootScope', 'Restangular', '$log', 'activeAccount', | |
function ($scope, $rootScope, Restangular, $log) { | |
var product_api = Restangular.all('product'); | |
$scope.page = 1; | |
$scope.per_page = 50; | |
$scope.loading = true; | |
$scope.total_products = 0; | |
$scope.fetchProducts = function () { | |
var query = { | |
'search' : $scope.search, | |
'per_page' : $scope.per_page, | |
'page' : $scope.page | |
}; | |
$scope.loading = true; | |
product_api.getList(query) | |
.then(function (products) { | |
$scope.loading = false; | |
if (products.meta) { | |
var links = products.meta._links; | |
$scope.total_products = products.meta.total_items || 0; | |
} | |
$scope.products = products; | |
}, function (response) { | |
$scope.loading = false; | |
var error_message = response.data.detail || 'Unable to fetch products'; | |
$log.error(error_message); | |
$.smallBox({ | |
title : 'Error!', | |
content : 'Unable to load products', | |
color : '#C46A69', | |
icon : 'fa fa-warning shake animated', | |
timeout : 6000 | |
}); | |
} | |
); | |
}; | |
}]) | |
.controller('ProductViewController', ['$scope', 'Restangular', '$log', '$stateParams', '$rootScope', '$state', '$filter', 'dateArray', | |
function ($scope, Restangular, $log, $stateParams, $rootScope, $state, $filter, dateArray) { | |
var product_api = Restangular.all('product'); | |
$scope.page = 1; | |
$scope.per_page = 50; | |
$scope.loading = true; | |
$scope.total_products = 0; | |
$scope.product_id = false; | |
$scope.errors = []; | |
var saveProductSuccess = function (response) { | |
$scope.saving = false; | |
$.smallBox({ | |
title : 'Success!', | |
content : response.detail || 'Product saved', | |
color : '#739E73', | |
icon : 'fa fa-check animated', | |
timeout : 6000 | |
}); | |
$state.go('ads.product.list'); | |
}; | |
var saveProductError = function (response) { | |
$scope.saving = false; | |
var error_message = response.data.detail || 'Unable to save product'; | |
$log.error(error_message); | |
$.smallBox({ | |
title : 'Error!', | |
content : 'Unable to save product', | |
color : '#C46A69', | |
icon : 'fa fa-warning shake animated', | |
timeout : 6000 | |
}); | |
$scope.errors = response.data.validation_messages || {}; | |
}; | |
$scope.fetchProduct = function () { | |
if ($scope.product_id === false) { | |
return; | |
} | |
$scope.loading = true; | |
product_api.get($scope.product_id).then( | |
function (result) { | |
$scope.loading = false; | |
$scope.product = result; | |
}, | |
function () { | |
$scope.loading = false; | |
$.smallBox({ | |
title : 'Error!', | |
content : 'Unable to load product doesnt exist', | |
color : '#C46A69', | |
icon : 'fa fa-warning shake animated', | |
timeout : 6000 | |
}); | |
$state.go('ads.product.list'); | |
} | |
); | |
}; | |
$scope.saveProduct = function() { | |
$scope.saving = true; | |
if ($scope.product_id === false) { | |
product_api.post($scope.product).then(saveProductSuccess, saveProductError); | |
return; | |
} | |
product_api.put().then(saveProductSuccess, saveProductError); | |
}; | |
} | |
]) | |
.controller('ProductFormController', ['$scope', '$rootScope', 'Restangular', '$log', 'adsSettings', '$stateParams', '$state', | |
function ($scope, $rootScope, Restangular, $log, adsSettings, $stateParams, $state) { | |
var product_api = Restangular.all('product'); | |
$scope.page = 1; | |
$scope.per_page = 50; | |
$scope.loading = true; | |
$scope.total_products = 0; | |
$scope.product_id = false; | |
$scope.errors = []; | |
var saveProductSuccess = function (response) { | |
$scope.saving = false; | |
$.smallBox({ | |
title : 'Success!', | |
content : response.detail || 'Product saved', | |
color : '#739E73', | |
icon : 'fa fa-check animated', | |
timeout : 6000 | |
}); | |
$state.go('ads.product.list'); | |
}; | |
var saveProductError = function (response) { | |
$scope.saving = false; | |
var error_message = response.data.detail || 'Unable to save product'; | |
$log.error(error_message); | |
$.smallBox({ | |
title : 'Error!', | |
content : 'Unable to save product', | |
color : '#C46A69', | |
icon : 'fa fa-warning shake animated', | |
timeout : 6000 | |
}); | |
$scope.errors = response.data.validation_messages || {}; | |
}; | |
$scope.fetchProduct = function () { | |
if ($scope.product_id === false) { | |
return; | |
} | |
$scope.loading = true; | |
product_api.get($scope.product_id).then( | |
function (result) { | |
$scope.loading = false; | |
$scope.product = result; | |
}, | |
function () { | |
$scope.loading = false; | |
$.smallBox({ | |
title : 'Error!', | |
content : 'Unable to load product doesnt exist', | |
color : '#C46A69', | |
icon : 'fa fa-warning shake animated', | |
timeout : 6000 | |
}); | |
$state.go('ads.product.list'); | |
} | |
); | |
}; | |
$scope.saveProduct = function() { | |
$scope.saving = true; | |
if ($scope.product_id === false) { | |
product_api.post($scope.product).then(saveProductSuccess, saveProductError); | |
return; | |
} | |
product_api.put().then(saveProductSuccess, saveProductError); | |
}; | |
} | |
]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated on 2013-12-20 using generator-angular 0.6.0 | |
'use strict'; | |
// # Globbing | |
// for performance reasons we're only matching one level down: | |
// 'test/spec/{,**/}*.js' | |
// use this if you want to recursively match all subfolders: | |
// 'test/spec/**/*.js' | |
module.exports = function(grunt) { | |
// Load grunt tasks automatically | |
require('load-grunt-tasks')(grunt); | |
// Time how long tasks take. Can help when optimizing build times | |
require('time-grunt')(grunt); | |
// Define the configuration for all the tasks | |
grunt.initConfig({ | |
// Project settings | |
yeoman: { | |
app: 'src/ads-admin', | |
dist: 'dist/ads-admin' | |
}, | |
// Watches files for changes and runs tasks based on the changed files | |
watch: { | |
js: { | |
files: ['<%= yeoman.app %>/js/{,**/}*.js'], | |
tasks: ['newer:jshint:all', 'concat:dist'] | |
}, | |
jsTest: { | |
files: ['test/spec/{,**/}*.js'], | |
tasks: ['newer:jshint:test', 'karma'] | |
}, | |
gruntfile: { | |
files: ['Gruntfile.js'] | |
}, | |
livereload: { | |
options: { | |
livereload: true | |
}, | |
files: [ | |
'<%= yeoman.app %>/{,**/}*.html', | |
'<%= yeoman.app %>/css/{,**/}*.css' | |
] | |
}, | |
html2js: { | |
files: ['<%= yeoman.app %>/html/{,**/}*.html'], | |
tasks: ['html2js', 'concat:dist'] | |
} | |
}, | |
// Make sure code styles are up to par and there are no obvious mistakes | |
jshint: { | |
options: { | |
jshintrc: '.jshintrc', | |
reporter: require('jshint-stylish'), | |
ignores: ['<%= yeoman.app %>/js/templates.js'] | |
}, | |
all: [ | |
'Gruntfile.js', | |
'<%= yeoman.app %>/js/{,**/}*.js' | |
], | |
test: { | |
options: { | |
jshintrc: 'test/.jshintrc' | |
}, | |
src: ['test/spec/{,**/}*.js'] | |
} | |
}, | |
// Empties folders to start fresh | |
clean: { | |
dist: { | |
files: [{ | |
dot: true, | |
src: [ | |
'.tmp', | |
'<%= yeoman.dist %>/*', | |
'!<%= yeoman.dist %>/.git*' | |
] | |
}] | |
}, | |
server: '.tmp' | |
}, | |
// Reads HTML for usemin blocks to enable smart builds that automatically | |
// concat, minify and revision files. Creates configurations in memory so | |
// additional tasks can operate on them | |
useminPrepare: { | |
html: '<%= yeoman.app %>/index.html', | |
options: { | |
dest: '<%= yeoman.dist %>' | |
} | |
}, | |
// Performs rewrites based on rev and the useminPrepare configuration | |
usemin: { | |
html: ['<%= yeoman.dist %>/{,**/}*.html'], | |
css: ['<%= yeoman.dist %>/css/{,**/}*.css'], | |
options: { | |
assetsDirs: ['<%= yeoman.dist %>'] | |
} | |
}, | |
htmlmin: { | |
dist: { | |
options: { | |
// Optional configurations that you can uncomment to use | |
// removeCommentsFromCDATA: true, | |
// collapseBooleanAttributes: true, | |
// removeAttributeQuotes: true, | |
removeRedundantAttributes: true, | |
// useShortDoctype: true, | |
removeEmptyAttributes: true | |
// removeOptionalTags: true*/ | |
}, | |
files: [{ | |
expand: true, | |
cwd: '<%= yeoman.app %>', | |
src: ['*.html', 'html/**/*.html'], | |
dest: '<%= yeoman.dist %>' | |
}] | |
} | |
}, | |
// Allow the use of non-minsafe AngularJS files. Automatically makes it | |
// minsafe compatible so Uglify does not destroy the ng references | |
ngmin: { | |
dist: { | |
files: [{ | |
expand: true, | |
cwd: '.tmp/concat/js', | |
src: '*.js', | |
dest: '.tmp/concat/js' | |
}] | |
} | |
}, | |
concat: { | |
dist: { | |
options: { | |
// Replace all 'use strict' statements in the code with a single one at the top | |
banner: '\'use strict\';\n', | |
process: function(src, filepath) { | |
return '// Source: ' + filepath + '\n' + | |
src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1'); | |
} | |
}, | |
src: ['<%= yeoman.app %>/js/{,**/}*.js'], | |
dest: '<%= yeoman.dist %>/js/app.js' | |
} | |
}, | |
// Copies remaining files to places other tasks can use | |
copy: { | |
dist: { | |
files: [{ | |
expand: true, | |
dot: true, | |
cwd: '<%= yeoman.app %>', | |
dest: '<%= yeoman.dist %>', | |
src: [ | |
'*.{ico,png,txt}', | |
'.htaccess', | |
'img/{,**/}*.webp', | |
'img/{,**/}*.gif', | |
'img/{,**/}*.png', | |
'img/favicon.ico', | |
'fonts/*', | |
'sound/*', | |
'js/data/**/*.json', | |
'ui/*' | |
] | |
}, { | |
expand: true, | |
dot: false, | |
cwd: '<%= yeoman.app %>/vendor/font-awesome/fonts', | |
dest: '<%= yeoman.dist %>/fonts/', | |
src: [ | |
'*' | |
] | |
}] | |
}, | |
template: { | |
files: [{ | |
expand: true, | |
dot: true, | |
cwd: '<%= yeoman.app %>', | |
dest: '<%= yeoman.dist %>', | |
src: ['js/templates.js'] | |
}] | |
} | |
}, | |
// Run some tasks in parallel to speed up the build process | |
concurrent: { | |
server: [ | |
], | |
test: [ | |
], | |
dist: [ | |
'htmlmin' | |
] | |
}, | |
// Test settings | |
karma: { | |
unit: { | |
configFile: 'karma.conf.js', | |
singleRun: true | |
} | |
}, | |
//Collect all html views into single template | |
html2js: { | |
options: { | |
base: '<%= yeoman.app %>' | |
}, | |
main: { | |
src: ['<%= yeoman.app %>/html/**/*.html'], | |
dest: '<%= yeoman.app %>/js/templates.js' | |
} | |
} | |
}); | |
grunt.registerTask('monkeyPatches', function () { | |
// monkeypatch FileProcessor to include utf-8 | |
var FileProcessor = require('grunt-usemin/lib/fileprocessor'); | |
FileProcessor.prototype.replaceWithOld = FileProcessor.prototype.replaceWith; | |
FileProcessor.prototype.replaceWith = function replaceWith(block) { | |
var script = FileProcessor.prototype.replaceWithOld(block); | |
if (script.match(/<script src/)) { | |
script = script.replace('></script>', ' charset="utf-8"></script>'); | |
} | |
return script; | |
}; | |
}); | |
grunt.registerTask('serve', function(target) { | |
grunt.task.run([ | |
'clean:server', | |
'concurrent:server', | |
'watch' | |
]); | |
}); | |
grunt.registerTask('test', [ | |
'clean:server', | |
'concurrent:test', | |
'karma' | |
]); | |
grunt.registerTask('build', [ | |
'clean:dist', | |
'html2js', | |
'useminPrepare', | |
'concurrent:dist', | |
'concat', | |
'ngmin', | |
'copy:dist', | |
'cssmin', | |
'uglify', | |
'monkeyPatches', | |
'usemin' | |
]); | |
grunt.registerTask('default', [ | |
'newer:jshint', | |
'test', | |
'build' | |
]); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
'use strict'; | |
angular.module('ads-admin', [ | |
'ui.bootstrap', | |
'ui.router', | |
'restangular', | |
'templates-main', | |
]) | |
.config( | |
['RestangularProvider', | |
function($provide, $stateProvider, $urlRouterProvider, RestangularProvider, cfpLoadingBarProvider) { | |
// this will Restangularize Apigility responses | |
// @see https://github.com/mgonto/restangular#my-response-is-actually-wrapped-with-some-metadata-how-do-i-get-the-data-in-that-case | |
RestangularProvider.addResponseInterceptor( | |
function (data, operation, what) { | |
var extractedData = data; | |
if (operation == 'getList') { | |
extractedData = data._embedded[what] || []; | |
extractedData.meta = { | |
_links: data._links || {}, | |
page_count: data.page_count || 0, | |
page_size: data.page_size || 0, | |
total_items: data.total_items || 0 | |
}; | |
} | |
return extractedData; | |
} | |
); | |
// Restangular will send a body on remove. Apigility doesn't like that so remove the body | |
RestangularProvider.addRequestInterceptor( | |
function (element, operation) { | |
if (operation === 'remove') { | |
return null; | |
} | |
return element; | |
} | |
); | |
RestangularProvider.setRestangularFields({ | |
selfLink: '_links.self.href', | |
cache: true | |
}); | |
}] | |
); | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "php_world_spa", | |
"type": "library", | |
"version": "1.5.0-beta", | |
"author": "", | |
"contributors": [], | |
"license": "MIT", | |
"main": "Gruntfile.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"dependencies": {}, | |
"devDependencies": { | |
"grunt": "~0.4.1", | |
"grunt-autoprefixer": "~0.4.0", | |
"grunt-concurrent": "~0.4.1", | |
"grunt-contrib-clean": "~0.5.0", | |
"grunt-contrib-less": "~0.9.0", | |
"grunt-contrib-concat": "~0.3.0", | |
"grunt-contrib-connect": "~0.5.0", | |
"grunt-contrib-copy": "~0.4.1", | |
"grunt-contrib-cssmin": "~0.7.0", | |
"grunt-contrib-htmlmin": "~0.1.3", | |
"grunt-contrib-jshint": "~0.7.1", | |
"grunt-contrib-uglify": "~0.2.0", | |
"grunt-contrib-watch": "~0.5.2", | |
"grunt-newer": "~0.5.4", | |
"grunt-ngmin": "~0.0.2", | |
"grunt-usemin": "~2.0.0", | |
"jshint-stylish": "~0.1.3", | |
"load-grunt-tasks": "~0.2.0", | |
"time-grunt": "~0.2.1", | |
"grunt-html2js": "^0.2.4" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment