Migrate to ember 2.7 + correct jquery null context error + declare shim for popcorn (instead of silencing the JSHint error)
authorymh <ymh.work@gmail.com>
Sat, 06 Aug 2016 21:29:33 +0700
changeset 261 02e2396bcbbc
parent 260 64caee7ce38d
child 262 e999bcaa0c08
Migrate to ember 2.7 + correct jquery null context error + declare shim for popcorn (instead of silencing the JSHint error)
cms/app-client/.jshintrc
cms/app-client/.travis.yml
cms/app-client/app/adapters/application.js
cms/app-client/app/components/discourses-component.js
cms/app-client/app/components/filtering-component.js
cms/app-client/app/components/player-component.js
cms/app-client/app/components/visu-langues.js
cms/app-client/app/index.html
cms/app-client/app/router.js
cms/app-client/bower.json
cms/app-client/config/environment.js
cms/app-client/ember-cli-build.js
cms/app-client/mirage/config.js
cms/app-client/package.json
cms/app-client/tests/.jshintrc
cms/app-client/tests/helpers/destroy-app.js
cms/app-client/tests/index.html
cms/app-client/vendor/shims/popcorn.js
common/corpus-common-addon/addon/services/resolver-service.js
common/corpus-common-addon/tests/dummy/app/router.js
common/corpus-common-addon/tests/dummy/config/environment.js
server/src/app/Libraries/Utils.php
server/src/app/Repositories/RdfDocumentRepository.php
server/src/tests/Libraries/UtilsTest.php
--- a/cms/app-client/.jshintrc	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/.jshintrc	Sat Aug 06 21:29:33 2016 +0700
@@ -1,33 +1,32 @@
 {
-    "predef": [
-        "Popcorn",
-        "server",
-        "document",
-        "window",
-        "-Promise"
-    ],
-    "browser": true,
-    "boss": true,
-    "curly": true,
-    "debug": false,
-    "devel": true,
-    "eqeqeq": true,
-    "evil": true,
-    "forin": false,
-    "immed": false,
-    "laxbreak": false,
-    "noarg": true,
-    "noempty": false,
-    "nonew": false,
-    "nomen": false,
-    "onevar": false,
-    "plusplus": false,
-    "regexp": false,
-    "undef": true,
-    "sub": true,
-    "strict": false,
-    "white": false,
-    "eqnull": true,
-    "esnext": true,
-    "unused": true
+  "predef": [
+    "document",
+    "window",
+    "-Promise"
+  ],
+  "browser": true,
+  "boss": true,
+  "curly": true,
+  "debug": false,
+  "devel": true,
+  "eqeqeq": true,
+  "evil": true,
+  "forin": false,
+  "immed": false,
+  "laxbreak": false,
+  "newcap": true,
+  "noarg": true,
+  "noempty": false,
+  "nonew": false,
+  "nomen": false,
+  "onevar": false,
+  "plusplus": false,
+  "regexp": false,
+  "undef": true,
+  "sub": true,
+  "strict": false,
+  "white": false,
+  "eqnull": true,
+  "esversion": 6,
+  "unused": true
 }
--- a/cms/app-client/.travis.yml	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/.travis.yml	Sat Aug 06 21:29:33 2016 +0700
@@ -12,7 +12,9 @@
 before_install:
   - npm config set spin false
   - npm install -g bower
+  - bower --version
   - npm install phantomjs-prebuilt
+  - phantomjs --version
 
 install:
   - npm install
--- a/cms/app-client/app/adapters/application.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/adapters/application.js	Sat Aug 06 21:29:33 2016 +0700
@@ -3,7 +3,7 @@
 
 export default RESTAdapter.extend({
 
-    namespace: ENV.baseURL.replace(/\/$/,"")+'/api/v1',
+    namespace: ENV.rootURL.replace(/\/$/,"")+'/api/v1',
 
     buildURL: function(modelName, id) {
         if(modelName === 'transcript') {
@@ -19,4 +19,4 @@
         return this._super(...arguments);
     }
 
-});
\ No newline at end of file
+});
--- a/cms/app-client/app/components/discourses-component.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/components/discourses-component.js	Sat Aug 06 21:29:33 2016 +0700
@@ -13,8 +13,8 @@
 
     didRender: function() {
         var self = this;
-        var baseURL = env.baseURL.replace(/\/$/,"")+'/api/v1';
-        
+        var baseURL = env.rootURL.replace(/\/$/,"")+'/api/v1';
+
         d3.json(baseURL + "/discourses", function(discourses) {
             var width = self.$().parent().width();
             var height = self.$().parent().height() - self.$().siblings().height();
@@ -66,7 +66,7 @@
                 .on('click', function(d) {
                     self.get('filter').set('discourse', d.id);
                 });
-            
+
             leaf.append("circle")
                 .attr("r", function(d) { return Math.max(7.5 + d.r * 2, d.r * 2); })
                 .attr("fill", function(d) { return d.fill; })
@@ -100,5 +100,5 @@
 
         return nodes;
     }
-    
+
 });
--- a/cms/app-client/app/components/filtering-component.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/components/filtering-component.js	Sat Aug 06 21:29:33 2016 +0700
@@ -19,7 +19,7 @@
     },
 
     elementFocusOut: function(event) {
-        if(!Ember.$.contains(this.get('element'), event.target)) {
+        if(this.get('element') && !Ember.$.contains(this.get('element'), event.target)) {
             this.set('isDropdownOpen', false);
         }
     },
--- a/cms/app-client/app/components/player-component.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/components/player-component.js	Sat Aug 06 21:29:33 2016 +0700
@@ -1,4 +1,5 @@
 import Ember from 'ember';
+import Popcorn from 'popcorn';
 
 export default Ember.Component.extend({
     classNames: ['player-component'],
--- a/cms/app-client/app/components/visu-langues.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/components/visu-langues.js	Sat Aug 06 21:29:33 2016 +0700
@@ -52,7 +52,7 @@
             .attr("y", 6 - margin.top)
             .attr("dy", ".75em");
 
-        var baseurl = ENV.baseURL.replace(/\/$/,"")+'/api/v1';
+        var baseurl = ENV.rootURL.replace(/\/$/,"")+'/api/v1';
         d3.json(baseurl+"/languages", function(languages) {
 
             var root = _.cloneDeep(self.constants.LANGUAGES_TREEMAP);
@@ -145,7 +145,7 @@
                     if (transitioning || !d) {
                         return;
                     }
-                    
+
                     selectHandler(d);
                     transitioning = true;
 
--- a/cms/app-client/app/index.html	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/index.html	Sat Aug 06 21:29:33 2016 +0700
@@ -10,9 +10,9 @@
 
         {{content-for "head"}}
 
-        <link rel="stylesheet" href="styles.css">
-        <link rel="stylesheet" href="assets/vendor.css">
-        <link rel="stylesheet" href="assets/app-client.css">
+        <link rel="stylesheet" href="{{rootURL}}styles.css">
+        <link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
+        <link rel="stylesheet" href="{{rootURL}}assets/app-client.css">
 
         {{content-for "head-footer"}}
     </head>
@@ -34,9 +34,9 @@
 
         <div id="corpus-app" class="corpus-app"></div>
 
-        <script src="assets/vendor.js"></script>
-        <script src="assets/app-client.js"></script>
-        <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
+        <script src="{{rootURL}}assets/vendor.js"></script>
+        <script src="{{rootURL}}assets/app-client.js"></script>
+        <!--script src="//code.jquery.com/jquery-1.11.3.min.js"></script-->
         <script>
             $(".menu_main .sub-menu").click(function(item, bla){
                 $(".menu_main .sub-menu").toggleClass("active", false);
--- a/cms/app-client/app/router.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/app/router.js	Sat Aug 06 21:29:33 2016 +0700
@@ -2,7 +2,8 @@
 import config from './config/environment';
 
 const Router = Ember.Router.extend({
-  location: config.locationType
+    location: config.locationType,
+    rootURL: config.rootURL
 });
 
 Router.map(function() {
--- a/cms/app-client/bower.json	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/bower.json	Sat Aug 06 21:29:33 2016 +0700
@@ -1,9 +1,8 @@
 {
   "name": "app-client",
   "dependencies": {
-    "ember": "~2.6.0-beta.2",
+    "ember": "~2.7.0",
     "ember-cli-shims": "0.1.1",
-    "ember-cli-test-loader": "0.2.2",
     "ember-qunit-notifications": "0.1.0",
     "jquery": "^2.2",
     "qunit": "~1.18.0",
@@ -14,6 +13,7 @@
     "lodash": "~4.11.1",
     "Faker": "~3.1.0",
     "store": "https://github.com/marcuswestin/store.js.git#v1.3.20",
-    "popcorn-js": "popcornjs#^1.5.11"
+    "popcorn-js": "popcornjs#^1.5.11",
+    "ember-qunit-notifications": "0.1.0"
   }
 }
--- a/cms/app-client/config/environment.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/config/environment.js	Sat Aug 06 21:29:33 2016 +0700
@@ -5,12 +5,19 @@
     rootElement: '#corpus-app',
     modulePrefix: 'app-client',
     environment: environment,
-    baseURL: '/corpus/',
-    // locationType: '',
+    rootURL: '/corpus/',
+    locationType: 'hash',
     // contentSecurityPolicy: {
     //   'default-src': "'none'",
     //   'style-src': "'self' 'http://localhost:4200'"
     // },
+    EmberENV: {
+      FEATURES: {
+        // Here you can enable experimental features on an ember canary build
+        // e.g. 'with-controller': true
+      }
+    },
+
     APP: {
       baseStatic: '',
       // Here you can pass flags/options to your application instance
@@ -38,7 +45,7 @@
 
   if (environment === 'test') {
     // Testem prefers this...
-    ENV.baseURL = '/';
+    ENV.rootURL = '/';
     ENV.locationType = 'none';
 
     // keep test console output quieter
--- a/cms/app-client/ember-cli-build.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/ember-cli-build.js	Sat Aug 06 21:29:33 2016 +0700
@@ -37,6 +37,11 @@
             'ammaps': ['defaults']
         }
     });
+    app.import('vendor/shims/popcorn.js', {
+        exports: {
+            'popcorn': ['defaults']
+        }
+    });
 
     return app.toTree();
 };
--- a/cms/app-client/mirage/config.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/mirage/config.js	Sat Aug 06 21:29:33 2016 +0700
@@ -13,7 +13,7 @@
     */
     // this.urlPrefix = '';    // make this `http://localhost:8080`, for example, if your API is on a different server
     // this.namespace = '';    // make this `api`, for example, if your API is namespaced
-    this.namespace = ENV.baseURL.replace(/\/$/,'')+'/api/v1';
+    this.namespace = ENV.rootURL.replace(/\/$/,'')+'/api/v1';
     // this.timing = 400;      // delay for each request, automatically set to 0 during testing
 
     this.get('/documents', function({ documents }) {
--- a/cms/app-client/package.json	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/package.json	Sat Aug 06 21:29:33 2016 +0700
@@ -1,60 +1,61 @@
 {
-    "name": "app-client",
-    "version": "0.0.1",
-    "description": "Small description for app-client goes here",
-    "private": true,
-    "directories": {
-        "doc": "doc",
-        "test": "tests"
-    },
-    "scripts": {
-        "build": "ember build",
-        "start": "ember server",
-        "test": "ember test",
-        "dl-documents": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/documents/ -d mirage/fixtures/documents.js -t documents -e \"11280.100/crdo-UVE_MOCIKA_SOUND,11280.100/crdo-CFPP2000_11_SOUND,11280.100/crdo-FRA_PK_IV_10_SOUND,11280.100/crdo-FSL-CUC023_SOUND,11280.100/crdo-NEE_KHIAAK_KO_AK_SOUND,11280.100/crdo-ESLO1_ENT_047\" -p 2 -f es6",
-        "dl-transcripts": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/documents/ -d mirage/fixtures/transcripts.js -t transcripts -e \"11280.100/crdo-UVE_MOCIKA_SOUND,11280.100/crdo-CFPP2000_11_SOUND,11280.100/crdo-FRA_PK_IV_10_SOUND,11280.100/crdo-FSL-CUC023_SOUND,11280.100/crdo-NEE_KHIAAK_KO_AK_SOUND,11280.100/crdo-ESLO1_ENT_047\" -p 2 -f es6",
-        "dl-themes": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/themes/ -d mirage/fixtures/themes.js -t themes -f es6",
-        "dl-discourses": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/discourses/ -d mirage/fixtures/discourses.js -t discourses -f es6"
-    },
-    "repository": "",
-    "engines": {
-        "node": ">= 0.10.0"
-    },
-    "author": "",
-    "license": "MIT",
-    "devDependencies": {
-        "bower": "^1.7.9",
-        "broccoli-asset-rev": "^2.4.2",
-        "broccoli-funnel": "^1.0.1",
-        "broccoli-merge-trees": "^1.1.1",
-        "broccoli-static-compiler": "^0.2.2",
-        "corpus-common-addon": "file:../../common/corpus-common-addon",
-        "ember-ajax": "^2.0.1",
-        "ember-cli": "^2.6.3",
-        "ember-cli-app-version": "^1.0.0",
-        "ember-cli-babel": "^5.1.6",
-        "ember-cli-d3": "1.1.6",
-        "ember-cli-dependency-checker": "^1.2.0",
-        "ember-cli-htmlbars": "^1.0.3",
-        "ember-cli-htmlbars-inline-precompile": "^0.3.1",
-        "ember-cli-inject-live-reload": "^1.4.0",
-        "ember-cli-jshint": "^1.0.0",
-        "ember-cli-mirage": "0.2.0",
-        "ember-cli-qunit": "^1.4.0",
-        "ember-cli-release": "1.0.0-beta.1",
-        "ember-cli-sass": "5.3.1",
-        "ember-cli-sri": "^2.1.0",
-        "ember-cli-uglify": "^1.2.0",
-        "ember-data": "^2.6.0-beta.1",
-        "ember-data-fixture-adapter": "1.13.0",
-        "ember-disable-proxy-controllers": "^1.0.1",
-        "ember-export-application-global": "^1.0.5",
-        "ember-font-awesome": "github:martndemus/ember-font-awesome#pull/91/head",
-        "ember-load-initializers": "^0.5.1",
-        "ember-lodash": "0.0.6",
-        "ember-resolver": "^2.0.3",
-        "ember-welcome-page": "^1.0.1",
-        "ember-wormhole": "0.3.5",
-        "loader.js": "^4.0.1"
-    }
+  "name": "app-client",
+  "version": "0.0.1",
+  "description": "Small description for app-client goes here",
+  "private": true,
+  "directories": {
+    "doc": "doc",
+    "test": "tests"
+  },
+  "scripts": {
+    "build": "ember build",
+    "start": "ember server",
+    "test": "ember test",
+    "dl-documents": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/documents/ -d mirage/fixtures/documents.js -t documents -e \"11280.100/crdo-UVE_MOCIKA_SOUND,11280.100/crdo-CFPP2000_11_SOUND,11280.100/crdo-FRA_PK_IV_10_SOUND,11280.100/crdo-FSL-CUC023_SOUND,11280.100/crdo-NEE_KHIAAK_KO_AK_SOUND,11280.100/crdo-ESLO1_ENT_047\" -p 2 -f es6",
+    "dl-transcripts": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/documents/ -d mirage/fixtures/transcripts.js -t transcripts -e \"11280.100/crdo-UVE_MOCIKA_SOUND,11280.100/crdo-CFPP2000_11_SOUND,11280.100/crdo-FRA_PK_IV_10_SOUND,11280.100/crdo-FSL-CUC023_SOUND,11280.100/crdo-NEE_KHIAAK_KO_AK_SOUND,11280.100/crdo-ESLO1_ENT_047\" -p 2 -f es6",
+    "dl-themes": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/themes/ -d mirage/fixtures/themes.js -t themes -f es6",
+    "dl-discourses": "ember dl-fixtures -u http://127.0.0.1:8000/api/v1/discourses/ -d mirage/fixtures/discourses.js -t discourses -f es6"
+  },
+  "repository": "",
+  "engines": {
+    "node": ">= 0.10.0"
+  },
+  "author": "",
+  "license": "MIT",
+  "devDependencies": {
+    "bower": "^1.7.9",
+    "broccoli-asset-rev": "^2.4.2",
+    "broccoli-funnel": "^1.0.1",
+    "broccoli-merge-trees": "^1.1.1",
+    "broccoli-static-compiler": "^0.2.2",
+    "corpus-common-addon": "file:../../common/corpus-common-addon",
+    "ember-ajax": "^2.4.1",
+    "ember-cli": "2.7.0",
+    "ember-cli-app-version": "^1.0.0",
+    "ember-cli-babel": "^5.1.6",
+    "ember-cli-d3": "1.1.6",
+    "ember-cli-dependency-checker": "^1.2.0",
+    "ember-cli-htmlbars": "^1.0.3",
+    "ember-cli-htmlbars-inline-precompile": "^0.3.1",
+    "ember-cli-inject-live-reload": "^1.4.0",
+    "ember-cli-jshint": "^1.0.0",
+    "ember-cli-mirage": "0.2.0",
+    "ember-cli-qunit": "^2.0.0",
+    "ember-cli-release": "^0.2.9",
+    "ember-cli-sass": "5.3.1",
+    "ember-cli-sri": "^2.1.0",
+    "ember-cli-test-loader": "^1.1.0",
+    "ember-cli-uglify": "^1.2.0",
+    "ember-data": "^2.7.0",
+    "ember-data-fixture-adapter": "1.13.0",
+    "ember-disable-proxy-controllers": "^1.0.1",
+    "ember-export-application-global": "^1.0.5",
+    "ember-font-awesome": "^2.1.1",
+    "ember-load-initializers": "^0.5.1",
+    "ember-lodash": "0.0.10",
+    "ember-resolver": "^2.0.3",
+    "ember-welcome-page": "^1.0.1",
+    "ember-wormhole": "0.4.0",
+    "loader.js": "^4.0.1"
+  }
 }
--- a/cms/app-client/tests/.jshintrc	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/tests/.jshintrc	Sat Aug 06 21:29:33 2016 +0700
@@ -1,6 +1,5 @@
 {
   "predef": [
-    "server",
     "document",
     "window",
     "location",
@@ -48,6 +47,6 @@
   "strict": false,
   "white": false,
   "eqnull": true,
-  "esnext": true,
+  "esversion": 6,
   "unused": true
 }
--- a/cms/app-client/tests/helpers/destroy-app.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/tests/helpers/destroy-app.js	Sat Aug 06 21:29:33 2016 +0700
@@ -2,5 +2,4 @@
 
 export default function destroyApp(application) {
   Ember.run(application, 'destroy');
-  server.shutdown();
 }
--- a/cms/app-client/tests/index.html	Sat Aug 06 21:27:53 2016 +0700
+++ b/cms/app-client/tests/index.html	Sat Aug 06 21:29:33 2016 +0700
@@ -10,9 +10,9 @@
     {{content-for "head"}}
     {{content-for "test-head"}}
 
-    <link rel="stylesheet" href="assets/vendor.css">
-    <link rel="stylesheet" href="assets/app-client.css">
-    <link rel="stylesheet" href="assets/test-support.css">
+    <link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
+    <link rel="stylesheet" href="{{rootURL}}assets/app-client.css">
+    <link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
 
     {{content-for "head-footer"}}
     {{content-for "test-head-footer"}}
@@ -21,12 +21,11 @@
     {{content-for "body"}}
     {{content-for "test-body"}}
 
-    <script src="testem.js" integrity=""></script>
-    <script src="assets/vendor.js"></script>
-    <script src="assets/test-support.js"></script>
-    <script src="assets/app-client.js"></script>
-    <script src="assets/tests.js"></script>
-    <script src="assets/test-loader.js"></script>
+    <script src="{{rootURL}}testem.js" integrity=""></script>
+    <script src="{{rootURL}}assets/vendor.js"></script>
+    <script src="{{rootURL}}assets/test-support.js"></script>
+    <script src="{{rootURL}}assets/app-client.js"></script>
+    <script src="{{rootURL}}assets/tests.js"></script>
 
     {{content-for "body-footer"}}
     {{content-for "test-body-footer"}}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/vendor/shims/popcorn.js	Sat Aug 06 21:29:33 2016 +0700
@@ -0,0 +1,9 @@
+(function() {
+  function vendorModule() {
+    'use strict';
+
+    return { 'default': self['Popcorn'] };
+  }
+
+  define('popcorn', [], vendorModule);
+})();
--- a/common/corpus-common-addon/addon/services/resolver-service.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/common/corpus-common-addon/addon/services/resolver-service.js	Sat Aug 06 21:29:33 2016 +0700
@@ -42,7 +42,7 @@
         }
         Ember.$.ajax({
             //TODO Configuration ?
-            url: this.env().baseURL.replace(/\/$/,'') + this.apiPath +ids,
+            url: this.env().rootURL.replace(/\/$/,'') + this.apiPath +ids,
 
             success: (itemDoc) => {
                 _.each(queryRegister, (resolve_reject) => {
--- a/common/corpus-common-addon/tests/dummy/app/router.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/common/corpus-common-addon/tests/dummy/app/router.js	Sat Aug 06 21:29:33 2016 +0700
@@ -2,7 +2,8 @@
 import config from './config/environment';
 
 const Router = Ember.Router.extend({
-  location: config.locationType
+    location: config.locationType,
+    rootURL: config.rootURL || '/'
 });
 
 Router.map(function() {
--- a/common/corpus-common-addon/tests/dummy/config/environment.js	Sat Aug 06 21:27:53 2016 +0700
+++ b/common/corpus-common-addon/tests/dummy/config/environment.js	Sat Aug 06 21:29:33 2016 +0700
@@ -4,7 +4,7 @@
   var ENV = {
     modulePrefix: 'dummy',
     environment: environment,
-    baseURL: '/',
+    rootURL: '/',
     locationType: 'auto',
     EmberENV: {
       FEATURES: {
@@ -29,7 +29,7 @@
 
   if (environment === 'test') {
     // Testem prefers this...
-    ENV.baseURL = '/';
+    ENV.rootURL = '/';
     ENV.locationType = 'none';
 
     // keep test console output quieter
--- a/server/src/app/Libraries/Utils.php	Sat Aug 06 21:27:53 2016 +0700
+++ b/server/src/app/Libraries/Utils.php	Sat Aug 06 21:29:33 2016 +0700
@@ -3,6 +3,8 @@
 
 use EasyRdf\Literal;
 use EasyRdf\Resource;
+use EasyRdf\Graph;
+
 
 /**
  * Utilities functions
@@ -117,5 +119,19 @@
         }
     }
 
+    /**
+     * @param EasyRdf\Graph $graph1
+     * @param EasyRdf\Graph $graph2
+     *
+     * @return EasyRdf\Graph
+     */
+    public static function mergeGraphs(Graph $graph1, Graph $graph2)
+    {
+        $data1 = $graph1->toRdfPhp();
+        $data2 = $graph2->toRdfPhp();
+        $merged = array_merge_recursive($data1, $data2);
+        unset($data1, $data2);
+        return new Graph($graph1->getUri(), $merged, 'php');
+    }
 
 }
--- a/server/src/app/Repositories/RdfDocumentRepository.php	Sat Aug 06 21:27:53 2016 +0700
+++ b/server/src/app/Repositories/RdfDocumentRepository.php	Sat Aug 06 21:29:33 2016 +0700
@@ -7,7 +7,10 @@
 use CorpusParole\Models\DocumentResult;
 use CorpusParole\Models\Document;
 use CorpusParole\Libraries\CorpusParoleException;
+use CorpusParole\Libraries\Utils;
 use CorpusParole\Libraries\Sparql\SparqlClient;
+
+
 use CorpusParole\Services\LexvoResolverInterface;
 
 use EasyRdf\Graph;
@@ -21,6 +24,42 @@
  */
 class RdfDocumentRepository implements DocumentRepository {
 
+    const ALL_QUERIES = [
+        "SELECT".
+        "    ?uri".
+        "    ?doc".
+        "    ?title".
+        "    ?issued".
+        "    ?modified".
+        "    ?lang".
+        "    (group_concat(distinct ?publisher;separator=\", \") as ?publishers) ".
+        "WHERE {".
+        "GRAPH ?uri { ?doc a <http://www.europeana.eu/schemas/edm/ProvidedCHO>.".
+        "    ?doc <http://purl.org/dc/elements/1.1/title> ?title.".
+        "    OPTIONAL {?doc <http://purl.org/dc/elements/1.1/language> ?lang.} ".
+        "    OPTIONAL {?doc <http://purl.org/dc/terms/issued> ?issued.} ".
+        "    OPTIONAL {?doc <http://purl.org/dc/terms/modified> ?modified.} ".
+        "    OPTIONAL {?doc <http://purl.org/dc/elements/1.1/publisher> ?publisher.} }".
+        "} ".
+        "GROUP BY ?uri ?doc ?title ?issued ?modified ?lang ".
+        "ORDER BY ?uri",
+
+        "SELECT".
+        "    ?uri".
+        "    ?doc".
+        "    (sample(distinct ?ext) as ?extent) ".
+        "WHERE {".
+        "    GRAPH ?uri {".
+        "        ?s a <http://www.europeana.eu/schemas/edm/WebResource>. ".
+        "        ?uri <http://www.europeana.eu/schemas/edm/isShownBy> ?s. ".
+        "        ?uri <http://www.europeana.eu/schemas/edm/aggregatedCHO> ?doc. ".
+        "        OPTIONAL {?s <http://purl.org/dc/terms/extent> ?ext.}".
+        "    }".
+        "} ".
+        "GROUP BY ?uri ?doc ".
+        "ORDER BY ?uri"
+    ];
+
     private $sparqlClient;
     private $lexvoResolver;
 
@@ -33,44 +72,56 @@
         return $this->sparqlClient;
     }
 
-    private function queryDocs($query) {
-        $docs = $this->sparqlClient->query($query);
-
-        $data = [];
-
-        foreach ($docs as $doc) {
-            $newGraph = new Graph($doc->uri->getUri());
-            $newGraph->add($doc->uri, "rdf:type", $newGraph->resource("http://www.openarchives.org/ore/terms/Aggregation"));
-            $newGraph->add($doc->uri, "http://www.europeana.eu/schemas/edm/aggregatedCHO", $doc->doc);
-            $newGraph->add($doc->doc, "rdf:type", $newGraph->resource("http://www.europeana.eu/schemas/edm/ProvidedCHO"));
+    private function getResGraph($doc) {
+        $newGraph = new Graph($doc->uri->getUri());
+        $newGraph->add($doc->uri, "rdf:type", $newGraph->resource("http://www.openarchives.org/ore/terms/Aggregation"));
+        $newGraph->add($doc->uri, "http://www.europeana.eu/schemas/edm/aggregatedCHO", $doc->doc);
+        $newGraph->add($doc->doc, "rdf:type", $newGraph->resource("http://www.europeana.eu/schemas/edm/ProvidedCHO"));
+        if(isset($doc->title)) {
             $newGraph->add($doc->doc, "http://purl.org/dc/elements/1.1/title", $doc->title);
-            if(isset($doc->lang)) {
-                $newGraph->add($doc->doc, "http://purl.org/dc/elements/1.1/language", $doc->lang);
+        }
+        if(isset($doc->lang)) {
+            $newGraph->add($doc->doc, "http://purl.org/dc/elements/1.1/language", $doc->lang);
+        }
+        if(isset($doc->issued)) {
+            $newGraph->add($doc->doc, "http://purl.org/dc/terms/issued", $doc->issued);
+        }
+        if(isset($doc->modified)) {
+            $newGraph->add($doc->doc, "http://purl.org/dc/terms/modified", $doc->modified);
+        }
+        if(isset($doc->publishers)) {
+            $newGraph->add($doc->doc, "http://purl.org/dc/elements/1.1/publisher", $doc->publishers);
+        }
+        if(isset($doc->extent)) {
+            $newGraph->add($doc->doc, "http://purl.org/dc/terms/extent", $doc->extent);
+        }
+        return $newGraph;
+    }
+
+    private function queryDocs($queries) {
+
+        $resDocs = [];
+
+        foreach($queries as $query) {
+            $docs = $this->sparqlClient->query($query);
+            foreach($docs as $doc) {
+                $graph = $this->getResGraph($doc);
+
+                $uri = $doc->uri->getUri();
+                if(array_key_exists($uri, $resDocs)) {
+                    $resDocs[$uri] = Utils::mergeGraphs($resDocs[$uri], $graph);
+                } else {
+                    $resDocs[$uri] = $graph;
+                }
+
             }
-            if(isset($doc->issued)) {
-                $newGraph->add($doc->doc, "http://purl.org/dc/terms/issued", $doc->issued);
-            }
-            if(isset($doc->modified)) {
-                $newGraph->add($doc->doc, "http://purl.org/dc/terms/modified", $doc->modified);
-            }
-            array_push($data, new DocumentResult($doc->uri->getUri(), $newGraph));
         }
 
-        return $data;
+        return array_map(function($g) { return new DocumentResult($g->getUri(), $g); }, array_values($resDocs));
     }
 
     public function all() {
-
-        return $this->queryDocs(
-        "SELECT DISTINCT ?uri ?doc ?title ?issued ?modified ?lang".
-        "    WHERE {".
-        "        GRAPH ?uri { ?doc a <http://www.europeana.eu/schemas/edm/ProvidedCHO>.".
-        "        ?doc <http://purl.org/dc/elements/1.1/title> ?title.".
-        "        OPTIONAL {?doc <http://purl.org/dc/elements/1.1/language> ?lang.} ".
-        "        OPTIONAL {?doc <http://purl.org/dc/terms/issued> ?issued.} ".
-        "        OPTIONAL {?doc <http://purl.org/dc/terms/modified> ?modified.} }".
-        "    } ORDER BY ?uri"
-        );
+        return $this->queryDocs(self::ALL_QUERIES);
     }
 
     public function get($id, bool $short=false) {
@@ -156,17 +207,7 @@
 
         $offset = max(0,($page - 1) * $perPage);
 
-        $query =
-            "SELECT DISTINCT ?uri ?doc ?title ?issued ?modified ?lang".
-            "    WHERE {".
-            "        GRAPH ?uri { ?doc a <http://www.europeana.eu/schemas/edm/ProvidedCHO>.".
-            "        ?doc <http://purl.org/dc/elements/1.1/title> ?title.".
-            "        OPTIONAL {?doc <http://purl.org/dc/elements/1.1/language> ?lang.} ".
-            "        OPTIONAL {?doc <http://purl.org/dc/terms/issued> ?issued.} ".
-            "        OPTIONAL {?doc <http://purl.org/dc/terms/modified> ?modified.} }".
-            "    } ORDER BY ?uri OFFSET $offset LIMIT $perPage";
-
-        $results = $this->queryDocs($query);
+        $results = $this->queryDocs(array_map(function($q) use ($offset, $perPage) { return $q . "\nOFFSET $offset LIMIT $perPage"; }, self::ALL_QUERIES));
 
         return new LengthAwarePaginator($results, $total, $perPage, $page, [
             'path' => Paginator::resolveCurrentPath(),
@@ -200,7 +241,4 @@
 
         return $docList;
     }
-
-
-
 }
--- a/server/src/tests/Libraries/UtilsTest.php	Sat Aug 06 21:27:53 2016 +0700
+++ b/server/src/tests/Libraries/UtilsTest.php	Sat Aug 06 21:29:33 2016 +0700
@@ -31,4 +31,10 @@
         $this->assertNull($ms, "duration must be null");
     }
 
+    public function testiso8601IntervalToMillisDoubleZero() {
+        $ms = Utils::iso8601IntervalToMillis("PT47M00S");
+        $this->assertEquals(2820000, $ms, "duration must be 2820000");
+    }
+
+
 }