1
0
mirror of https://github.com/ToxicCrack/PrintABrick.git synced 2025-05-21 06:30:10 -07:00

Merged branch feat/ldraw-loader into dev

This commit is contained in:
David Hübner 2017-01-21 23:35:19 +01:00
commit 0b589ba2ca
49 changed files with 1147 additions and 899 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@
/node_modules/ /node_modules/
/app/Resources/assets/semantic/dist /app/Resources/assets/semantic/dist
/web/resources/ /web/resources/
.php_cs.cache

18
.php_cs Normal file
View File

@ -0,0 +1,18 @@
<?php
$finder = PhpCsFixer\Finder::create()
->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);

View File

@ -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). For full requirements see Symfony 3.2 [docs](http://symfony.com/doc/3.2/reference/requirements.html).
###Installing ###Installing
####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`

View File

@ -17,6 +17,7 @@ class AppKernel extends Kernel
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new AppBundle\AppBundle(), new AppBundle\AppBundle(),
new Knp\Bundle\MenuBundle\KnpMenuBundle(), new Knp\Bundle\MenuBundle\KnpMenuBundle(),
new Oneup\FlysystemBundle\OneupFlysystemBundle(),
]; ];
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {

View File

@ -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);
};
};

View File

@ -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 ];
}
};
}

View File

@ -1,76 +1,6 @@
{% extends 'base.html.twig' %} {% extends 'base.html.twig' %}
{% block body %} {% block body %}
<div id="wrapper">
<div id="container">
<div id="welcome">
<h1><span>Welcome to</span> Symfony {{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}</h1>
</div>
<div id="status">
<p>
<svg id="icon-status" width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1671 566q0 40-28 68l-724 724-136 136q-28 28-68 28t-68-28l-136-136-362-362q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 295 656-657q28-28 68-28t68 28l136 136q28 28 28 68z" fill="#759E1A"/></svg>
Your application is now ready. You can start working on it at:
<code>{{ base_dir }}</code>
</p>
</div>
<div id="next">
<h2>What's next?</h2>
<p>
<svg id="icon-book" version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="-12.5 9 64 64" enable-background="new -12.5 9 64 64" xml:space="preserve">
<path fill="#AAA" d="M6.8,40.8c2.4,0.8,4.5-0.7,4.9-2.5c0.2-1.2-0.3-2.1-1.3-3.2l-0.8-0.8c-0.4-0.5-0.6-1.3-0.2-1.9
c0.4-0.5,0.9-0.8,1.8-0.5c1.3,0.4,1.9,1.3,2.9,2.2c-0.4,1.4-0.7,2.9-0.9,4.2l-0.2,1c-0.7,4-1.3,6.2-2.7,7.5
c-0.3,0.3-0.7,0.5-1.3,0.6c-0.3,0-0.4-0.3-0.4-0.3c0-0.3,0.2-0.3,0.3-0.4c0.2-0.1,0.5-0.3,0.4-0.8c0-0.7-0.6-1.3-1.3-1.3
c-0.6,0-1.4,0.6-1.4,1.7s1,1.9,2.4,1.8c0.8,0,2.5-0.3,4.2-2.5c2-2.5,2.5-5.4,2.9-7.4l0.5-2.8c0.3,0,0.5,0.1,0.8,0.1
c2.4,0.1,3.7-1.3,3.7-2.3c0-0.6-0.3-1.2-0.9-1.2c-0.4,0-0.8,0.3-1,0.8c-0.1,0.6,0.8,1.1,0.1,1.5c-0.5,0.3-1.4,0.6-2.7,0.4l0.3-1.3
c0.5-2.6,1-5.7,3.2-5.8c0.2,0,0.8,0,0.8,0.4c0,0.2,0,0.2-0.2,0.5c-0.2,0.3-0.3,0.4-0.2,0.7c0,0.7,0.5,1.1,1.2,1.1
c0.9,0,1.2-1,1.2-1.4c0-1.2-1.2-1.8-2.6-1.8c-1.5,0.1-2.8,0.9-3.7,2.1c-1.1,1.3-1.8,2.9-2.3,4.5c-0.9-0.8-1.6-1.8-3.1-2.3
c-1.1-0.7-2.3-0.5-3.4,0.3c-0.5,0.4-0.8,1-1,1.6c-0.4,1.5,0.4,2.9,0.8,3.4l0.9,1c0.2,0.2,0.6,0.8,0.4,1.5c-0.3,0.8-1.2,1.3-2.1,1
c-0.4-0.2-1-0.5-0.9-0.9c0.1-0.2,0.2-0.3,0.3-0.5s0.1-0.3,0.1-0.3c0.2-0.6-0.1-1.4-0.7-1.6c-0.6-0.2-1.2,0-1.3,0.8
C4.3,38.4,4.7,40,6.8,40.8z M46.1,20.9c0-4.2-3.2-7.5-7.1-7.5h-3.8C34.8,10.8,32.7,9,30.2,9L-2.3,9.1c-2.8,0.1-4.9,2.4-4.9,5.4
L-7,58.6c0,4.8,8.1,13.9,11.6,14.1l34.7-0.1c3.9,0,7-3.4,7-7.6L46.1,20.9z M-0.3,36.4c0-8.6,6.5-15.6,14.5-15.6
c8,0,14.5,7,14.5,15.6S22.1,52,14.2,52C6.1,52-0.3,45-0.3,36.4z M42.1,65.1c0,1.8-1.5,3.1-3.1,3.1H4.6c-0.7,0-3-1.8-4.5-4.4h30.4
c2.8,0,5-2.4,5-5.4V17.9h3.7c1.6,0,2.9,1.4,2.9,3.1V65.1L42.1,65.1z"/>
</svg>
Read the documentation to learn
<a href="http://symfony.com/doc/{{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION')[:3] }}/book/page_creation.html">
How to create your first page in Symfony
</a>
</p>
</div>
</div>
</div>
{% endblock %} {% endblock %}
{% block stylesheets %}
<style>
body { background: #F5F5F5; font: 18px/1.5 sans-serif; }
h1, h2 { line-height: 1.2; margin: 0 0 .5em; }
h1 { font-size: 36px; }
h2 { font-size: 21px; margin-bottom: 1em; }
p { margin: 0 0 1em 0; }
a { color: #0000F0; }
a:hover { text-decoration: none; }
code { background: #F5F5F5; max-width: 100px; padding: 2px 6px; word-wrap: break-word; }
#wrapper { background: #FFF; margin: 1em auto; max-width: 800px; width: 95%; }
#container { padding: 2em; }
#welcome, #status { margin-bottom: 2em; }
#welcome h1 span { display: block; font-size: 75%; }
#icon-status, #icon-book { float: left; height: 64px; margin-right: 1em; margin-top: -4px; width: 64px; }
#icon-book { display: none; }
@media (min-width: 768px) {
#wrapper { width: 80%; margin: 2em auto; }
#icon-book { display: inline-block; }
#status a, #next a { display: block; }
@-webkit-keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
@keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
.sf-toolbar { opacity: 0; -webkit-animation: fade-in 1s .2s forwards; animation: fade-in 1s .2s forwards;}
}
</style>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ dump(part) }}
{{ dump(localPart) }}
<div id="model" style="height: 300px; width: 300px; padding: 5px; display: inline-block"></div>
<img src="{{ part.partImgUrl }}">
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript" src="{{ asset('resources/js/three.js') }}"></script>
<script type="text/javascript" src="{{ asset('resources/js/OrbitControls.js') }}"></script>
<script type="text/javascript" src="{{ asset('resources/js/ModelViewer.js') }}"></script>
<script type="text/javascript">
window.onload = function() {
modelView = new ModelViewer();
modelView.init('model');
{% if localPart.model is defined %}
modelView.loadStl('{{ path('download_model', {'id' : localPart.model.id })}}');
{% endif %}
modelView.render();
};
</script>
{% endblock %}

View File

@ -1,7 +0,0 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ dump(part) }}
{% endblock %}

View File

@ -7,6 +7,11 @@ imports:
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration # http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters: parameters:
locale: en 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: framework:
#esi: ~ #esi: ~
@ -75,4 +80,13 @@ knp_menu:
# if true, enables the helper for PHP templates # if true, enables the helper for PHP templates
templating: false templating: false
# the renderer to use, list is also available by default # the renderer to use, list is also available by default
default_renderer: twig default_renderer: twig
oneup_flysystem:
adapters:
ldraw_adapter:
local:
directory: "%kernel.root_dir%/../var/data/ldraw"
filesystems:
ldraw:
adapter: ldraw_adapter

View File

@ -13,12 +13,16 @@ services:
class: AppBundle\Api\Manager\RebrickableManager class: AppBundle\Api\Manager\RebrickableManager
arguments: ['@client.rebrickable'] arguments: ['@client.rebrickable']
app.collection_service: sevice.collection:
class: AppBundle\Service\CollectionService class: AppBundle\Service\CollectionService
arguments: ['@doctrine.orm.entity_manager', '@manager.brickset','@manager.rebrickable'] arguments: ['@doctrine.orm.entity_manager', '@manager.brickset','@manager.rebrickable']
app.model_loader_service:
class: AppBundle\Service\ModelLoaderService loader.rebrickable:
arguments: ['@doctrine.orm.entity_manager','%kernel.root_dir%/../var/data/LDrawLibrary', '@manager.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: app.form.filter_set:
class: AppBundle\Form\FilterSetType class: AppBundle\Form\FilterSetType

BIN
bin/ldview Normal file

Binary file not shown.

30
bin/php-cs-fixer-hook.sh Normal file
View File

@ -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"

View File

@ -23,11 +23,13 @@
"sensio/framework-extra-bundle": "^3.0.2", "sensio/framework-extra-bundle": "^3.0.2",
"incenteev/composer-parameter-handler": "^2.0", "incenteev/composer-parameter-handler": "^2.0",
"guzzlehttp/guzzle": "^6.2", "guzzlehttp/guzzle": "^6.2",
"knplabs/knp-menu-bundle": "^2.0" "knplabs/knp-menu-bundle": "^2.0",
"oneup/flysystem-bundle": "^1.7"
}, },
"require-dev": { "require-dev": {
"sensio/generator-bundle": "^3.0", "sensio/generator-bundle": "^3.0",
"symfony/phpunit-bridge": "^3.0" "symfony/phpunit-bridge": "^3.0",
"friendsofphp/php-cs-fixer": "^2.0"
}, },
"scripts": { "scripts": {
"symfony-scripts": [ "symfony-scripts": [

418
composer.lock generated
View File

@ -4,8 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "5ce1afc2e13970cdfddedeb899ae01a1", "content-hash": "54b7bfc7ee85ba1c5bb4cd9f7d9cfa60",
"content-hash": "f88eedfb311bae0ebb9f759a2d044707",
"packages": [ "packages": [
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
@ -73,7 +72,7 @@
"docblock", "docblock",
"parser" "parser"
], ],
"time": "2015-08-31 12:32:49" "time": "2015-08-31T12:32:49+00:00"
}, },
{ {
"name": "doctrine/cache", "name": "doctrine/cache",
@ -143,7 +142,7 @@
"cache", "cache",
"caching" "caching"
], ],
"time": "2016-10-29 11:16:17" "time": "2016-10-29T11:16:17+00:00"
}, },
{ {
"name": "doctrine/collections", "name": "doctrine/collections",
@ -209,7 +208,7 @@
"collections", "collections",
"iterator" "iterator"
], ],
"time": "2015-04-14 22:21:58" "time": "2015-04-14T22:21:58+00:00"
}, },
{ {
"name": "doctrine/common", "name": "doctrine/common",
@ -282,7 +281,7 @@
"persistence", "persistence",
"spl" "spl"
], ],
"time": "2016-11-30 16:50:46" "time": "2016-11-30T16:50:46+00:00"
}, },
{ {
"name": "doctrine/dbal", "name": "doctrine/dbal",
@ -353,7 +352,7 @@
"persistence", "persistence",
"queryobject" "queryobject"
], ],
"time": "2016-09-09 19:13:33" "time": "2016-09-09T19:13:33+00:00"
}, },
{ {
"name": "doctrine/doctrine-bundle", "name": "doctrine/doctrine-bundle",
@ -434,7 +433,7 @@
"orm", "orm",
"persistence" "persistence"
], ],
"time": "2016-08-10 15:35:22" "time": "2016-08-10T15:35:22+00:00"
}, },
{ {
"name": "doctrine/doctrine-cache-bundle", "name": "doctrine/doctrine-cache-bundle",
@ -522,7 +521,7 @@
"cache", "cache",
"caching" "caching"
], ],
"time": "2016-01-26 17:28:51" "time": "2016-01-26T17:28:51+00:00"
}, },
{ {
"name": "doctrine/inflector", "name": "doctrine/inflector",
@ -589,7 +588,7 @@
"singularize", "singularize",
"string" "string"
], ],
"time": "2015-11-06 14:35:42" "time": "2015-11-06T14:35:42+00:00"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
@ -643,7 +642,7 @@
"constructor", "constructor",
"instantiate" "instantiate"
], ],
"time": "2015-06-14 21:17:01" "time": "2015-06-14T21:17:01+00:00"
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
@ -697,7 +696,7 @@
"lexer", "lexer",
"parser" "parser"
], ],
"time": "2014-09-09 13:34:57" "time": "2014-09-09T13:34:57+00:00"
}, },
{ {
"name": "doctrine/orm", "name": "doctrine/orm",
@ -773,7 +772,7 @@
"database", "database",
"orm" "orm"
], ],
"time": "2016-12-18 15:42:34" "time": "2016-12-18T15:42:34+00:00"
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
@ -835,7 +834,7 @@
"rest", "rest",
"web service" "web service"
], ],
"time": "2016-10-08 15:01:37" "time": "2016-10-08T15:01:37+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
@ -886,7 +885,7 @@
"keywords": [ "keywords": [
"promise" "promise"
], ],
"time": "2016-12-20 10:07:11" "time": "2016-12-20T10:07:11+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
@ -944,7 +943,7 @@
"stream", "stream",
"uri" "uri"
], ],
"time": "2016-06-24 23:00:38" "time": "2016-06-24T23:00:38+00:00"
}, },
{ {
"name": "incenteev/composer-parameter-handler", "name": "incenteev/composer-parameter-handler",
@ -995,7 +994,7 @@
"keywords": [ "keywords": [
"parameters management" "parameters management"
], ],
"time": "2015-11-10 17:04:01" "time": "2015-11-10T17:04:01+00:00"
}, },
{ {
"name": "jdorn/sql-formatter", "name": "jdorn/sql-formatter",
@ -1045,7 +1044,7 @@
"highlight", "highlight",
"sql" "sql"
], ],
"time": "2014-01-12 16:20:24" "time": "2014-01-12T16:20:24+00:00"
}, },
{ {
"name": "knplabs/knp-menu", "name": "knplabs/knp-menu",
@ -1111,7 +1110,7 @@
"menu", "menu",
"tree" "tree"
], ],
"time": "2016-09-22 07:36:19" "time": "2016-09-22T07:36:19+00:00"
}, },
{ {
"name": "knplabs/knp-menu-bundle", "name": "knplabs/knp-menu-bundle",
@ -1168,7 +1167,90 @@
"keywords": [ "keywords": [
"menu" "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", "name": "monolog/monolog",
@ -1246,7 +1328,86 @@
"logging", "logging",
"psr-3" "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", "name": "paragonie/random_compat",
@ -1294,7 +1455,7 @@
"pseudorandom", "pseudorandom",
"random" "random"
], ],
"time": "2016-11-07 23:38:38" "time": "2016-11-07T23:38:38+00:00"
}, },
{ {
"name": "psr/cache", "name": "psr/cache",
@ -1340,7 +1501,7 @@
"psr", "psr",
"psr-6" "psr-6"
], ],
"time": "2016-08-06 20:24:11" "time": "2016-08-06T20:24:11+00:00"
}, },
{ {
"name": "psr/http-message", "name": "psr/http-message",
@ -1390,7 +1551,7 @@
"request", "request",
"response" "response"
], ],
"time": "2016-08-06 14:39:51" "time": "2016-08-06T14:39:51+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",
@ -1437,7 +1598,7 @@
"psr", "psr",
"psr-3" "psr-3"
], ],
"time": "2016-10-10 12:19:37" "time": "2016-10-10T12:19:37+00:00"
}, },
{ {
"name": "sensio/distribution-bundle", "name": "sensio/distribution-bundle",
@ -1489,7 +1650,7 @@
"configuration", "configuration",
"distribution" "distribution"
], ],
"time": "2016-12-06 07:29:27" "time": "2016-12-06T07:29:27+00:00"
}, },
{ {
"name": "sensio/framework-extra-bundle", "name": "sensio/framework-extra-bundle",
@ -1557,7 +1718,7 @@
"annotations", "annotations",
"controllers" "controllers"
], ],
"time": "2016-12-14 08:30:06" "time": "2016-12-14T08:30:06+00:00"
}, },
{ {
"name": "sensiolabs/security-checker", "name": "sensiolabs/security-checker",
@ -1601,7 +1762,7 @@
} }
], ],
"description": "A security checker for your composer.lock", "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", "name": "swiftmailer/swiftmailer",
@ -1654,7 +1815,7 @@
"mail", "mail",
"mailer" "mailer"
], ],
"time": "2016-11-24 01:01:23" "time": "2016-11-24T01:01:23+00:00"
}, },
{ {
"name": "symfony/monolog-bundle", "name": "symfony/monolog-bundle",
@ -1714,7 +1875,7 @@
"log", "log",
"logging" "logging"
], ],
"time": "2016-11-06 18:54:50" "time": "2016-11-06T18:54:50+00:00"
}, },
{ {
"name": "symfony/polyfill-apcu", "name": "symfony/polyfill-apcu",
@ -1767,7 +1928,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2016-11-14 01:06:16" "time": "2016-11-14T01:06:16+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-icu", "name": "symfony/polyfill-intl-icu",
@ -1825,7 +1986,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2016-11-14 01:06:16" "time": "2016-11-14T01:06:16+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
@ -1884,7 +2045,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2016-11-14 01:06:16" "time": "2016-11-14T01:06:16+00:00"
}, },
{ {
"name": "symfony/polyfill-php56", "name": "symfony/polyfill-php56",
@ -1940,7 +2101,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2016-11-14 01:06:16" "time": "2016-11-14T01:06:16+00:00"
}, },
{ {
"name": "symfony/polyfill-php70", "name": "symfony/polyfill-php70",
@ -1999,7 +2160,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2016-11-14 01:06:16" "time": "2016-11-14T01:06:16+00:00"
}, },
{ {
"name": "symfony/polyfill-util", "name": "symfony/polyfill-util",
@ -2051,7 +2212,7 @@
"polyfill", "polyfill",
"shim" "shim"
], ],
"time": "2016-11-14 01:06:16" "time": "2016-11-14T01:06:16+00:00"
}, },
{ {
"name": "symfony/swiftmailer-bundle", "name": "symfony/swiftmailer-bundle",
@ -2110,7 +2271,7 @@
], ],
"description": "Symfony SwiftmailerBundle", "description": "Symfony SwiftmailerBundle",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2016-12-20 04:44:33" "time": "2016-12-20T04:44:33+00:00"
}, },
{ {
"name": "symfony/symfony", "name": "symfony/symfony",
@ -2252,7 +2413,7 @@
"keywords": [ "keywords": [
"framework" "framework"
], ],
"time": "2016-12-13 13:20:15" "time": "2016-12-13T13:20:15+00:00"
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
@ -2313,10 +2474,127 @@
"keywords": [ "keywords": [
"templating" "templating"
], ],
"time": "2016-12-13 17:28:18" "time": "2016-12-13T17:28:18+00:00"
} }
], ],
"packages-dev": [ "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", "name": "sensio/generator-bundle",
"version": "v3.1.2", "version": "v3.1.2",
@ -2367,7 +2645,7 @@
} }
], ],
"description": "This bundle generates code for you", "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", "name": "symfony/phpunit-bridge",
@ -2425,7 +2703,65 @@
], ],
"description": "Symfony PHPUnit Bridge", "description": "Symfony PHPUnit Bridge",
"homepage": "https://symfony.com", "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": [], "aliases": [],

View File

@ -17,11 +17,32 @@ gulp.task('css', function() {
.pipe(gulp.dest('web/resources/css')); .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() { gulp.task('js', function() {
return gulp.src([ return gulp.src([
'node_modules/jquery/dist/jquery.js', 'node_modules/jquery/dist/jquery.js',
'app/Resources/assets/semantic/dist/semantic.js', 'app/Resources/assets/semantic/dist/semantic.js',
'node_modules//three/build/three.js'
]) ])
.pipe(plugins.concat('main.js')) .pipe(plugins.concat('main.js'))
.pipe(gulp.dest('web/resources/js')); .pipe(gulp.dest('web/resources/js'));

View File

@ -23,7 +23,7 @@ class Brickset extends \SoapClient
/** /**
* @var array The defined classes * @var array The defined classes
*/ */
private static $classmap = array( private static $classmap = [
'sets' => Set::class, 'sets' => Set::class,
'additionalImages' => AdditionalImage::class, 'additionalImages' => AdditionalImage::class,
'instructions' => Instructions::class, 'instructions' => Instructions::class,
@ -31,14 +31,14 @@ class Brickset extends \SoapClient
'themes' => Theme::class, 'themes' => Theme::class,
'subthemes' => Subtheme::class, 'subthemes' => Subtheme::class,
'years' => Year::class, 'years' => Year::class,
); ];
/** /**
* @param string $apikey Brickset API key * @param string $apikey Brickset API key
* @param array $options A array of config values * @param array $options A array of config values
* @param string $wsdl The wsdl file to use * @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; $this->apiKey = $apikey;
@ -238,11 +238,10 @@ class Brickset extends \SoapClient
return false; return false;
} elseif (strpos($response, 'ERROR:') === 0) { } elseif (strpos($response, 'ERROR:') === 0) {
return false; return false;
} else {
$this->userHash = $response;
return true;
} }
$this->userHash = $response;
return true;
} }
/** /**

View File

@ -57,7 +57,7 @@ class Review
/** /**
* Review constructor. * Review constructor.
*/ */
function __construct() public function __construct()
{ {
} }
@ -88,12 +88,11 @@ class Review
{ {
if ($this->datePosted == null) { if ($this->datePosted == null) {
return null; return null;
} else { }
try { try {
return new \DateTime($this->datePosted); return new \DateTime($this->datePosted);
} catch (\Exception $e) { } catch (\Exception $e) {
return null; return null;
}
} }
} }

View File

@ -848,12 +848,11 @@ class Set
{ {
if ($this->lastUpdated == null) { if ($this->lastUpdated == null) {
return null; return null;
} else { }
try { try {
return new \DateTime($this->lastUpdated); return new \DateTime($this->lastUpdated);
} catch (\Exception $e) { } catch (\Exception $e) {
return null; return null;
}
} }
} }

View File

@ -138,6 +138,7 @@ class Part
{ {
$this->name = $name; $this->name = $name;
} }
/** /**
* @return mixed * @return mixed
*/ */
@ -185,6 +186,7 @@ class Part
{ {
$this->category = $category; $this->category = $category;
} }
/** /**
* @return mixed * @return mixed
*/ */
@ -200,6 +202,7 @@ class Part
{ {
$this->colors = $colors; $this->colors = $colors;
} }
/** /**
* @return mixed * @return mixed
*/ */

View File

@ -11,7 +11,7 @@ class Rebrickable
{ {
const BASE_URI = 'https://rebrickable.com/api/'; const BASE_URI = 'https://rebrickable.com/api/';
const FORMAT = 'json'; const FORMAT = 'json';
/** /**
* @var Client * @var Client
*/ */
@ -21,7 +21,7 @@ class Rebrickable
* @var string * @var string
*/ */
private $apiKey; private $apiKey;
/** /**
* RebrickableAPI constructor. * RebrickableAPI constructor.
*/ */
@ -52,13 +52,12 @@ class Rebrickable
throw new LogicException('Invalid API Key'); throw new LogicException('Invalid API Key');
} elseif ($content === 'NOSET' || $content === 'NOPART') { } elseif ($content === 'NOSET' || $content === 'NOPART') {
return null; return null;
} else {
return $content;
} }
} else {
return $content;
}
//TODO //TODO
throw new LogicException($response->getStatusCode()); throw new LogicException($response->getStatusCode());
}
} catch (ConnectException $e) { } catch (ConnectException $e) {
//TODO //TODO
throw new LogicException($e->getMessage()); throw new LogicException($e->getMessage());

View File

@ -2,11 +2,11 @@
namespace AppBundle\Api\Manager; 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\Color;
use AppBundle\Api\Client\Rebrickable\Entity\Part; use AppBundle\Api\Client\Rebrickable\Entity\Part;
use AppBundle\Api\Client\Rebrickable\Entity\Set; 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\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
@ -33,10 +33,10 @@ class RebrickableManager
private function getSerializer() private function getSerializer()
{ {
$encoders = array(new JsonEncoder()); $encoders = [new JsonEncoder()];
$nameConverter = new PartPropertyNameConverter(); $nameConverter = new PartPropertyNameConverter();
$objectNormalizer = new ObjectNormalizer(null, $nameConverter); $objectNormalizer = new ObjectNormalizer(null, $nameConverter);
$normalizers = array($objectNormalizer, new ArrayDenormalizer()); $normalizers = [$objectNormalizer, new ArrayDenormalizer()];
$serializer = new Serializer($normalizers, $encoders); $serializer = new Serializer($normalizers, $encoders);
return $serializer; return $serializer;

View File

@ -0,0 +1,43 @@
<?php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LoadLibraryCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->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());
}
}
}

View File

@ -1,36 +0,0 @@
<?php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LoadRebrickableCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->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());
}
}
}

View File

@ -0,0 +1,187 @@
<?php
namespace AppBundle\Command\Loader;
use AppBundle\Entity\Category;
use AppBundle\Entity\Model;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
use Symfony\Component\Asset\Exception\LogicException;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Process\ProcessBuilder;
class LDrawLoader extends Loader
{
/**
* @var string LDView binary file path
*/
private $ldview;
/**
* @var Filesystem
*/
private $ldraw;
/**
* @var \League\Flysystem\Filesystem
*/
private $dataPath;
private $ldraw_url;
public function __construct($em, $ldview, $dataPath, $ldraw_url)
{
/*
* @var $em EntityManager
* */
$this->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 <CategoryName> <PartDescription>
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 <CategoryName>
elseif (strpos($line, '!CATEGORY ') === 0) {
$category = trim(preg_replace('/^!CATEGORY /', '', $line));
}
// 0 !KEYWORDS <first keyword>, <second keyword>, ..., <last keyword>
elseif (strpos($line, '!KEYWORDS ') === 0) {
$keywords = explode(', ', preg_replace('/^!KEYWORDS /', '', $line));
}
// 0 Name: <Filename>.dat
elseif (strpos($line, 'Name: ') === 0) {
$model->setNumber(preg_replace('/(^Name: )(.*)(.dat)/', '$2', $line));
}
// 0 Author: <Realname> [<Username>]
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);
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace AppBundle\Command\Loader;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Asset\Exception\LogicException;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Debug\Exception\ContextErrorException;
class Loader
{
/**
* @var EntityManager
*/
protected $em;
/**
* @var OutputInterface
*/
protected $output;
/**
* @var ProgressBar
*/
protected $progressBar;
public function setOutput(OutputInterface $output)
{
$this->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;
}
}

View File

@ -1,114 +1,53 @@
<?php <?php
namespace AppBundle\Service; namespace AppBundle\Command\Loader;
use AppBundle\Api\Manager\RebrickableManager; use AppBundle\Api\Manager\RebrickableManager;
use AppBundle\Entity\BuildingKit;
use AppBundle\Entity\Category; use AppBundle\Entity\Category;
use AppBundle\Entity\Color; use AppBundle\Entity\Color;
use AppBundle\Entity\Keyword; use AppBundle\Entity\Keyword;
use AppBundle\Entity\Model;
use AppBundle\Entity\BuildingKit;
use AppBundle\Entity\Part; use AppBundle\Entity\Part;
use AppBundle\Entity\Part_BuildingKit; use AppBundle\Entity\Part_BuildingKit;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Asset\Exception\LogicException;
use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
//TODO Refactor
class ModelLoaderService class RebrickableLoader extends Loader
{ {
private $STLlib;
/**
* @var EntityManager
*/
private $em;
/** /**
* @var RebrickableManager * @var RebrickableManager
*/ */
private $rebrickableManager; private $rebrickableManager;
private $rebrickable_url;
/** /**
* ModelLoaderService constructor. * ModelLoaderService constructor.
*/ */
public function __construct($em, $STLlib, $rebrickableManager) public function __construct($em, $rebrickableManager, $rebrickable_url)
{ {
$this->STLlib = $STLlib;
$this->em = $em; $this->em = $em;
$this->rebrickableManager = $rebrickableManager; $this->rebrickableManager = $rebrickableManager;
$this->rebrickable_url = $rebrickable_url;
} }
// LDraw public function loadPartBuildingKits()
public function loadModels($LDrawLibrary)
{ {
$finder = new Finder(); $this->output->writeln('Downloading set_pieces.csv from Rebrickable.com');
$files = $finder->files()->name('*.dat')->depth('== 0')->in(getcwd().'/'.$LDrawLibrary.'/parts'); $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'); $partRepository = $this->em->getRepository('AppBundle:Part');
$buldingKitRepository = $this->em->getRepository('AppBundle:BuildingKit'); $buldingKitRepository = $this->em->getRepository('AppBundle:BuildingKit');
$colorRepository = $this->em->getRepository('AppBundle:Color'); $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); $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, ','); $header = fgetcsv($handle, 200, ',');
// create a new progress bar (50 units) // 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->setFormat('very_verbose');
$progress->setBarWidth(50); $progress->setBarWidth(50);
$progress->start(); $progress->start();
@ -144,26 +83,26 @@ class ModelLoaderService
$this->em->clear(); $this->em->clear();
fclose($handle); fclose($handle);
$progress->finish(); $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.'); $keywordRepository = $this->em->getRepository('AppBundle:Keyword');
file_put_contents($sets, fopen('compress.zlib://http://rebrickable.com/files/sets.csv.gz', 'r'));
$this->em->getConnection()->getConfiguration()->setSQLLogger(null); $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, ','); $header = fgetcsv($handle, 500, ',');
// create a new progress bar (50 units) // 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->setFormat('very_verbose');
$progress->setBarWidth(50); $progress->setBarWidth(50);
$progress->start(); $progress->start();
@ -206,24 +145,23 @@ class ModelLoaderService
fclose($handle); fclose($handle);
$progress->finish(); $progress->finish();
$progress->clear();
} }
unlink($sets); unlink($file);
} }
public function loadParts($output) public function loadParts()
{ {
$pieces = tempnam(sys_get_temp_dir(), 'printabrick.'); $this->output->writeln('Downloading pieces.csv from Rebrickable.com');
file_put_contents($pieces, fopen('compress.zlib://http://rebrickable.com/files/pieces.csv.gz', 'r')); $file = $this->downloadFile('compress.zlib://'.$this->rebrickable_url['pieces']);
$categoryRepository = $this->em->getRepository('AppBundle:Category'); $categoryRepository = $this->em->getRepository('AppBundle:Category');
$this->em->getConnection()->getConfiguration()->setSQLLogger(null); $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) // 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->setFormat('very_verbose');
$progress->setBarWidth(50); $progress->setBarWidth(50);
$progress->start(); $progress->start();
@ -256,14 +194,15 @@ class ModelLoaderService
fclose($handle); fclose($handle);
$progress->finish(); $progress->finish();
$progress->clear();
} }
unlink($pieces); unlink($file);
} }
public function loadColors() public function loadColors()
{ {
$this->output->writeln('Loading colors into Database');
$rb_colors = $this->rebrickableManager->getColors(); $rb_colors = $this->rebrickableManager->getColors();
foreach ($rb_colors as $rb_color) { foreach ($rb_colors as $rb_color) {
@ -283,10 +222,10 @@ class ModelLoaderService
{ {
$modelRepository = $this->em->getRepository('AppBundle:Model'); $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]]); $model = $modelRepository->findOneBy(['number' => explode('p', $part->getNumber())[0]]);
} else {
$model = $modelRepository->findOneBy(['number' => $part->getNumber()]);
} }
return $model; return $model;

View File

@ -13,9 +13,7 @@ class DefaultController extends Controller
*/ */
public function indexAction(Request $request) public function indexAction(Request $request)
{ {
// replace this example code with whatever you need
return $this->render('default/index.html.twig', [ return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
]); ]);
} }
} }

View File

@ -0,0 +1,43 @@
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Model;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/download")
*/
class DownloadController extends Controller
{
/**
* @Route("/model/{id}", name="download_model")
*
* @return Response
*/
public function modelAction(Model $model)
{
$ldraw_filesystem = $this->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());
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* @Route("/rebrickable/part")
*/
class PartController extends Controller
{
/**
* @Route("/{id}", name="part_detail")
*/
public function detailAction($id)
{
$part = $this->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,
]);
}
}

View File

@ -1,24 +0,0 @@
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
/**
* @Route("rebrickable/parts")
*/
class PartsController extends Controller
{
/**
* @Route("/{id}", name="part_detail")
*/
public function detailAction($id)
{
$part = $this->get('manager.rebrickable')->getPartById($id);
return $this->render('parts/detail.html.twig', [
'part' => $part,
]);
}
}

View File

@ -8,12 +8,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request; 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) 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(), 'form' => $form->createView(),
'sets' => $sets, 'sets' => $sets,
]); ]);
@ -43,13 +43,10 @@ class SetsController extends Controller
*/ */
public function detailAction(Request $request, $id, $name = null) 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('set/detail.html.twig', [
return $this->render('sets/detail.html.twig', [
'set' => $set, 'set' => $set,
'parts' => $parts,
]); ]);
} }
} }

View File

@ -7,7 +7,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* BuildingKit * BuildingKit.
* *
* @ORM\Table(name="building_kit") * @ORM\Table(name="building_kit")
* @ORM\Entity(repositoryClass="AppBundle\Repository\BuildingKitRepository") * @ORM\Entity(repositoryClass="AppBundle\Repository\BuildingKitRepository")
@ -74,9 +74,8 @@ class BuildingKit
$this->keywords = new ArrayCollection(); $this->keywords = new ArrayCollection();
} }
/** /**
* Get id * Get id.
* *
* @return int * @return int
*/ */
@ -105,9 +104,8 @@ class BuildingKit
return $this; return $this;
} }
/** /**
* Set name * Set name.
* *
* @param string $name * @param string $name
* *
@ -121,7 +119,7 @@ class BuildingKit
} }
/** /**
* Get name * Get name.
* *
* @return string * @return string
*/ */
@ -131,9 +129,9 @@ class BuildingKit
} }
/** /**
* Set year * Set year.
* *
* @param integer $year * @param int $year
* *
* @return BuildingKit * @return BuildingKit
*/ */
@ -145,7 +143,7 @@ class BuildingKit
} }
/** /**
* Get year * Get year.
* *
* @return int * @return int
*/ */
@ -175,7 +173,7 @@ class BuildingKit
} }
/** /**
* Get parts * Get parts.
* *
* @return Collection * @return Collection
*/ */
@ -209,7 +207,7 @@ class BuildingKit
} }
/** /**
* Get keywords * Get keywords.
* *
* @return Collection * @return Collection
*/ */

View File

@ -5,10 +5,9 @@ namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Form\CallbackTransformer;
/** /**
* Category * Category.
* *
* @ORM\Table(name="category") * @ORM\Table(name="category")
* @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository") * @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
@ -54,9 +53,8 @@ class Category
$this->parts = new ArrayCollection(); $this->parts = new ArrayCollection();
} }
/** /**
* Get id * Get id.
* *
* @return int * @return int
*/ */
@ -66,7 +64,7 @@ class Category
} }
/** /**
* Set name * Set name.
* *
* @param string $name * @param string $name
* *
@ -80,7 +78,7 @@ class Category
} }
/** /**
* Get name * Get name.
* *
* @return string * @return string
*/ */
@ -90,7 +88,7 @@ class Category
} }
/** /**
* Get models * Get models.
* *
* @return ArrayCollection * @return ArrayCollection
*/ */
@ -124,7 +122,7 @@ class Category
} }
/** /**
* Get parts * Get parts.
* *
* @return ArrayCollection * @return ArrayCollection
*/ */

View File

@ -6,7 +6,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Color * Color.
* *
* @ORM\Table(name="color") * @ORM\Table(name="color")
* @ORM\Entity(repositoryClass="AppBundle\Repository\ColorRepository") * @ORM\Entity(repositoryClass="AppBundle\Repository\ColorRepository")
@ -43,7 +43,7 @@ class Color
private $part_building_kits; private $part_building_kits;
/** /**
* Set id * Set id.
* *
* @var int * @var int
* *
@ -57,7 +57,7 @@ class Color
} }
/** /**
* Get id * Get id.
* *
* @return int * @return int
*/ */
@ -67,7 +67,7 @@ class Color
} }
/** /**
* Set name * Set name.
* *
* @param string $name * @param string $name
* *
@ -81,7 +81,7 @@ class Color
} }
/** /**
* Get name * Get name.
* *
* @return string * @return string
*/ */
@ -91,7 +91,7 @@ class Color
} }
/** /**
* Set rgb * Set rgb.
* *
* @param string $rgb * @param string $rgb
* *
@ -105,7 +105,7 @@ class Color
} }
/** /**
* Get rgb * Get rgb.
* *
* @return string * @return string
*/ */
@ -123,7 +123,6 @@ class Color
} }
/** /**
*
* @param Part_BuildingKit $part_building_kit * @param Part_BuildingKit $part_building_kit
* *
* @return Color * @return Color
@ -148,11 +147,10 @@ class Color
} }
/** /**
* Constructor * Constructor.
*/ */
public function __construct() public function __construct()
{ {
$this->part_building_kits = new \Doctrine\Common\Collections\ArrayCollection(); $this->part_building_kits = new \Doctrine\Common\Collections\ArrayCollection();
} }
} }

View File

@ -6,7 +6,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Keyword * Keyword.
* *
* @ORM\Table(name="keyword") * @ORM\Table(name="keyword")
* @ORM\Entity(repositoryClass="AppBundle\Repository\KeywordRepository") * @ORM\Entity(repositoryClass="AppBundle\Repository\KeywordRepository")
@ -44,9 +44,8 @@ class Keyword
$this->building_kits = new ArrayCollection(); $this->building_kits = new ArrayCollection();
} }
/** /**
* Get id * Get id.
* *
* @return int * @return int
*/ */
@ -56,7 +55,7 @@ class Keyword
} }
/** /**
* Set name * Set name.
* *
* @param string $name * @param string $name
* *
@ -70,7 +69,7 @@ class Keyword
} }
/** /**
* Get name * Get name.
* *
* @return string * @return string
*/ */
@ -110,5 +109,4 @@ class Keyword
return $this; return $this;
} }
} }

View File

@ -6,7 +6,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Model * Model.
* *
* @ORM\Table(name="model") * @ORM\Table(name="model")
* @ORM\Entity(repositoryClass="AppBundle\Repository\ModelRepository") * @ORM\Entity(repositoryClass="AppBundle\Repository\ModelRepository")
@ -22,6 +22,12 @@ class Model
*/ */
private $id; private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
/** /**
* @var string * @var string
* *
@ -53,13 +59,12 @@ class Model
/** /**
* @var Category * @var Category
* *
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models") * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models", cascade={"persist"})
*/ */
private $category; private $category;
/** /**
* Get id * Get id.
* *
* @return int * @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 * @param string $number
* *
@ -83,7 +104,7 @@ class Model
} }
/** /**
* Get number * Get number.
* *
* @return string * @return string
*/ */
@ -93,7 +114,7 @@ class Model
} }
/** /**
* Set author * Set author.
* *
* @param string $author * @param string $author
* *
@ -107,7 +128,7 @@ class Model
} }
/** /**
* Get author * Get author.
* *
* @return string * @return string
*/ */
@ -117,7 +138,7 @@ class Model
} }
/** /**
* Set file * Set file.
* *
* @param string $file * @param string $file
* *
@ -131,7 +152,7 @@ class Model
} }
/** /**
* Get file * Get file.
* *
* @return string * @return string
*/ */
@ -141,7 +162,7 @@ class Model
} }
/** /**
* Get parts * Get parts.
* *
* @return Collection * @return Collection
*/ */
@ -175,7 +196,7 @@ class Model
} }
/** /**
* Set category * Set category.
* *
* @param Category $category * @param Category $category
* *
@ -190,7 +211,7 @@ class Model
} }
/** /**
* Get category * Get category.
* *
* @return Category * @return Category
*/ */

View File

@ -2,11 +2,10 @@
namespace AppBundle\Entity; namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Part_BuildingKit * Part_BuildingKit.
* *
* @ORM\Table(name="part__building_kit") * @ORM\Table(name="part__building_kit")
* @ORM\Entity(repositoryClass="AppBundle\Repository\Part_BuildingKitRepository") * @ORM\Entity(repositoryClass="AppBundle\Repository\Part_BuildingKitRepository")
@ -57,9 +56,8 @@ class Part_BuildingKit
*/ */
private $building_kit; private $building_kit;
/** /**
* Get id * Get id.
* *
* @return int * @return int
*/ */
@ -69,9 +67,9 @@ class Part_BuildingKit
} }
/** /**
* Set count * Set count.
* *
* @param integer $count * @param int $count
* *
* @return Part_BuildingKit * @return Part_BuildingKit
*/ */
@ -83,7 +81,7 @@ class Part_BuildingKit
} }
/** /**
* Get count * Get count.
* *
* @return int * @return int
*/ */
@ -93,7 +91,7 @@ class Part_BuildingKit
} }
/** /**
* Set color * Set color.
* *
* @param Color $color * @param Color $color
* *
@ -107,7 +105,7 @@ class Part_BuildingKit
} }
/** /**
* Get color * Get color.
* *
* @return Color * @return Color
*/ */
@ -117,9 +115,9 @@ class Part_BuildingKit
} }
/** /**
* Set type * Set type.
* *
* @param boolean $type * @param bool $type
* *
* @return Part_BuildingKit * @return Part_BuildingKit
*/ */
@ -131,7 +129,7 @@ class Part_BuildingKit
} }
/** /**
* Get type * Get type.
* *
* @return bool * @return bool
*/ */
@ -181,6 +179,4 @@ class Part_BuildingKit
return $this; return $this;
} }
} }

View File

@ -26,36 +26,35 @@ class FilterSetType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add("theme", ChoiceType::class, [ ->add('theme', ChoiceType::class, [
'choices' => $this->bricksetManager->getThemes(), 'choices' => $this->bricksetManager->getThemes(),
'choice_label' => function(Theme $theme = null) { 'choice_label' => function (Theme $theme = null) {
return $theme ? $theme->getTheme().' ('.$theme->getSetCount().')' : ''; return $theme ? $theme->getTheme().' ('.$theme->getSetCount().')' : '';
}, },
'placeholder' => '', 'placeholder' => '',
'required' => false 'required' => false,
]); ]);
$formModifier = function (Form $form, Theme $theme = null) { $formModifier = function (Form $form, Theme $theme = null) {
$subthemes = null === $theme ? [] : $this->bricksetManager->getSubthemesByTheme($theme); $subthemes = null === $theme ? [] : $this->bricksetManager->getSubthemesByTheme($theme);
$years = null === $theme ? [] : $this->bricksetManager->getYearsByTheme($theme); $years = null === $theme ? [] : $this->bricksetManager->getYearsByTheme($theme);
$form->add("subtheme", ChoiceType::class, [ $form->add('subtheme', ChoiceType::class, [
'choices' => $subthemes, 'choices' => $subthemes,
'choice_label' => function(Subtheme $subtheme = null) { 'choice_label' => function (Subtheme $subtheme = null) {
return $subtheme ? $subtheme->getSubtheme() : ''; return $subtheme ? $subtheme->getSubtheme() : '';
}, },
'placeholder' => '', 'placeholder' => '',
'required' => false 'required' => false,
]); ]);
$form->add("years", ChoiceType::class, [ $form->add('years', ChoiceType::class, [
'choices' => $years, 'choices' => $years,
'choice_label' => function(Year $year = null) { 'choice_label' => function (Year $year = null) {
return $year ? $year->getYear() : ''; return $year ? $year->getYear() : '';
}, },
'placeholder' => '', 'placeholder' => '',
'required' => false 'required' => false,
]); ]);
}; };
@ -76,6 +75,6 @@ class FilterSetType extends AbstractType
} }
); );
$builder->add('submit',SubmitType::class); $builder->add('submit', SubmitType::class);
} }
} }

View File

@ -15,7 +15,7 @@ class Builder
]); ]);
$menu->addChild('Sets', [ $menu->addChild('Sets', [
'route' => 'sets_browse', 'route' => 'set_browse',
]); ]);
return $menu; return $menu;

View File

@ -5,7 +5,7 @@ namespace AppBundle\Repository;
use AppBundle\Entity\Part; use AppBundle\Entity\Part;
/** /**
* BuildingSetRepository * BuildingSetRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.

View File

@ -2,10 +2,8 @@
namespace AppBundle\Repository; namespace AppBundle\Repository;
use AppBundle\Entity\Category;
/** /**
* CategoryRepository * CategoryRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.

View File

@ -3,7 +3,7 @@
namespace AppBundle\Repository; namespace AppBundle\Repository;
/** /**
* ColorRepository * ColorRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.

View File

@ -3,7 +3,7 @@
namespace AppBundle\Repository; namespace AppBundle\Repository;
/** /**
* KeywordRepository * KeywordRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.

View File

@ -3,7 +3,7 @@
namespace AppBundle\Repository; namespace AppBundle\Repository;
/** /**
* ModelRepository * ModelRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.

View File

@ -3,7 +3,7 @@
namespace AppBundle\Repository; namespace AppBundle\Repository;
/** /**
* PartRepository * PartRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.

View File

@ -3,7 +3,7 @@
namespace AppBundle\Repository; namespace AppBundle\Repository;
/** /**
* Part_BuildingKitRepository * Part_BuildingKitRepository.
* *
* This class was generated by the Doctrine ORM. Add your own custom * This class was generated by the Doctrine ORM. Add your own custom
* repository methods below. * repository methods below.