diff --git a/.gitignore b/.gitignore
index 28282b4..1989e00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@
/node_modules/
/app/Resources/assets/semantic/dist
/web/resources/
+.php_cs.cache
diff --git a/.php_cs b/.php_cs
new file mode 100644
index 0000000..744b531
--- /dev/null
+++ b/.php_cs
@@ -0,0 +1,18 @@
+in(__DIR__.'/src');
+
+return PhpCsFixer\Config::create()
+ ->setRules([
+ '@Symfony' => true,
+ 'combine_consecutive_unsets' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'no_multiline_whitespace_before_semicolons' => true,
+ 'no_useless_else' => true,
+ 'no_useless_return' => true,
+ 'ordered_imports' => true,
+ 'phpdoc_order' => true,
+ 'array_syntax' => array('syntax' => 'short'),
+ ])
+ ->setFinder($finder);
diff --git a/README.md b/README.md
index 64ff678..aaf289a 100644
--- a/README.md
+++ b/README.md
@@ -14,4 +14,16 @@ You can check if your system meets requirements by running `$ bin/symfony_requir
For full requirements see Symfony 3.2 [docs](http://symfony.com/doc/3.2/reference/requirements.html).
###Installing
-
\ No newline at end of file
+
+####Back-end
+1. Make sure your system meets the application requirements
+2. Install dependencies via [Composer](https://getcomposer.org/), `$ composer install`
+
+####Front-end
+1. Install dependencies via [npm](https://www.npmjs.com/), `$ npm install`
+2. Compile assets by running [Gulp](http://gulpjs.com/) default task, `$ gulp default`
+
+####Database
+1. Set application parameters in *app/config/parameters.yml*
+2. Generate empty database by running command `$ php bin/console doctrine:database:create`
+
\ No newline at end of file
diff --git a/app/AppKernel.php b/app/AppKernel.php
index 4c1b43e..724f7f9 100644
--- a/app/AppKernel.php
+++ b/app/AppKernel.php
@@ -17,6 +17,7 @@ class AppKernel extends Kernel
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new AppBundle\AppBundle(),
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
+ new Oneup\FlysystemBundle\OneupFlysystemBundle(),
];
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
diff --git a/app/Resources/assets/javascripts/ModelViewer.js b/app/Resources/assets/javascripts/ModelViewer.js
new file mode 100644
index 0000000..a201365
--- /dev/null
+++ b/app/Resources/assets/javascripts/ModelViewer.js
@@ -0,0 +1,92 @@
+ModelViewer = function() {
+ var container;
+ var camera, scene, cameraTarget, renderer, controls, object;
+ var width, height;
+
+ this.init = function(containerId) {
+ container = document.getElementById(containerId);
+
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ width = parseFloat(document.defaultView.getComputedStyle(container,null).getPropertyValue('width'));
+ height = parseFloat(document.defaultView.getComputedStyle(container,null).getPropertyValue('height'));
+ } else {
+ width = parseFloat(container.currentStyle.width);
+ height = parseFloat(container.currentStyle.height);
+ }
+
+
+ camera = new THREE.PerspectiveCamera(45, width/height, 0.1, 1000);
+ camera.position.set(-2, 2, 0.8);
+ camera.lookAt(new THREE.Vector3(0, 3, 0));
+
+ scene = new THREE.Scene();
+ scene.fog = new THREE.FogExp2(0x000000, 0.001);
+
+
+ var grid = new THREE.GridHelper( 30, 70 );
+ grid.position.set(30/70,-0.5,30/70);
+ scene.add( grid );
+
+ // Lights
+
+ light = new THREE.DirectionalLight( 0xffffff );
+ light.position.set( 1, 1, 1 );
+ scene.add( light );
+
+ light = new THREE.DirectionalLight( 0x002288 );
+ light.position.set( -1, -1, -1 );
+ scene.add( light );
+
+
+ scene.add( new THREE.AmbientLight( 0xf0f0f0 ));
+ scene.background = new THREE.Color( 0x000000 );
+
+ // renderer
+ renderer = new THREE.WebGLRenderer();
+ renderer.setClearColor( scene.fog.color );
+ renderer.setPixelRatio( window.devicePixelRatio );
+ renderer.setSize( width, height );
+ renderer.gammaInput = true;
+ renderer.gammaOutput = true;
+ renderer.shadowMap.enabled = true;
+ renderer.shadowMap.renderReverseSided = false;
+
+ container.appendChild(renderer.domElement);
+
+ controls = new THREE.OrbitControls( camera, renderer.domElement );
+ controls.addEventListener( 'change', this.render ); // add this only if there is no animation loop (requestAnimationFrame)
+ // controls.enableDamping = true;
+ // controls.dampingFactor = 0.25;
+ controls.enableZoom = true;
+
+ };
+
+ this.loadStl = function(model) {
+ var loader = new THREE.STLLoader();
+ loader.load(model, function (geometry) {
+ var material = new THREE.MeshPhongMaterial({color: 0xaaaaaa, shininess:200, specular: 0x333333, shading: THREE.FlatShading});
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.position.set(0, 0.5, 0);
+ mesh.rotation.set(Math.PI, 0, 0);
+ mesh.castShadow = true;
+ mesh.receiveShadow = true;
+ scene.add(mesh);
+
+ renderer.render(scene, camera);
+ });
+ };
+
+ this.animate = function() {
+
+ requestAnimationFrame( this.animate );
+
+ controls.update(); // required if controls.enableDamping = true, or if controls.autoRotate = true
+
+ this.render();
+ };
+
+ this.render = function() {
+ renderer.render(scene, camera);
+ };
+};
\ No newline at end of file
diff --git a/app/Resources/assets/javascripts/STLLoader.js b/app/Resources/assets/javascripts/STLLoader.js
deleted file mode 100644
index bbcff10..0000000
--- a/app/Resources/assets/javascripts/STLLoader.js
+++ /dev/null
@@ -1,491 +0,0 @@
-/**
- * @author aleeper / http://adamleeper.com/
- * @author mrdoob / http://mrdoob.com/
- * @author gero3 / https://github.com/gero3
- *
- * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
- *
- * Supports both binary and ASCII encoded files, with automatic detection of type.
- *
- * Limitations:
- * Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL).
- * There is perhaps some question as to how valid it is to always assume little-endian-ness.
- * ASCII decoding assumes file is UTF-8. Seems to work for the examples...
- *
- * Usage:
- * var loader = new THREE.STLLoader();
- * loader.load( './models/stl/slotted_disk.stl', function ( geometry ) {
- * scene.add( new THREE.Mesh( geometry ) );
- * });
- *
- * For binary STLs geometry might contain colors for vertices. To use it:
- * // use the same code to load STL as above
- * if (geometry.hasColors) {
- * material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors });
- * } else { .... }
- * var mesh = new THREE.Mesh( geometry, material );
- */
-
-
-THREE.STLLoader = function ( manager ) {
-
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-
-};
-
-THREE.STLLoader.prototype = {
-
- constructor: THREE.STLLoader,
-
- load: function ( url, onLoad, onProgress, onError ) {
-
- var scope = this;
-
- var loader = new THREE.XHRLoader( scope.manager );
- loader.setResponseType( 'arraybuffer' );
- loader.load( url, function ( text ) {
-
- onLoad( scope.parse( text ) );
-
- }, onProgress, onError );
-
- },
-
- parse: function ( data ) {
-
- var isBinary = function () {
-
- var expect, face_size, n_faces, reader;
- reader = new DataView( binData );
- face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 );
- n_faces = reader.getUint32( 80, true );
- expect = 80 + ( 32 / 8 ) + ( n_faces * face_size );
-
- if ( expect === reader.byteLength ) {
-
- return true;
-
- }
-
- // some binary files will have different size from expected,
- // checking characters higher than ASCII to confirm is binary
- var fileLength = reader.byteLength;
- for ( var index = 0; index < fileLength; index ++ ) {
-
- if ( reader.getUint8( index, false ) > 127 ) {
-
- return true;
-
- }
-
- }
-
- return false;
-
- };
-
- var binData = this.ensureBinary( data );
-
- return isBinary()
- ? this.parseBinary( binData )
- : this.parseASCII( this.ensureString( data ) );
-
- },
-
- parseBinary: function ( data ) {
-
- var reader = new DataView( data );
- var faces = reader.getUint32( 80, true );
-
- var r, g, b, hasColors = false, colors;
- var defaultR, defaultG, defaultB, alpha;
-
- // process STL header
- // check for default color in header ("COLOR=rgba" sequence).
-
- for ( var index = 0; index < 80 - 10; index ++ ) {
-
- if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) &&
- ( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) &&
- ( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) {
-
- hasColors = true;
- colors = new Float32Array( faces * 3 * 3 );
-
- defaultR = reader.getUint8( index + 6 ) / 255;
- defaultG = reader.getUint8( index + 7 ) / 255;
- defaultB = reader.getUint8( index + 8 ) / 255;
- alpha = reader.getUint8( index + 9 ) / 255;
-
- }
-
- }
-
- var dataOffset = 84;
- var faceLength = 12 * 4 + 2;
-
- var offset = 0;
-
- var geometry = new THREE.BufferGeometry();
-
- var vertices = new Float32Array( faces * 3 * 3 );
- var normals = new Float32Array( faces * 3 * 3 );
-
- for ( var face = 0; face < faces; face ++ ) {
-
- var start = dataOffset + face * faceLength;
- var normalX = reader.getFloat32( start, true );
- var normalY = reader.getFloat32( start + 4, true );
- var normalZ = reader.getFloat32( start + 8, true );
-
- if ( hasColors ) {
-
- var packedColor = reader.getUint16( start + 48, true );
-
- if ( ( packedColor & 0x8000 ) === 0 ) {
-
- // facet has its own unique color
-
- r = ( packedColor & 0x1F ) / 31;
- g = ( ( packedColor >> 5 ) & 0x1F ) / 31;
- b = ( ( packedColor >> 10 ) & 0x1F ) / 31;
-
- } else {
-
- r = defaultR;
- g = defaultG;
- b = defaultB;
-
- }
-
- }
-
- for ( var i = 1; i <= 3; i ++ ) {
-
- var vertexstart = start + i * 12;
-
- vertices[ offset ] = reader.getFloat32( vertexstart, true );
- vertices[ offset + 1 ] = reader.getFloat32( vertexstart + 4, true );
- vertices[ offset + 2 ] = reader.getFloat32( vertexstart + 8, true );
-
- normals[ offset ] = normalX;
- normals[ offset + 1 ] = normalY;
- normals[ offset + 2 ] = normalZ;
-
- if ( hasColors ) {
-
- colors[ offset ] = r;
- colors[ offset + 1 ] = g;
- colors[ offset + 2 ] = b;
-
- }
-
- offset += 3;
-
- }
-
- }
-
- geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
- geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
-
- if ( hasColors ) {
-
- geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
- geometry.hasColors = true;
- geometry.alpha = alpha;
-
- }
-
- return geometry;
-
- },
-
- parseASCII: function ( data ) {
-
- var geometry, length, normal, patternFace, patternNormal, patternVertex, result, text;
- geometry = new THREE.Geometry();
- patternFace = /facet([\s\S]*?)endfacet/g;
-
- while ( ( result = patternFace.exec( data ) ) !== null ) {
-
- text = result[ 0 ];
- patternNormal = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;
-
- while ( ( result = patternNormal.exec( text ) ) !== null ) {
-
- normal = new THREE.Vector3( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) );
-
- }
-
- patternVertex = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;
-
- while ( ( result = patternVertex.exec( text ) ) !== null ) {
-
- geometry.vertices.push( new THREE.Vector3( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) ) );
-
- }
-
- length = geometry.vertices.length;
-
- geometry.faces.push( new THREE.Face3( length - 3, length - 2, length - 1, normal ) );
-
- }
-
- geometry.computeBoundingBox();
- geometry.computeBoundingSphere();
-
- return geometry;
-
- },
-
- ensureString: function ( buf ) {
-
- if ( typeof buf !== "string" ) {
-
- var array_buffer = new Uint8Array( buf );
- var strArray = [];
- for ( var i = 0; i < buf.byteLength; i ++ ) {
-
- strArray.push(String.fromCharCode( array_buffer[ i ] )); // implicitly assumes little-endian
-
- }
- return strArray.join('');
-
- } else {
-
- return buf;
-
- }
-
- },
-
- ensureBinary: function ( buf ) {
-
- if ( typeof buf === "string" ) {
-
- var array_buffer = new Uint8Array( buf.length );
- for ( var i = 0; i < buf.length; i ++ ) {
-
- array_buffer[ i ] = buf.charCodeAt( i ) & 0xff; // implicitly assumes little-endian
-
- }
- return array_buffer.buffer || array_buffer;
-
- } else {
-
- return buf;
-
- }
-
- }
-
-};
-
-if ( typeof DataView === 'undefined' ) {
-
- DataView = function( buffer, byteOffset, byteLength ) {
-
- this.buffer = buffer;
- this.byteOffset = byteOffset || 0;
- this.byteLength = byteLength || buffer.byteLength || buffer.length;
- this._isString = typeof buffer === "string";
-
- };
-
- DataView.prototype = {
-
- _getCharCodes: function( buffer, start, length ) {
-
- start = start || 0;
- length = length || buffer.length;
- var end = start + length;
- var codes = [];
- for ( var i = start; i < end; i ++ ) {
-
- codes.push( buffer.charCodeAt( i ) & 0xff );
-
- }
- return codes;
-
- },
-
- _getBytes: function ( length, byteOffset, littleEndian ) {
-
- var result;
-
- // Handle the lack of endianness
- if ( littleEndian === undefined ) {
-
- littleEndian = this._littleEndian;
-
- }
-
- // Handle the lack of byteOffset
- if ( byteOffset === undefined ) {
-
- byteOffset = this.byteOffset;
-
- } else {
-
- byteOffset = this.byteOffset + byteOffset;
-
- }
-
- if ( length === undefined ) {
-
- length = this.byteLength - byteOffset;
-
- }
-
- // Error Checking
- if ( typeof byteOffset !== 'number' ) {
-
- throw new TypeError( 'DataView byteOffset is not a number' );
-
- }
-
- if ( length < 0 || byteOffset + length > this.byteLength ) {
-
- throw new Error( 'DataView length or (byteOffset+length) value is out of bounds' );
-
- }
-
- if ( this.isString ) {
-
- result = this._getCharCodes( this.buffer, byteOffset, byteOffset + length );
-
- } else {
-
- result = this.buffer.slice( byteOffset, byteOffset + length );
-
- }
-
- if ( ! littleEndian && length > 1 ) {
-
- if ( Array.isArray( result ) === false ) {
-
- result = Array.prototype.slice.call( result );
-
- }
-
- result.reverse();
-
- }
-
- return result;
-
- },
-
- // Compatibility functions on a String Buffer
-
- getFloat64: function ( byteOffset, littleEndian ) {
-
- var b = this._getBytes( 8, byteOffset, littleEndian ),
-
- sign = 1 - ( 2 * ( b[ 7 ] >> 7 ) ),
- exponent = ( ( ( ( b[ 7 ] << 1 ) & 0xff ) << 3 ) | ( b[ 6 ] >> 4 ) ) - ( ( 1 << 10 ) - 1 ),
-
- // Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead
- mantissa = ( ( b[ 6 ] & 0x0f ) * Math.pow( 2, 48 ) ) + ( b[ 5 ] * Math.pow( 2, 40 ) ) + ( b[ 4 ] * Math.pow( 2, 32 ) ) +
- ( b[ 3 ] * Math.pow( 2, 24 ) ) + ( b[ 2 ] * Math.pow( 2, 16 ) ) + ( b[ 1 ] * Math.pow( 2, 8 ) ) + b[ 0 ];
-
- if ( exponent === 1024 ) {
-
- if ( mantissa !== 0 ) {
-
- return NaN;
-
- } else {
-
- return sign * Infinity;
-
- }
-
- }
-
- if ( exponent === - 1023 ) {
-
- // Denormalized
- return sign * mantissa * Math.pow( 2, - 1022 - 52 );
-
- }
-
- return sign * ( 1 + mantissa * Math.pow( 2, - 52 ) ) * Math.pow( 2, exponent );
-
- },
-
- getFloat32: function ( byteOffset, littleEndian ) {
-
- var b = this._getBytes( 4, byteOffset, littleEndian ),
-
- sign = 1 - ( 2 * ( b[ 3 ] >> 7 ) ),
- exponent = ( ( ( b[ 3 ] << 1 ) & 0xff ) | ( b[ 2 ] >> 7 ) ) - 127,
- mantissa = ( ( b[ 2 ] & 0x7f ) << 16 ) | ( b[ 1 ] << 8 ) | b[ 0 ];
-
- if ( exponent === 128 ) {
-
- if ( mantissa !== 0 ) {
-
- return NaN;
-
- } else {
-
- return sign * Infinity;
-
- }
-
- }
-
- if ( exponent === - 127 ) {
-
- // Denormalized
- return sign * mantissa * Math.pow( 2, - 126 - 23 );
-
- }
-
- return sign * ( 1 + mantissa * Math.pow( 2, - 23 ) ) * Math.pow( 2, exponent );
-
- },
-
- getInt32: function ( byteOffset, littleEndian ) {
-
- var b = this._getBytes( 4, byteOffset, littleEndian );
- return ( b[ 3 ] << 24 ) | ( b[ 2 ] << 16 ) | ( b[ 1 ] << 8 ) | b[ 0 ];
-
- },
-
- getUint32: function ( byteOffset, littleEndian ) {
-
- return this.getInt32( byteOffset, littleEndian ) >>> 0;
-
- },
-
- getInt16: function ( byteOffset, littleEndian ) {
-
- return ( this.getUint16( byteOffset, littleEndian ) << 16 ) >> 16;
-
- },
-
- getUint16: function ( byteOffset, littleEndian ) {
-
- var b = this._getBytes( 2, byteOffset, littleEndian );
- return ( b[ 1 ] << 8 ) | b[ 0 ];
-
- },
-
- getInt8: function ( byteOffset ) {
-
- return ( this.getUint8( byteOffset ) << 24 ) >> 24;
-
- },
-
- getUint8: function ( byteOffset ) {
-
- return this._getBytes( 1, byteOffset )[ 0 ];
-
- }
-
- };
-
-}
diff --git a/app/Resources/views/default/index.html.twig b/app/Resources/views/default/index.html.twig
index aa88ca9..e8b7a5f 100644
--- a/app/Resources/views/default/index.html.twig
+++ b/app/Resources/views/default/index.html.twig
@@ -1,76 +1,6 @@
{% extends 'base.html.twig' %}
{% block body %}
-
-
-
-
Welcome to Symfony {{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}
-
-
-
-
-
- Your application is now ready. You can start working on it at:
- {{ base_dir }}
-
-
-
-
-
-
-
{% endblock %}
-{% block stylesheets %}
-
-{% endblock %}
diff --git a/app/Resources/views/part/detail.html.twig b/app/Resources/views/part/detail.html.twig
new file mode 100644
index 0000000..b6461a2
--- /dev/null
+++ b/app/Resources/views/part/detail.html.twig
@@ -0,0 +1,33 @@
+{% extends 'base.html.twig' %}
+
+{% block body %}
+
+ {{ dump(part) }}
+
+ {{ dump(localPart) }}
+
+
+
+
+{% endblock %}
+
+{% block javascripts %}
+ {{ parent() }}
+
+
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/Resources/views/parts/detail.html.twig b/app/Resources/views/parts/detail.html.twig
deleted file mode 100644
index e626c3c..0000000
--- a/app/Resources/views/parts/detail.html.twig
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends 'base.html.twig' %}
-
-{% block body %}
-
- {{ dump(part) }}
-
-{% endblock %}
\ No newline at end of file
diff --git a/app/Resources/views/sets/browse.html.twig b/app/Resources/views/set/browse.html.twig
similarity index 100%
rename from app/Resources/views/sets/browse.html.twig
rename to app/Resources/views/set/browse.html.twig
diff --git a/app/Resources/views/sets/detail.html.twig b/app/Resources/views/set/detail.html.twig
similarity index 100%
rename from app/Resources/views/sets/detail.html.twig
rename to app/Resources/views/set/detail.html.twig
diff --git a/app/config/config.yml b/app/config/config.yml
index 685a70d..4b4bbd4 100644
--- a/app/config/config.yml
+++ b/app/config/config.yml
@@ -7,6 +7,11 @@ imports:
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: en
+ rebrickable_url:
+ pieces: 'http://rebrickable.com/files/pieces.csv.gz'
+ sets: 'http://rebrickable.com/files/sets.csv.gz'
+ set_pieces: 'http://rebrickable.com/files/set_pieces.csv.gz'
+ ldraw_url: 'http://www.ldraw.org/library/updates/completeCA.zip'
framework:
#esi: ~
@@ -75,4 +80,13 @@ knp_menu:
# if true, enables the helper for PHP templates
templating: false
# the renderer to use, list is also available by default
- default_renderer: twig
\ No newline at end of file
+ default_renderer: twig
+
+oneup_flysystem:
+ adapters:
+ ldraw_adapter:
+ local:
+ directory: "%kernel.root_dir%/../var/data/ldraw"
+ filesystems:
+ ldraw:
+ adapter: ldraw_adapter
\ No newline at end of file
diff --git a/app/config/services.yml b/app/config/services.yml
index fa1ed9f..5814f07 100644
--- a/app/config/services.yml
+++ b/app/config/services.yml
@@ -13,12 +13,16 @@ services:
class: AppBundle\Api\Manager\RebrickableManager
arguments: ['@client.rebrickable']
- app.collection_service:
+ sevice.collection:
class: AppBundle\Service\CollectionService
arguments: ['@doctrine.orm.entity_manager', '@manager.brickset','@manager.rebrickable']
- app.model_loader_service:
- class: AppBundle\Service\ModelLoaderService
- arguments: ['@doctrine.orm.entity_manager','%kernel.root_dir%/../var/data/LDrawLibrary', '@manager.rebrickable']
+
+ loader.rebrickable:
+ class: AppBundle\Command\Loader\RebrickableLoader
+ arguments: ['@doctrine.orm.entity_manager', '@manager.rebrickable', '%rebrickable_url%' ]
+ loader.ldraw:
+ class: AppBundle\Command\Loader\LDrawLoader
+ arguments: ['@doctrine.orm.entity_manager', '%kernel.root_dir%/../bin/ldview', '@oneup_flysystem.ldraw_filesystem', '%ldraw_url%']
app.form.filter_set:
class: AppBundle\Form\FilterSetType
diff --git a/bin/ldview b/bin/ldview
new file mode 100644
index 0000000..d255b0f
Binary files /dev/null and b/bin/ldview differ
diff --git a/bin/php-cs-fixer-hook.sh b/bin/php-cs-fixer-hook.sh
new file mode 100644
index 0000000..47bcf2f
--- /dev/null
+++ b/bin/php-cs-fixer-hook.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# To use this hook you need to install php-cs-fixer
+# Copy this file to ./git/hooks/pre-commit to get it working.
+
+ROOT=""
+
+echo "php-cs-fixer pre commit hook start"
+
+PHP_CS_FIXER="vendor/bin/php-cs-fixer"
+HAS_PHP_CS_FIXER=false
+
+if [ -x vendor/bin/php-cs-fixer ]; then
+ HAS_PHP_CS_FIXER=true
+fi
+
+if $HAS_PHP_CS_FIXER; then
+ git status --porcelain | grep -e '^[AM]\(.*\).php$' | cut -c 3- | while read line; do
+ $PHP_CS_FIXER fix --config=$ROOT/.php_cs --verbose "$line";
+ git add "$line";
+ done
+else
+ echo ""
+ echo "Please install php-cs-fixer, e.g.:"
+ echo ""
+ echo " composer require --dev friendsofphp/php-cs-fixer"
+ echo ""
+fi
+
+echo "php-cs-fixer pre commit hook finish"
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 7368436..4346b66 100644
--- a/composer.json
+++ b/composer.json
@@ -23,11 +23,13 @@
"sensio/framework-extra-bundle": "^3.0.2",
"incenteev/composer-parameter-handler": "^2.0",
"guzzlehttp/guzzle": "^6.2",
- "knplabs/knp-menu-bundle": "^2.0"
+ "knplabs/knp-menu-bundle": "^2.0",
+ "oneup/flysystem-bundle": "^1.7"
},
"require-dev": {
"sensio/generator-bundle": "^3.0",
- "symfony/phpunit-bridge": "^3.0"
+ "symfony/phpunit-bridge": "^3.0",
+ "friendsofphp/php-cs-fixer": "^2.0"
},
"scripts": {
"symfony-scripts": [
diff --git a/composer.lock b/composer.lock
index 47c4b3e..fccd0a0 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "5ce1afc2e13970cdfddedeb899ae01a1",
- "content-hash": "f88eedfb311bae0ebb9f759a2d044707",
+ "content-hash": "54b7bfc7ee85ba1c5bb4cd9f7d9cfa60",
"packages": [
{
"name": "doctrine/annotations",
@@ -73,7 +72,7 @@
"docblock",
"parser"
],
- "time": "2015-08-31 12:32:49"
+ "time": "2015-08-31T12:32:49+00:00"
},
{
"name": "doctrine/cache",
@@ -143,7 +142,7 @@
"cache",
"caching"
],
- "time": "2016-10-29 11:16:17"
+ "time": "2016-10-29T11:16:17+00:00"
},
{
"name": "doctrine/collections",
@@ -209,7 +208,7 @@
"collections",
"iterator"
],
- "time": "2015-04-14 22:21:58"
+ "time": "2015-04-14T22:21:58+00:00"
},
{
"name": "doctrine/common",
@@ -282,7 +281,7 @@
"persistence",
"spl"
],
- "time": "2016-11-30 16:50:46"
+ "time": "2016-11-30T16:50:46+00:00"
},
{
"name": "doctrine/dbal",
@@ -353,7 +352,7 @@
"persistence",
"queryobject"
],
- "time": "2016-09-09 19:13:33"
+ "time": "2016-09-09T19:13:33+00:00"
},
{
"name": "doctrine/doctrine-bundle",
@@ -434,7 +433,7 @@
"orm",
"persistence"
],
- "time": "2016-08-10 15:35:22"
+ "time": "2016-08-10T15:35:22+00:00"
},
{
"name": "doctrine/doctrine-cache-bundle",
@@ -522,7 +521,7 @@
"cache",
"caching"
],
- "time": "2016-01-26 17:28:51"
+ "time": "2016-01-26T17:28:51+00:00"
},
{
"name": "doctrine/inflector",
@@ -589,7 +588,7 @@
"singularize",
"string"
],
- "time": "2015-11-06 14:35:42"
+ "time": "2015-11-06T14:35:42+00:00"
},
{
"name": "doctrine/instantiator",
@@ -643,7 +642,7 @@
"constructor",
"instantiate"
],
- "time": "2015-06-14 21:17:01"
+ "time": "2015-06-14T21:17:01+00:00"
},
{
"name": "doctrine/lexer",
@@ -697,7 +696,7 @@
"lexer",
"parser"
],
- "time": "2014-09-09 13:34:57"
+ "time": "2014-09-09T13:34:57+00:00"
},
{
"name": "doctrine/orm",
@@ -773,7 +772,7 @@
"database",
"orm"
],
- "time": "2016-12-18 15:42:34"
+ "time": "2016-12-18T15:42:34+00:00"
},
{
"name": "guzzlehttp/guzzle",
@@ -835,7 +834,7 @@
"rest",
"web service"
],
- "time": "2016-10-08 15:01:37"
+ "time": "2016-10-08T15:01:37+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -886,7 +885,7 @@
"keywords": [
"promise"
],
- "time": "2016-12-20 10:07:11"
+ "time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
@@ -944,7 +943,7 @@
"stream",
"uri"
],
- "time": "2016-06-24 23:00:38"
+ "time": "2016-06-24T23:00:38+00:00"
},
{
"name": "incenteev/composer-parameter-handler",
@@ -995,7 +994,7 @@
"keywords": [
"parameters management"
],
- "time": "2015-11-10 17:04:01"
+ "time": "2015-11-10T17:04:01+00:00"
},
{
"name": "jdorn/sql-formatter",
@@ -1045,7 +1044,7 @@
"highlight",
"sql"
],
- "time": "2014-01-12 16:20:24"
+ "time": "2014-01-12T16:20:24+00:00"
},
{
"name": "knplabs/knp-menu",
@@ -1111,7 +1110,7 @@
"menu",
"tree"
],
- "time": "2016-09-22 07:36:19"
+ "time": "2016-09-22T07:36:19+00:00"
},
{
"name": "knplabs/knp-menu-bundle",
@@ -1168,7 +1167,90 @@
"keywords": [
"menu"
],
- "time": "2016-09-22 12:24:40"
+ "time": "2016-09-22T12:24:40+00:00"
+ },
+ {
+ "name": "league/flysystem",
+ "version": "1.0.32",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/flysystem.git",
+ "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b5c4a0031697f46e779a9d1b309c2e1b24daeab",
+ "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.9"
+ },
+ "conflict": {
+ "league/flysystem-sftp": "<1.0.6"
+ },
+ "require-dev": {
+ "ext-fileinfo": "*",
+ "mockery/mockery": "~0.9",
+ "phpspec/phpspec": "^2.2",
+ "phpunit/phpunit": "~4.8"
+ },
+ "suggest": {
+ "ext-fileinfo": "Required for MimeType",
+ "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
+ "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
+ "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
+ "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
+ "league/flysystem-copy": "Allows you to use Copy.com storage",
+ "league/flysystem-dropbox": "Allows you to use Dropbox storage",
+ "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
+ "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
+ "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
+ "league/flysystem-webdav": "Allows you to use WebDAV storage",
+ "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Flysystem\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Frank de Jonge",
+ "email": "info@frenky.net"
+ }
+ ],
+ "description": "Filesystem abstraction: Many filesystems, one API.",
+ "keywords": [
+ "Cloud Files",
+ "WebDAV",
+ "abstraction",
+ "aws",
+ "cloud",
+ "copy.com",
+ "dropbox",
+ "file systems",
+ "files",
+ "filesystem",
+ "filesystems",
+ "ftp",
+ "rackspace",
+ "remote",
+ "s3",
+ "sftp",
+ "storage"
+ ],
+ "time": "2016-10-19T20:38:46+00:00"
},
{
"name": "monolog/monolog",
@@ -1246,7 +1328,86 @@
"logging",
"psr-3"
],
- "time": "2016-11-26 00:15:39"
+ "time": "2016-11-26T00:15:39+00:00"
+ },
+ {
+ "name": "oneup/flysystem-bundle",
+ "version": "1.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/1up-lab/OneupFlysystemBundle.git",
+ "reference": "5b8b5896d6981127b5c55e7620d10dabb86778bc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/1up-lab/OneupFlysystemBundle/zipball/5b8b5896d6981127b5c55e7620d10dabb86778bc",
+ "reference": "5b8b5896d6981127b5c55e7620d10dabb86778bc",
+ "shasum": ""
+ },
+ "require": {
+ "league/flysystem": "^1.0.14",
+ "php": ">=5.4.0",
+ "symfony/framework-bundle": "~2.0|~3.0"
+ },
+ "require-dev": {
+ "league/flysystem-aws-s3-v2": "~1.0",
+ "league/flysystem-cached-adapter": "~1.0",
+ "league/flysystem-copy": "~1.0",
+ "league/flysystem-dropbox": "~1.0",
+ "league/flysystem-gridfs": "~1.0",
+ "league/flysystem-memory": "~1.0",
+ "league/flysystem-rackspace": "~1.0",
+ "league/flysystem-sftp": "~1.0",
+ "league/flysystem-webdav": "~1.0",
+ "league/flysystem-ziparchive": "~1.0",
+ "litipk/flysystem-fallback-adapter": "~0.1",
+ "phpunit/phpunit": "4.4.*",
+ "symfony/browser-kit": "~2.0|~3.0",
+ "symfony/finder": "~2.0|~3.0",
+ "twistor/flysystem-stream-wrapper": "~1.0"
+ },
+ "suggest": {
+ "ext-fileinfo": "Required for MimeType",
+ "league/flysystem-aws-s3-v2": "Use S3 storage with AWS SDK v2",
+ "league/flysystem-aws-s3-v3": "Use S3 storage with AWS SDK v3",
+ "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
+ "league/flysystem-copy": "Allows you to use Copy.com storage",
+ "league/flysystem-dropbox": "Use Dropbox storage",
+ "league/flysystem-gridfs": "Allows you to use GridFS adapter",
+ "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
+ "league/flysystem-sftp": "Allows SFTP server storage via phpseclib",
+ "league/flysystem-webdav": "Allows you to use WebDAV storage",
+ "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
+ "litipk/flysystem-fallback-adapter": "Allows you to use a fallback filesystem",
+ "twistor/flysystem-stream-wrapper": "Allows you to use stream wrapper"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "Oneup\\FlysystemBundle\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jim Schmid",
+ "email": "js@1up.io",
+ "homepage": "http://1up.io",
+ "role": "Developer"
+ }
+ ],
+ "description": "Integrates Flysystem filesystem abstraction library to your Symfony2 project.",
+ "homepage": "http://1up.io",
+ "keywords": [
+ "Flysystem",
+ "Symfony2",
+ "abstraction",
+ "filesystem"
+ ],
+ "time": "2016-12-04T12:16:31+00:00"
},
{
"name": "paragonie/random_compat",
@@ -1294,7 +1455,7 @@
"pseudorandom",
"random"
],
- "time": "2016-11-07 23:38:38"
+ "time": "2016-11-07T23:38:38+00:00"
},
{
"name": "psr/cache",
@@ -1340,7 +1501,7 @@
"psr",
"psr-6"
],
- "time": "2016-08-06 20:24:11"
+ "time": "2016-08-06T20:24:11+00:00"
},
{
"name": "psr/http-message",
@@ -1390,7 +1551,7 @@
"request",
"response"
],
- "time": "2016-08-06 14:39:51"
+ "time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
@@ -1437,7 +1598,7 @@
"psr",
"psr-3"
],
- "time": "2016-10-10 12:19:37"
+ "time": "2016-10-10T12:19:37+00:00"
},
{
"name": "sensio/distribution-bundle",
@@ -1489,7 +1650,7 @@
"configuration",
"distribution"
],
- "time": "2016-12-06 07:29:27"
+ "time": "2016-12-06T07:29:27+00:00"
},
{
"name": "sensio/framework-extra-bundle",
@@ -1557,7 +1718,7 @@
"annotations",
"controllers"
],
- "time": "2016-12-14 08:30:06"
+ "time": "2016-12-14T08:30:06+00:00"
},
{
"name": "sensiolabs/security-checker",
@@ -1601,7 +1762,7 @@
}
],
"description": "A security checker for your composer.lock",
- "time": "2016-09-23 18:09:57"
+ "time": "2016-09-23T18:09:57+00:00"
},
{
"name": "swiftmailer/swiftmailer",
@@ -1654,7 +1815,7 @@
"mail",
"mailer"
],
- "time": "2016-11-24 01:01:23"
+ "time": "2016-11-24T01:01:23+00:00"
},
{
"name": "symfony/monolog-bundle",
@@ -1714,7 +1875,7 @@
"log",
"logging"
],
- "time": "2016-11-06 18:54:50"
+ "time": "2016-11-06T18:54:50+00:00"
},
{
"name": "symfony/polyfill-apcu",
@@ -1767,7 +1928,7 @@
"portable",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2016-11-14T01:06:16+00:00"
},
{
"name": "symfony/polyfill-intl-icu",
@@ -1825,7 +1986,7 @@
"portable",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2016-11-14T01:06:16+00:00"
},
{
"name": "symfony/polyfill-mbstring",
@@ -1884,7 +2045,7 @@
"portable",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2016-11-14T01:06:16+00:00"
},
{
"name": "symfony/polyfill-php56",
@@ -1940,7 +2101,7 @@
"portable",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2016-11-14T01:06:16+00:00"
},
{
"name": "symfony/polyfill-php70",
@@ -1999,7 +2160,7 @@
"portable",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2016-11-14T01:06:16+00:00"
},
{
"name": "symfony/polyfill-util",
@@ -2051,7 +2212,7 @@
"polyfill",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2016-11-14T01:06:16+00:00"
},
{
"name": "symfony/swiftmailer-bundle",
@@ -2110,7 +2271,7 @@
],
"description": "Symfony SwiftmailerBundle",
"homepage": "http://symfony.com",
- "time": "2016-12-20 04:44:33"
+ "time": "2016-12-20T04:44:33+00:00"
},
{
"name": "symfony/symfony",
@@ -2252,7 +2413,7 @@
"keywords": [
"framework"
],
- "time": "2016-12-13 13:20:15"
+ "time": "2016-12-13T13:20:15+00:00"
},
{
"name": "twig/twig",
@@ -2313,10 +2474,127 @@
"keywords": [
"templating"
],
- "time": "2016-12-13 17:28:18"
+ "time": "2016-12-13T17:28:18+00:00"
}
],
"packages-dev": [
+ {
+ "name": "friendsofphp/php-cs-fixer",
+ "version": "v2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
+ "reference": "f3baf72eb2f58bf275b372540f5b47d25aed910f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/f3baf72eb2f58bf275b372540f5b47d25aed910f",
+ "reference": "f3baf72eb2f58bf275b372540f5b47d25aed910f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^5.3.6 || >=7.0 <7.2",
+ "sebastian/diff": "^1.1",
+ "symfony/console": "^2.3 || ^3.0",
+ "symfony/event-dispatcher": "^2.1 || ^3.0",
+ "symfony/filesystem": "^2.4 || ^3.0",
+ "symfony/finder": "^2.2 || ^3.0",
+ "symfony/polyfill-php54": "^1.0",
+ "symfony/process": "^2.3 || ^3.0",
+ "symfony/stopwatch": "^2.5 || ^3.0"
+ },
+ "conflict": {
+ "hhvm": "<3.9"
+ },
+ "require-dev": {
+ "gecko-packages/gecko-php-unit": "^2.0",
+ "phpunit/phpunit": "^4.5|^5",
+ "satooshi/php-coveralls": "^1.0"
+ },
+ "bin": [
+ "php-cs-fixer"
+ ],
+ "type": "application",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpCsFixer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dariusz RumiĆski",
+ "email": "dariusz.ruminski@gmail.com"
+ },
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "A tool to automatically fix PHP code style",
+ "time": "2016-12-01T06:18:06+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
+ "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff"
+ ],
+ "time": "2015-12-08T07:14:41+00:00"
+ },
{
"name": "sensio/generator-bundle",
"version": "v3.1.2",
@@ -2367,7 +2645,7 @@
}
],
"description": "This bundle generates code for you",
- "time": "2016-12-05 16:01:19"
+ "time": "2016-12-05T16:01:19+00:00"
},
{
"name": "symfony/phpunit-bridge",
@@ -2425,7 +2703,65 @@
],
"description": "Symfony PHPUnit Bridge",
"homepage": "https://symfony.com",
- "time": "2016-12-12 13:31:08"
+ "time": "2016-12-12T13:31:08+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php54",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php54.git",
+ "reference": "90e085822963fdcc9d1c5b73deb3d2e5783b16a0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/90e085822963fdcc9d1c5b73deb3d2e5783b16a0",
+ "reference": "90e085822963fdcc9d1c5b73deb3d2e5783b16a0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php54\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2016-11-14T01:06:16+00:00"
}
],
"aliases": [],
diff --git a/gulpfile.js b/gulpfile.js
index 6b6b82b..c977193 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -17,11 +17,32 @@ gulp.task('css', function() {
.pipe(gulp.dest('web/resources/css'));
});
+gulp.task('three', function() {
+ gulp.src([
+ 'node_modules/three/build/three.js',
+ 'node_modules/three/examples/js/libs/stats.min.js',
+ 'node_modules/three/examples/js/loaders/STLLoader.js',
+ ])
+ .pipe(plugins.concat('three.js'))
+ .pipe(gulp.dest('web/resources/js'));
+
+ gulp.src([
+ 'node_modules/three/examples/js/controls/OrbitControls.js',
+ ])
+ .pipe(plugins.concat('OrbitControls.js'))
+ .pipe(gulp.dest('web/resources/js'));
+
+ gulp.src([
+ 'app/Resources/assets/javascripts/ModelViewer.js',
+ ])
+ .pipe(plugins.concat('ModelViewer.js'))
+ .pipe(gulp.dest('web/resources/js'));
+});
+
gulp.task('js', function() {
return gulp.src([
'node_modules/jquery/dist/jquery.js',
'app/Resources/assets/semantic/dist/semantic.js',
- 'node_modules//three/build/three.js'
])
.pipe(plugins.concat('main.js'))
.pipe(gulp.dest('web/resources/js'));
diff --git a/src/AppBundle/Api/Client/Brickset/Brickset.php b/src/AppBundle/Api/Client/Brickset/Brickset.php
index 7ac2831..4d98dca 100644
--- a/src/AppBundle/Api/Client/Brickset/Brickset.php
+++ b/src/AppBundle/Api/Client/Brickset/Brickset.php
@@ -23,7 +23,7 @@ class Brickset extends \SoapClient
/**
* @var array The defined classes
*/
- private static $classmap = array(
+ private static $classmap = [
'sets' => Set::class,
'additionalImages' => AdditionalImage::class,
'instructions' => Instructions::class,
@@ -31,14 +31,14 @@ class Brickset extends \SoapClient
'themes' => Theme::class,
'subthemes' => Subtheme::class,
'years' => Year::class,
- );
+ ];
/**
* @param string $apikey Brickset API key
* @param array $options A array of config values
* @param string $wsdl The wsdl file to use
*/
- public function __construct($apikey, $wsdl = null, array $options = array())
+ public function __construct($apikey, $wsdl = null, array $options = [])
{
$this->apiKey = $apikey;
@@ -238,11 +238,10 @@ class Brickset extends \SoapClient
return false;
} elseif (strpos($response, 'ERROR:') === 0) {
return false;
- } else {
- $this->userHash = $response;
-
- return true;
}
+ $this->userHash = $response;
+
+ return true;
}
/**
diff --git a/src/AppBundle/Api/Client/Brickset/Entity/Review.php b/src/AppBundle/Api/Client/Brickset/Entity/Review.php
index 632e04c..c692749 100644
--- a/src/AppBundle/Api/Client/Brickset/Entity/Review.php
+++ b/src/AppBundle/Api/Client/Brickset/Entity/Review.php
@@ -57,7 +57,7 @@ class Review
/**
* Review constructor.
*/
- function __construct()
+ public function __construct()
{
}
@@ -88,12 +88,11 @@ class Review
{
if ($this->datePosted == null) {
return null;
- } else {
- try {
- return new \DateTime($this->datePosted);
- } catch (\Exception $e) {
- return null;
- }
+ }
+ try {
+ return new \DateTime($this->datePosted);
+ } catch (\Exception $e) {
+ return null;
}
}
diff --git a/src/AppBundle/Api/Client/Brickset/Entity/Set.php b/src/AppBundle/Api/Client/Brickset/Entity/Set.php
index d1edc95..6b5ad5c 100644
--- a/src/AppBundle/Api/Client/Brickset/Entity/Set.php
+++ b/src/AppBundle/Api/Client/Brickset/Entity/Set.php
@@ -848,12 +848,11 @@ class Set
{
if ($this->lastUpdated == null) {
return null;
- } else {
- try {
- return new \DateTime($this->lastUpdated);
- } catch (\Exception $e) {
- return null;
- }
+ }
+ try {
+ return new \DateTime($this->lastUpdated);
+ } catch (\Exception $e) {
+ return null;
}
}
diff --git a/src/AppBundle/Api/Client/Rebrickable/Entity/Part.php b/src/AppBundle/Api/Client/Rebrickable/Entity/Part.php
index b899498..000446b 100644
--- a/src/AppBundle/Api/Client/Rebrickable/Entity/Part.php
+++ b/src/AppBundle/Api/Client/Rebrickable/Entity/Part.php
@@ -138,6 +138,7 @@ class Part
{
$this->name = $name;
}
+
/**
* @return mixed
*/
@@ -185,6 +186,7 @@ class Part
{
$this->category = $category;
}
+
/**
* @return mixed
*/
@@ -200,6 +202,7 @@ class Part
{
$this->colors = $colors;
}
+
/**
* @return mixed
*/
diff --git a/src/AppBundle/Api/Client/Rebrickable/Rebrickable.php b/src/AppBundle/Api/Client/Rebrickable/Rebrickable.php
index f802e2c..03b412e 100644
--- a/src/AppBundle/Api/Client/Rebrickable/Rebrickable.php
+++ b/src/AppBundle/Api/Client/Rebrickable/Rebrickable.php
@@ -11,7 +11,7 @@ class Rebrickable
{
const BASE_URI = 'https://rebrickable.com/api/';
const FORMAT = 'json';
-
+
/**
* @var Client
*/
@@ -21,7 +21,7 @@ class Rebrickable
* @var string
*/
private $apiKey;
-
+
/**
* RebrickableAPI constructor.
*/
@@ -52,13 +52,12 @@ class Rebrickable
throw new LogicException('Invalid API Key');
} elseif ($content === 'NOSET' || $content === 'NOPART') {
return null;
- } else {
- return $content;
}
- } else {
+
+ return $content;
+ }
//TODO
throw new LogicException($response->getStatusCode());
- }
} catch (ConnectException $e) {
//TODO
throw new LogicException($e->getMessage());
diff --git a/src/AppBundle/Api/Manager/RebrickableManager.php b/src/AppBundle/Api/Manager/RebrickableManager.php
index 11368a7..40ef01e 100644
--- a/src/AppBundle/Api/Manager/RebrickableManager.php
+++ b/src/AppBundle/Api/Manager/RebrickableManager.php
@@ -2,11 +2,11 @@
namespace AppBundle\Api\Manager;
-use AppBundle\Api\Client\Rebrickable\Rebrickable;
+use AppBundle\Api\Client\Rebrickable\Converter\PartPropertyNameConverter;
use AppBundle\Api\Client\Rebrickable\Entity\Color;
use AppBundle\Api\Client\Rebrickable\Entity\Part;
use AppBundle\Api\Client\Rebrickable\Entity\Set;
-use AppBundle\Api\Client\Rebrickable\Converter\PartPropertyNameConverter;
+use AppBundle\Api\Client\Rebrickable\Rebrickable;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
@@ -33,10 +33,10 @@ class RebrickableManager
private function getSerializer()
{
- $encoders = array(new JsonEncoder());
+ $encoders = [new JsonEncoder()];
$nameConverter = new PartPropertyNameConverter();
$objectNormalizer = new ObjectNormalizer(null, $nameConverter);
- $normalizers = array($objectNormalizer, new ArrayDenormalizer());
+ $normalizers = [$objectNormalizer, new ArrayDenormalizer()];
$serializer = new Serializer($normalizers, $encoders);
return $serializer;
diff --git a/src/AppBundle/Command/LoadLibraryCommand.php b/src/AppBundle/Command/LoadLibraryCommand.php
new file mode 100644
index 0000000..d96d211
--- /dev/null
+++ b/src/AppBundle/Command/LoadLibraryCommand.php
@@ -0,0 +1,43 @@
+setName('app:load:library')
+ ->setDescription('Loads LDraw library parts')
+ ->setHelp('This command allows you to..')
+ ->addArgument('ldraw', InputArgument::OPTIONAL, 'Path to LDraw library folder');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $ldrawLoader = $this->getContainer()->get('loader.ldraw');
+ $ldrawLoader->setOutput($output);
+
+ $rebrickableLoader = $this->getContainer()->get('loader.rebrickable');
+ $rebrickableLoader->setOutput($output);
+
+ try {
+ $ldrawLoader->loadModels($input->getArgument('ldraw'));
+
+ $rebrickableLoader->loadColors();
+
+ $rebrickableLoader->loadParts();
+
+ $rebrickableLoader->loadBuildingKits();
+
+ $rebrickableLoader->loadPartBuildingKits();
+ } catch (\Exception $e) {
+ printf($e->getMessage());
+ }
+ }
+}
diff --git a/src/AppBundle/Command/LoadRebrickableCommand.php b/src/AppBundle/Command/LoadRebrickableCommand.php
deleted file mode 100644
index 7e5ef0b..0000000
--- a/src/AppBundle/Command/LoadRebrickableCommand.php
+++ /dev/null
@@ -1,36 +0,0 @@
-setName('app:loadRebrickable')
- ->setDescription('Loads Rebrickable csv data')
- ->setHelp('This command allows you to..')
- ;
- }
-
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $modelLoader = $this->getContainer()->get('app.model_loader_service');
-
- try {
- $modelLoader->loadColors();
-
- $modelLoader->loadParts($output);
-
- $modelLoader->loadBuildingKits($output);
-
- $modelLoader->loadPartBuildingKits($output);
- } catch (\Exception $e) {
- printf($e->getMessage());
- }
- }
-}
diff --git a/src/AppBundle/Command/Loader/LDrawLoader.php b/src/AppBundle/Command/Loader/LDrawLoader.php
new file mode 100644
index 0000000..92dc37f
--- /dev/null
+++ b/src/AppBundle/Command/Loader/LDrawLoader.php
@@ -0,0 +1,187 @@
+em = $em;
+ $this->ldview = $ldview;
+ $this->dataPath = $dataPath;
+ $this->ldraw_url = $ldraw_url;
+ }
+
+ public function downloadLibrary()
+ {
+ $this->output->writeln('Downloading set_pieces.csv from Rebrickable.com');
+ $temp = $this->downloadFile($this->ldraw_url);
+ $temp_dir = tempnam(sys_get_temp_dir(), 'printabrick.');
+ if (file_exists($temp_dir)) {
+ unlink($temp_dir);
+ }
+ mkdir($temp_dir);
+ $zip = new \ZipArchive();
+ if ($zip->open($temp) != 'true') {
+ echo 'Error :- Unable to open the Zip File';
+ }
+ $zip->extractTo($temp_dir);
+ $zip->close();
+ unlink($temp);
+
+ return $temp_dir;
+ }
+
+ public function loadModels($LDrawLibrary)
+ {
+ //TODO Refactor, use flysystem
+ $adapter = new Local(getcwd().DIRECTORY_SEPARATOR.$LDrawLibrary);
+ $this->ldraw = new Filesystem($adapter);
+// $files = $this->ldraw->get('parts')->getContents();
+
+ $finder = new Finder();
+ $files = $finder->files()->name('*.dat')->depth('== 0')->in(getcwd().DIRECTORY_SEPARATOR.$LDrawLibrary.DIRECTORY_SEPARATOR.'parts');
+
+ $progressBar = new ProgressBar($this->output, $files->count());
+ $progressBar->setFormat('very_verbose');
+ $progressBar->setMessage('Loading LDraw library models');
+ $progressBar->setFormat('%message:6s% %current%/%max% [%bar%]%percent:3s%% (%elapsed:6s%/%estimated:-6s%)');
+ $progressBar->start();
+ foreach ($files as $file) {
+ $model = $this->loadPartHeader($file);
+ $model->setFile($this->createStlFile($file)->getPath());
+
+ $this->em->persist($model);
+ $this->em->flush();
+
+ $progressBar->advance();
+ }
+ $progressBar->finish();
+ }
+
+ /**
+ * @param SplFileInfo $file
+ *
+ * @return Model
+ */
+ private function loadPartHeader($file)
+ {
+ $handle = fopen($file->getRealPath(), 'r');
+ if ($handle) {
+ $firstLine = false;
+
+ $model = new Model();
+
+ // read lines while line starts with 0 or is empty
+ while (($line = trim(fgets($handle))) !== false && ($line ? $line[0] == '0' : true)) {
+ if ($line !== '') {
+ $line = preg_replace('/^0 /', '', $line);
+
+ // 0
+ if (!$firstLine) {
+ //TODO handle "~Moved to"
+ //TODO "=" - alias name for other part kept for referece
+ //TODO "_" shortcut
+
+ $array = explode(' ', trim($line), 2);
+ $category = isset($array[0]) ? $array[0] : '';
+ $model->setName($line);
+
+ $firstLine = true;
+ }
+ // 0 !CATEGORY
+ elseif (strpos($line, '!CATEGORY ') === 0) {
+ $category = trim(preg_replace('/^!CATEGORY /', '', $line));
+ }
+ // 0 !KEYWORDS , , ...,
+ elseif (strpos($line, '!KEYWORDS ') === 0) {
+ $keywords = explode(', ', preg_replace('/^!KEYWORDS /', '', $line));
+ }
+ // 0 Name: .dat
+ elseif (strpos($line, 'Name: ') === 0) {
+ $model->setNumber(preg_replace('/(^Name: )(.*)(.dat)/', '$2', $line));
+ }
+ // 0 Author: []
+ elseif (strpos($line, 'Author: ') === 0) {
+ $model->setAuthor(preg_replace('/^Author: /', '', $line));
+ }
+ }
+ }
+
+ $cat = $this->em->getRepository('AppBundle:Category')->findOneBy(['name' => $category]);
+ if ($cat == null) {
+ $cat = new Category();
+ $cat->setName($category);
+ }
+
+ $model->setCategory($cat);
+ $cat->addModel($model);
+ } else {
+ throw new LogicException('loadHeader error'); //TODO
+ }
+ fclose($handle);
+
+ return $model;
+ }
+
+ /**
+ * @param SplFileInfo $file
+ *
+ * @return \League\Flysystem\File
+ */
+ private function createStlFile($file)
+ {
+ $stlFilename = str_replace('.dat', '.stl', $file->getFilename());
+
+ if (!$this->dataPath->has($stlFilename)) {
+ $builder = new ProcessBuilder();
+ $process = $builder
+ ->setPrefix($this->ldview)
+ ->setArguments([
+// $this->ldraw->getAdapter()->getPathPrefix().$file['path'],
+ $file->getRealPath(),
+ '-LDrawDir='.$this->ldraw->getAdapter()->getPathPrefix(),
+ '-ExportFile='.$this->dataPath->getAdapter()->getPathPrefix().$stlFilename,
+ ])
+ ->getProcess();
+
+ $process->run();
+
+ if (!$process->isSuccessful() || !$this->dataPath->has($stlFilename)) {
+ throw new LogicException($file->getFilename().' : '.$process->getOutput()); //TODO
+ }
+ }
+
+ return $this->dataPath->get($stlFilename);
+ }
+}
diff --git a/src/AppBundle/Command/Loader/Loader.php b/src/AppBundle/Command/Loader/Loader.php
new file mode 100644
index 0000000..f0f2622
--- /dev/null
+++ b/src/AppBundle/Command/Loader/Loader.php
@@ -0,0 +1,72 @@
+output = $output;
+ $this->output->setDecorated(true);
+ }
+
+ private function progressCallback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max)
+ {
+ switch ($notification_code) {
+ case STREAM_NOTIFY_FILE_SIZE_IS:
+ $this->progressBar = new ProgressBar($this->output);
+ $this->progressBar->setBarWidth(100);
+ $this->progressBar->start($bytes_max);
+ break;
+ case STREAM_NOTIFY_PROGRESS:
+ $this->progressBar->setProgress($bytes_transferred);
+ break;
+ case STREAM_NOTIFY_COMPLETED:
+ $this->progressBar->setProgress($bytes_transferred);
+ $this->progressBar->finish();
+ break;
+ }
+ }
+
+ protected function downloadFile($url)
+ {
+ $temp = tempnam(sys_get_temp_dir(), 'printabrick.');
+
+ $ctx = stream_context_create([], [
+ 'notification' => [$this, 'progressCallback'],
+ ]);
+
+ try {
+ if (false === file_put_contents($temp, fopen($url, 'r', 0, $ctx))) {
+ throw new LogicException('error writing file'); //TODO
+ }
+ } catch (ContextErrorException $e) {
+ throw new LogicException('wrong url'); //TODO
+ } catch (\Exception $e) {
+ throw new LogicException('exception: '.$e->getMessage()); //TODO
+ }
+
+ return $temp;
+ }
+}
diff --git a/src/AppBundle/Service/ModelLoaderService.php b/src/AppBundle/Command/Loader/RebrickableLoader.php
similarity index 60%
rename from src/AppBundle/Service/ModelLoaderService.php
rename to src/AppBundle/Command/Loader/RebrickableLoader.php
index 8fd3d81..2009394 100644
--- a/src/AppBundle/Service/ModelLoaderService.php
+++ b/src/AppBundle/Command/Loader/RebrickableLoader.php
@@ -1,114 +1,53 @@
STLlib = $STLlib;
$this->em = $em;
$this->rebrickableManager = $rebrickableManager;
+ $this->rebrickable_url = $rebrickable_url;
}
- // LDraw
-
- public function loadModels($LDrawLibrary)
+ public function loadPartBuildingKits()
{
- $finder = new Finder();
- $files = $finder->files()->name('*.dat')->depth('== 0')->in(getcwd().'/'.$LDrawLibrary.'/parts');
+ $this->output->writeln('Downloading set_pieces.csv from Rebrickable.com');
+ $file = $this->downloadFile('compress.zlib://'.$this->rebrickable_url['set_pieces']);
- foreach ($files as $file) {
- $this->loadModelHeader($file);
- }
- }
-
- private function loadModelHeader(SplFileInfo $fileInfo)
- {
- $handle = fopen($fileInfo->getRealPath(), 'r');
- if ($handle) {
- $firstLine = fgets($handle);
- $description = trim(substr($firstLine, 2));
- $model = new Model();
- $model->setFile($fileInfo->getFilename());
- $p['category'] = explode(' ', trim($description))[0];
-
- //TODO handle ~Moved to
-
- while (!feof($handle)) {
- $line = trim(fgets($handle));
- if ($line && ($line[0] == '1')) {
- break;
- } elseif ($line && ($line[0] == '0' && strpos($line, '!CATEGORY '))) {
- $p['category'] = trim(explode('!CATEGORY ', $line)[1]);
- } elseif ($line && ($line[0] == '0' && strpos($line, '!KEYWORDS '))) {
- $keywords = explode(',', explode('!KEYWORDS ', $line)[1]);
- foreach ($keywords as $k) {
- $p['keywords'][] = trim($k);
- }
- } elseif ($line && ($line[0] == '0' && strpos($line, 'Name: '))) {
- $model->setNumber(trim(explode('.dat', explode('Name: ', $line)[1])[0]));
- } elseif ($line && ($line[0] == '0' && strpos($line, 'Author: '))) {
- $model->setAuthor(explode('Author: ', $line)[1]);
- }
- }
-
- $this->em->persist($model);
- $this->em->flush();
- } else {
- throw new LogicException('loadHeader error'); //TODO
- }
- fclose($handle);
- }
-
- // Rebrickable
-
- public function loadPartBuildingKits($output)
- {
$partRepository = $this->em->getRepository('AppBundle:Part');
$buldingKitRepository = $this->em->getRepository('AppBundle:BuildingKit');
$colorRepository = $this->em->getRepository('AppBundle:Color');
- $setPieces = tempnam(sys_get_temp_dir(), 'printabrick.');
- file_put_contents($setPieces, fopen('compress.zlib://http://rebrickable.com/files/set_pieces.csv.gz', 'r'));
-
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
- if (($handle = fopen($setPieces, 'r')) !== false) {
+ $this->output->writeln('Loading set_pieces.csv into Database');
+ if (($handle = fopen($file, 'r')) !== false) {
$header = fgetcsv($handle, 200, ',');
// create a new progress bar (50 units)
- $progress = new ProgressBar($output, intval(exec("wc -l '$setPieces'")));
+ $progress = new ProgressBar($this->output, intval(exec("wc -l '$file'"))); //TODO replace wc-l
$progress->setFormat('very_verbose');
$progress->setBarWidth(50);
$progress->start();
@@ -144,26 +83,26 @@ class ModelLoaderService
$this->em->clear();
fclose($handle);
$progress->finish();
- $progress->clear();
}
- unlink($setPieces);
+ unlink($file);
}
- public function loadBuildingKits($output)
+ public function loadBuildingKits()
{
- $keywordRepository = $this->em->getRepository('AppBundle:Keyword');
+ $this->output->writeln('Downloading sets.csv from Rebrickable.com');
+ $file = $this->downloadFile('compress.zlib://'.$this->rebrickable_url['sets']);
- $sets = tempnam(sys_get_temp_dir(), 'printabrick.');
- file_put_contents($sets, fopen('compress.zlib://http://rebrickable.com/files/sets.csv.gz', 'r'));
+ $keywordRepository = $this->em->getRepository('AppBundle:Keyword');
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
- if (($handle = fopen($sets, 'r')) !== false) {
+ $this->output->writeln('Loading sets.csv into Database');
+ if (($handle = fopen($file, 'r')) !== false) {
$header = fgetcsv($handle, 500, ',');
// create a new progress bar (50 units)
- $progress = new ProgressBar($output, intval(exec("wc -l '$sets'")));
+ $progress = new ProgressBar($this->output, intval(exec("wc -l '$file'"))); //TODO replace wc-l
$progress->setFormat('very_verbose');
$progress->setBarWidth(50);
$progress->start();
@@ -206,24 +145,23 @@ class ModelLoaderService
fclose($handle);
$progress->finish();
- $progress->clear();
}
- unlink($sets);
+ unlink($file);
}
- public function loadParts($output)
+ public function loadParts()
{
- $pieces = tempnam(sys_get_temp_dir(), 'printabrick.');
- file_put_contents($pieces, fopen('compress.zlib://http://rebrickable.com/files/pieces.csv.gz', 'r'));
+ $this->output->writeln('Downloading pieces.csv from Rebrickable.com');
+ $file = $this->downloadFile('compress.zlib://'.$this->rebrickable_url['pieces']);
$categoryRepository = $this->em->getRepository('AppBundle:Category');
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
- if (($handle = fopen($pieces, 'r')) !== false) {
-
+ $this->output->writeln('Loading pieces.csv into Database');
+ if (($handle = fopen($file, 'r')) !== false) {
// create a new progress bar (50 units)
- $progress = new ProgressBar($output, intval(exec("wc -l '$pieces'")));
+ $progress = new ProgressBar($this->output, intval(exec("wc -l '$file'"))); //TODO replace wc-l
$progress->setFormat('very_verbose');
$progress->setBarWidth(50);
$progress->start();
@@ -256,14 +194,15 @@ class ModelLoaderService
fclose($handle);
$progress->finish();
- $progress->clear();
}
- unlink($pieces);
+ unlink($file);
}
public function loadColors()
{
+ $this->output->writeln('Loading colors into Database');
+
$rb_colors = $this->rebrickableManager->getColors();
foreach ($rb_colors as $rb_color) {
@@ -283,10 +222,10 @@ class ModelLoaderService
{
$modelRepository = $this->em->getRepository('AppBundle:Model');
- if (strpos($part->getNumber(), 'p')) {
+ $model = $modelRepository->findOneBy(['number' => $part->getNumber()]);
+
+ if (!$model && strpos($part->getNumber(), 'p')) {
$model = $modelRepository->findOneBy(['number' => explode('p', $part->getNumber())[0]]);
- } else {
- $model = $modelRepository->findOneBy(['number' => $part->getNumber()]);
}
return $model;
diff --git a/src/AppBundle/Controller/DefaultController.php b/src/AppBundle/Controller/DefaultController.php
index 5216afe..36ea5c0 100644
--- a/src/AppBundle/Controller/DefaultController.php
+++ b/src/AppBundle/Controller/DefaultController.php
@@ -13,9 +13,7 @@ class DefaultController extends Controller
*/
public function indexAction(Request $request)
{
- // replace this example code with whatever you need
return $this->render('default/index.html.twig', [
- 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
]);
}
}
diff --git a/src/AppBundle/Controller/DownloadController.php b/src/AppBundle/Controller/DownloadController.php
new file mode 100644
index 0000000..3447bcb
--- /dev/null
+++ b/src/AppBundle/Controller/DownloadController.php
@@ -0,0 +1,43 @@
+get('oneup_flysystem.ldraw_filesystem');
+
+ if ($ldraw_filesystem->has($model->getFile())) {
+ $response = new BinaryFileResponse($ldraw_filesystem->getAdapter()->getPathPrefix().$model->getFile());
+ $response->headers->set('Content-Type', 'application/vnd.ms-pki.stl');
+
+ // Create the disposition of the file
+ $disposition = $response->headers->makeDisposition(
+ ResponseHeaderBag::DISPOSITION_ATTACHMENT,
+ $model->getFile()
+ );
+
+ $response->headers->set('Content-Disposition', $disposition);
+
+ return $response;
+ }
+ throw new FileNotFoundException($model->getFile());
+ }
+}
diff --git a/src/AppBundle/Controller/PartController.php b/src/AppBundle/Controller/PartController.php
new file mode 100644
index 0000000..cfff17f
--- /dev/null
+++ b/src/AppBundle/Controller/PartController.php
@@ -0,0 +1,28 @@
+get('manager.rebrickable')->getPart($id);
+
+ $em = $this->getDoctrine()->getManager();
+ $localPart = $em->getRepository('AppBundle:Part')->findOneBy(['number' => $id]);
+
+ return $this->render('part/detail.html.twig', [
+ 'part' => $part,
+ 'localPart' => $localPart,
+ ]);
+ }
+}
diff --git a/src/AppBundle/Controller/PartsController.php b/src/AppBundle/Controller/PartsController.php
deleted file mode 100644
index 07c9b1c..0000000
--- a/src/AppBundle/Controller/PartsController.php
+++ /dev/null
@@ -1,24 +0,0 @@
-get('manager.rebrickable')->getPartById($id);
-
- return $this->render('parts/detail.html.twig', [
- 'part' => $part,
- ]);
- }
-}
\ No newline at end of file
diff --git a/src/AppBundle/Controller/SetsController.php b/src/AppBundle/Controller/SetController.php
similarity index 72%
rename from src/AppBundle/Controller/SetsController.php
rename to src/AppBundle/Controller/SetController.php
index d4109e2..7679e3b 100644
--- a/src/AppBundle/Controller/SetsController.php
+++ b/src/AppBundle/Controller/SetController.php
@@ -8,12 +8,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
/**
- * @Route("/brickset/sets")
+ * @Route("/brickset/set")
*/
-class SetsController extends Controller
+class SetController extends Controller
{
/**
- * @Route("/", name="sets_browse")
+ * @Route("/", name="set_browse")
*/
public function browseAction(Request $request)
{
@@ -32,7 +32,7 @@ class SetsController extends Controller
]);
}
- return $this->render('sets/browse.html.twig', [
+ return $this->render('set/browse.html.twig', [
'form' => $form->createView(),
'sets' => $sets,
]);
@@ -43,13 +43,10 @@ class SetsController extends Controller
*/
public function detailAction(Request $request, $id, $name = null)
{
- $set = $this->get('manager.brickset')->getSetById($id);;
+ $set = $this->get('manager.brickset')->getSetById($id);
- $parts = $this->get('app.collection_service')->getSet($set->getNumber().'-'.$set->getNumberVariant())->getParts();
-
- return $this->render('sets/detail.html.twig', [
+ return $this->render('set/detail.html.twig', [
'set' => $set,
- 'parts' => $parts,
]);
}
}
diff --git a/src/AppBundle/Entity/BuildingKit.php b/src/AppBundle/Entity/BuildingKit.php
index 2eed090..b6ee8ef 100644
--- a/src/AppBundle/Entity/BuildingKit.php
+++ b/src/AppBundle/Entity/BuildingKit.php
@@ -7,7 +7,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
- * BuildingKit
+ * BuildingKit.
*
* @ORM\Table(name="building_kit")
* @ORM\Entity(repositoryClass="AppBundle\Repository\BuildingKitRepository")
@@ -74,9 +74,8 @@ class BuildingKit
$this->keywords = new ArrayCollection();
}
-
/**
- * Get id
+ * Get id.
*
* @return int
*/
@@ -105,9 +104,8 @@ class BuildingKit
return $this;
}
-
/**
- * Set name
+ * Set name.
*
* @param string $name
*
@@ -121,7 +119,7 @@ class BuildingKit
}
/**
- * Get name
+ * Get name.
*
* @return string
*/
@@ -131,9 +129,9 @@ class BuildingKit
}
/**
- * Set year
+ * Set year.
*
- * @param integer $year
+ * @param int $year
*
* @return BuildingKit
*/
@@ -145,7 +143,7 @@ class BuildingKit
}
/**
- * Get year
+ * Get year.
*
* @return int
*/
@@ -175,7 +173,7 @@ class BuildingKit
}
/**
- * Get parts
+ * Get parts.
*
* @return Collection
*/
@@ -209,7 +207,7 @@ class BuildingKit
}
/**
- * Get keywords
+ * Get keywords.
*
* @return Collection
*/
diff --git a/src/AppBundle/Entity/Category.php b/src/AppBundle/Entity/Category.php
index 636ed55..10be5c7 100644
--- a/src/AppBundle/Entity/Category.php
+++ b/src/AppBundle/Entity/Category.php
@@ -5,10 +5,9 @@ namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
-use Symfony\Component\Form\CallbackTransformer;
/**
- * Category
+ * Category.
*
* @ORM\Table(name="category")
* @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
@@ -54,9 +53,8 @@ class Category
$this->parts = new ArrayCollection();
}
-
/**
- * Get id
+ * Get id.
*
* @return int
*/
@@ -66,7 +64,7 @@ class Category
}
/**
- * Set name
+ * Set name.
*
* @param string $name
*
@@ -80,7 +78,7 @@ class Category
}
/**
- * Get name
+ * Get name.
*
* @return string
*/
@@ -90,7 +88,7 @@ class Category
}
/**
- * Get models
+ * Get models.
*
* @return ArrayCollection
*/
@@ -124,7 +122,7 @@ class Category
}
/**
- * Get parts
+ * Get parts.
*
* @return ArrayCollection
*/
diff --git a/src/AppBundle/Entity/Color.php b/src/AppBundle/Entity/Color.php
index 18d41c8..abd6547 100644
--- a/src/AppBundle/Entity/Color.php
+++ b/src/AppBundle/Entity/Color.php
@@ -6,7 +6,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
- * Color
+ * Color.
*
* @ORM\Table(name="color")
* @ORM\Entity(repositoryClass="AppBundle\Repository\ColorRepository")
@@ -43,7 +43,7 @@ class Color
private $part_building_kits;
/**
- * Set id
+ * Set id.
*
* @var int
*
@@ -57,7 +57,7 @@ class Color
}
/**
- * Get id
+ * Get id.
*
* @return int
*/
@@ -67,7 +67,7 @@ class Color
}
/**
- * Set name
+ * Set name.
*
* @param string $name
*
@@ -81,7 +81,7 @@ class Color
}
/**
- * Get name
+ * Get name.
*
* @return string
*/
@@ -91,7 +91,7 @@ class Color
}
/**
- * Set rgb
+ * Set rgb.
*
* @param string $rgb
*
@@ -105,7 +105,7 @@ class Color
}
/**
- * Get rgb
+ * Get rgb.
*
* @return string
*/
@@ -123,7 +123,6 @@ class Color
}
/**
- *
* @param Part_BuildingKit $part_building_kit
*
* @return Color
@@ -148,11 +147,10 @@ class Color
}
/**
- * Constructor
+ * Constructor.
*/
public function __construct()
{
$this->part_building_kits = new \Doctrine\Common\Collections\ArrayCollection();
}
-
}
diff --git a/src/AppBundle/Entity/Keyword.php b/src/AppBundle/Entity/Keyword.php
index 7b40e3e..f35ebba 100644
--- a/src/AppBundle/Entity/Keyword.php
+++ b/src/AppBundle/Entity/Keyword.php
@@ -6,7 +6,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
- * Keyword
+ * Keyword.
*
* @ORM\Table(name="keyword")
* @ORM\Entity(repositoryClass="AppBundle\Repository\KeywordRepository")
@@ -44,9 +44,8 @@ class Keyword
$this->building_kits = new ArrayCollection();
}
-
/**
- * Get id
+ * Get id.
*
* @return int
*/
@@ -56,7 +55,7 @@ class Keyword
}
/**
- * Set name
+ * Set name.
*
* @param string $name
*
@@ -70,7 +69,7 @@ class Keyword
}
/**
- * Get name
+ * Get name.
*
* @return string
*/
@@ -110,5 +109,4 @@ class Keyword
return $this;
}
-
}
diff --git a/src/AppBundle/Entity/Model.php b/src/AppBundle/Entity/Model.php
index 87e5cc0..b88c5d6 100644
--- a/src/AppBundle/Entity/Model.php
+++ b/src/AppBundle/Entity/Model.php
@@ -6,7 +6,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
- * Model
+ * Model.
*
* @ORM\Table(name="model")
* @ORM\Entity(repositoryClass="AppBundle\Repository\ModelRepository")
@@ -22,6 +22,12 @@ class Model
*/
private $id;
+ /**
+ * @var string
+ *
+ * @ORM\Column(name="name", type="string", length=255, nullable=true)
+ */
+ private $name;
/**
* @var string
*
@@ -53,13 +59,12 @@ class Model
/**
* @var Category
*
- * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models")
+ * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models", cascade={"persist"})
*/
private $category;
-
/**
- * Get id
+ * Get id.
*
* @return int
*/
@@ -69,7 +74,23 @@ class Model
}
/**
- * Set number
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * @param string $name
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Set number.
*
* @param string $number
*
@@ -83,7 +104,7 @@ class Model
}
/**
- * Get number
+ * Get number.
*
* @return string
*/
@@ -93,7 +114,7 @@ class Model
}
/**
- * Set author
+ * Set author.
*
* @param string $author
*
@@ -107,7 +128,7 @@ class Model
}
/**
- * Get author
+ * Get author.
*
* @return string
*/
@@ -117,7 +138,7 @@ class Model
}
/**
- * Set file
+ * Set file.
*
* @param string $file
*
@@ -131,7 +152,7 @@ class Model
}
/**
- * Get file
+ * Get file.
*
* @return string
*/
@@ -141,7 +162,7 @@ class Model
}
/**
- * Get parts
+ * Get parts.
*
* @return Collection
*/
@@ -175,7 +196,7 @@ class Model
}
/**
- * Set category
+ * Set category.
*
* @param Category $category
*
@@ -190,7 +211,7 @@ class Model
}
/**
- * Get category
+ * Get category.
*
* @return Category
*/
diff --git a/src/AppBundle/Entity/Part_BuildingKit.php b/src/AppBundle/Entity/Part_BuildingKit.php
index 2133246..3703ef4 100644
--- a/src/AppBundle/Entity/Part_BuildingKit.php
+++ b/src/AppBundle/Entity/Part_BuildingKit.php
@@ -2,11 +2,10 @@
namespace AppBundle\Entity;
-use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
- * Part_BuildingKit
+ * Part_BuildingKit.
*
* @ORM\Table(name="part__building_kit")
* @ORM\Entity(repositoryClass="AppBundle\Repository\Part_BuildingKitRepository")
@@ -57,9 +56,8 @@ class Part_BuildingKit
*/
private $building_kit;
-
/**
- * Get id
+ * Get id.
*
* @return int
*/
@@ -69,9 +67,9 @@ class Part_BuildingKit
}
/**
- * Set count
+ * Set count.
*
- * @param integer $count
+ * @param int $count
*
* @return Part_BuildingKit
*/
@@ -83,7 +81,7 @@ class Part_BuildingKit
}
/**
- * Get count
+ * Get count.
*
* @return int
*/
@@ -93,7 +91,7 @@ class Part_BuildingKit
}
/**
- * Set color
+ * Set color.
*
* @param Color $color
*
@@ -107,7 +105,7 @@ class Part_BuildingKit
}
/**
- * Get color
+ * Get color.
*
* @return Color
*/
@@ -117,9 +115,9 @@ class Part_BuildingKit
}
/**
- * Set type
+ * Set type.
*
- * @param boolean $type
+ * @param bool $type
*
* @return Part_BuildingKit
*/
@@ -131,7 +129,7 @@ class Part_BuildingKit
}
/**
- * Get type
+ * Get type.
*
* @return bool
*/
@@ -181,6 +179,4 @@ class Part_BuildingKit
return $this;
}
-
-
}
diff --git a/src/AppBundle/Form/FilterSetType.php b/src/AppBundle/Form/FilterSetType.php
index 1e68eaa..50f57e2 100644
--- a/src/AppBundle/Form/FilterSetType.php
+++ b/src/AppBundle/Form/FilterSetType.php
@@ -26,36 +26,35 @@ class FilterSetType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
- ->add("theme", ChoiceType::class, [
+ ->add('theme', ChoiceType::class, [
'choices' => $this->bricksetManager->getThemes(),
- 'choice_label' => function(Theme $theme = null) {
+ 'choice_label' => function (Theme $theme = null) {
return $theme ? $theme->getTheme().' ('.$theme->getSetCount().')' : '';
},
'placeholder' => '',
- 'required' => false
-
+ 'required' => false,
]);
$formModifier = function (Form $form, Theme $theme = null) {
$subthemes = null === $theme ? [] : $this->bricksetManager->getSubthemesByTheme($theme);
$years = null === $theme ? [] : $this->bricksetManager->getYearsByTheme($theme);
- $form->add("subtheme", ChoiceType::class, [
+ $form->add('subtheme', ChoiceType::class, [
'choices' => $subthemes,
- 'choice_label' => function(Subtheme $subtheme = null) {
+ 'choice_label' => function (Subtheme $subtheme = null) {
return $subtheme ? $subtheme->getSubtheme() : '';
},
'placeholder' => '',
- 'required' => false
+ 'required' => false,
]);
- $form->add("years", ChoiceType::class, [
+ $form->add('years', ChoiceType::class, [
'choices' => $years,
- 'choice_label' => function(Year $year = null) {
+ 'choice_label' => function (Year $year = null) {
return $year ? $year->getYear() : '';
},
'placeholder' => '',
- 'required' => false
+ 'required' => false,
]);
};
@@ -76,6 +75,6 @@ class FilterSetType extends AbstractType
}
);
- $builder->add('submit',SubmitType::class);
+ $builder->add('submit', SubmitType::class);
}
-}
\ No newline at end of file
+}
diff --git a/src/AppBundle/Menu/Builder.php b/src/AppBundle/Menu/Builder.php
index e22ca9b..b78814e 100644
--- a/src/AppBundle/Menu/Builder.php
+++ b/src/AppBundle/Menu/Builder.php
@@ -15,7 +15,7 @@ class Builder
]);
$menu->addChild('Sets', [
- 'route' => 'sets_browse',
+ 'route' => 'set_browse',
]);
return $menu;
diff --git a/src/AppBundle/Repository/BuildingKitRepository.php b/src/AppBundle/Repository/BuildingKitRepository.php
index e5eaa81..5cf0efe 100644
--- a/src/AppBundle/Repository/BuildingKitRepository.php
+++ b/src/AppBundle/Repository/BuildingKitRepository.php
@@ -5,7 +5,7 @@ namespace AppBundle\Repository;
use AppBundle\Entity\Part;
/**
- * BuildingSetRepository
+ * BuildingSetRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
diff --git a/src/AppBundle/Repository/CategoryRepository.php b/src/AppBundle/Repository/CategoryRepository.php
index adfdee4..6b9fe2b 100644
--- a/src/AppBundle/Repository/CategoryRepository.php
+++ b/src/AppBundle/Repository/CategoryRepository.php
@@ -2,10 +2,8 @@
namespace AppBundle\Repository;
-use AppBundle\Entity\Category;
-
/**
- * CategoryRepository
+ * CategoryRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
diff --git a/src/AppBundle/Repository/ColorRepository.php b/src/AppBundle/Repository/ColorRepository.php
index 7370126..5874460 100644
--- a/src/AppBundle/Repository/ColorRepository.php
+++ b/src/AppBundle/Repository/ColorRepository.php
@@ -3,7 +3,7 @@
namespace AppBundle\Repository;
/**
- * ColorRepository
+ * ColorRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
diff --git a/src/AppBundle/Repository/KeywordRepository.php b/src/AppBundle/Repository/KeywordRepository.php
index c559947..8a2e4e0 100644
--- a/src/AppBundle/Repository/KeywordRepository.php
+++ b/src/AppBundle/Repository/KeywordRepository.php
@@ -3,7 +3,7 @@
namespace AppBundle\Repository;
/**
- * KeywordRepository
+ * KeywordRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
diff --git a/src/AppBundle/Repository/ModelRepository.php b/src/AppBundle/Repository/ModelRepository.php
index 49907f3..10611e0 100644
--- a/src/AppBundle/Repository/ModelRepository.php
+++ b/src/AppBundle/Repository/ModelRepository.php
@@ -3,7 +3,7 @@
namespace AppBundle\Repository;
/**
- * ModelRepository
+ * ModelRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
diff --git a/src/AppBundle/Repository/PartRepository.php b/src/AppBundle/Repository/PartRepository.php
index 2fdb597..334bc3b 100644
--- a/src/AppBundle/Repository/PartRepository.php
+++ b/src/AppBundle/Repository/PartRepository.php
@@ -3,7 +3,7 @@
namespace AppBundle\Repository;
/**
- * PartRepository
+ * PartRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
diff --git a/src/AppBundle/Repository/Part_BuildingKitRepository.php b/src/AppBundle/Repository/Part_BuildingKitRepository.php
index 19c6347..4d6a820 100644
--- a/src/AppBundle/Repository/Part_BuildingKitRepository.php
+++ b/src/AppBundle/Repository/Part_BuildingKitRepository.php
@@ -3,7 +3,7 @@
namespace AppBundle\Repository;
/**
- * Part_BuildingKitRepository
+ * Part_BuildingKitRepository.
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.