mirror of
https://github.com/ToxicCrack/PrintABrick.git
synced 2025-05-16 20:30:09 -07:00
Merged branch enhance/improve-loader into dev
This commit is contained in:
commit
9eb99a32ea
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,4 +18,5 @@
|
||||
/node_modules/
|
||||
/app/Resources/libs/semantic/dist
|
||||
/web/resources/
|
||||
/web/media/
|
||||
.php_cs.cache
|
@ -29,7 +29,8 @@ For full requirements see Symfony 3.2 [docs](http://symfony.com/doc/3.2/referenc
|
||||
|
||||
#### Database
|
||||
1. Set application parameters in *app/config/parameters.yml*
|
||||
2. Generate empty database by running command `$ php bin/console doctrine:database:create`
|
||||
3. Load LDraw models into database by running commad `$ php bin/console app:load:ldraw [ldraw_dir_path]`
|
||||
2. Generate empty database by running command `$ php bin/console doctrine:database:create`
|
||||
3. Create database tables by running command `$ bin/console doctrine:schema:create`
|
||||
3. Load LDraw models into database by running commad `$ php bin/console app:load:models <ldraw_dir> [--all] [--file=FILE] [--update]`
|
||||
4. Load Rebrickable data into database by running command `$ php bin/console app:load:rebrickable`
|
||||
5. Load relations between LDraw models and Rebrickable parts by running command `$ php bin/console app:load:relation`
|
@ -20,6 +20,7 @@ class AppKernel extends Kernel
|
||||
new Oneup\FlysystemBundle\OneupFlysystemBundle(),
|
||||
new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(),
|
||||
new Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle(),
|
||||
new Liip\ImagineBundle\LiipImagineBundle(),
|
||||
];
|
||||
|
||||
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
|
||||
|
BIN
app/Resources/assets/images/brickset_logo.png
Normal file
BIN
app/Resources/assets/images/brickset_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
app/Resources/assets/images/rebrickable_logo.png
Normal file
BIN
app/Resources/assets/images/rebrickable_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@ -1,85 +1,277 @@
|
||||
ModelViewer = function() {
|
||||
var container;
|
||||
var camera, cameraTarget, scene, renderer, controls, object;
|
||||
var width, height;
|
||||
var ModelViewer = function($dom_element, model_url) {
|
||||
var $this = this;
|
||||
this.container = document.createElement('div');
|
||||
this.container.setAttribute('class','model-view');
|
||||
this.dom_element = $dom_element;
|
||||
$dom_element.append(this.container);
|
||||
|
||||
this.initScene = function($container) {
|
||||
width = parseFloat($container.width());
|
||||
height = parseFloat($container.height());
|
||||
this.camera = null;
|
||||
this.scene = null;
|
||||
this.renderer = null;
|
||||
this.controls = null;
|
||||
this.width = parseFloat($dom_element.width());
|
||||
this.height = parseFloat($dom_element.height());
|
||||
this.scale = 1;
|
||||
this.wireframe = false;
|
||||
this.rendering = false;
|
||||
this.container.style.display = "none";
|
||||
this.toggleButton = null;
|
||||
this.background = 0xffffff;
|
||||
this.model_url = model_url;
|
||||
this.loaded = false;
|
||||
|
||||
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));
|
||||
this.object = null;
|
||||
|
||||
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 );
|
||||
this.initHtml();
|
||||
this.initScene();
|
||||
|
||||
|
||||
scene.add( new THREE.AmbientLight( 0xf0f0f0 ));
|
||||
scene.background = new THREE.Color( 0x000000 );
|
||||
// this.stats = new Stats();
|
||||
// this.stats.dom.style.position = 'absolute';
|
||||
// this.container.append(this.stats.dom);
|
||||
|
||||
// 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.append(renderer.domElement);
|
||||
function renderLoop() {
|
||||
requestAnimationFrame(renderLoop);
|
||||
if($this.rendering) {
|
||||
if(!$this.loaded) {
|
||||
$this.loadStl($this.model_url);
|
||||
$this.loaded = true;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
if($this.stats) {
|
||||
$this.stats.update();
|
||||
}
|
||||
$this.render();
|
||||
}
|
||||
|
||||
$this.resize(parseInt($this.dom_element.width()), parseInt($this.dom_element.height()));
|
||||
}
|
||||
|
||||
|
||||
renderLoop();
|
||||
};
|
||||
|
||||
ModelViewer.prototype.initHtml = function () {
|
||||
$this = this;
|
||||
|
||||
var buttons = document.createElement("div");
|
||||
buttons.setAttribute("class", "modelviewer-buttons");
|
||||
|
||||
this.wireframeButton = $('<button/>', {
|
||||
'class':'model',
|
||||
'style':'display:none',
|
||||
'html':'<i class="eye icon"/>Wireframe',
|
||||
'click': $this.toggleMaterial.bind($this)
|
||||
}).appendTo(buttons);
|
||||
|
||||
this.toggleButton = $('<button/>', {
|
||||
'class':'toggle',
|
||||
'html':'<i class="cube icon"/>3D',
|
||||
'click': $this.toggleRendering.bind($this)
|
||||
}).appendTo(buttons);
|
||||
|
||||
this.dom_element.append(buttons);
|
||||
};
|
||||
|
||||
ModelViewer.prototype.initCamera = function () {
|
||||
this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, .1, 300);
|
||||
this.camera.position.z = 80;
|
||||
this.camera.position.y = -45;
|
||||
this.camera.position.x = 35;
|
||||
this.camera.up = new THREE.Vector3(0, 0, 1);
|
||||
};
|
||||
|
||||
ModelViewer.prototype.initScene = function() {
|
||||
this.scene = new THREE.Scene();
|
||||
this.scene.background = new THREE.Color( this.background );
|
||||
|
||||
this.scene.fog = new THREE.FogExp2(this.background, 0.06);
|
||||
|
||||
this.initLights();
|
||||
this.initCamera();
|
||||
|
||||
var groundPlaneMaterial = new THREE.MeshPhongMaterial({
|
||||
color: 0xFFFFFF,
|
||||
wireframe: false,
|
||||
transparent: true,
|
||||
opacity: 0.25,
|
||||
fog: false,
|
||||
specular: 0x999999,
|
||||
shininess: 100
|
||||
});
|
||||
|
||||
this.plane = new THREE.Mesh(new THREE.PlaneGeometry(80,80), groundPlaneMaterial);
|
||||
this.plane.receiveShadow = true;
|
||||
this.scene.add(this.plane);
|
||||
|
||||
this.grid = new THREE.GridHelper( 80, 100, 0x000000, 0xAAAAAA);
|
||||
this.grid.rotation.x = Math.PI/2;
|
||||
this.scene.add(this.grid);
|
||||
|
||||
this.renderer = new THREE.WebGLRenderer();
|
||||
this.renderer.setSize(this.width, this.height);
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
|
||||
|
||||
this.container.append(this.renderer.domElement);
|
||||
|
||||
this.controls = new THREE.OrbitControls( this.camera, this.renderer.domElement );
|
||||
this.controls.enableZoom = true;
|
||||
};
|
||||
|
||||
ModelViewer.prototype.initLights = function () {
|
||||
this.spotLight = new THREE.SpotLight(0xffffff, 0.8, 0);
|
||||
this.spotLight.position.set(-100, 100, 100);
|
||||
this.spotLight.castShadow = false;
|
||||
this.scene.add(this.spotLight);
|
||||
|
||||
this.bottomSpotLight = new THREE.SpotLight(0xffffff, 0.8, 0);
|
||||
this.bottomSpotLight.position.set(0, -10, -100);
|
||||
this.bottomSpotLight.castShadow = false;
|
||||
this.scene.add(this.bottomSpotLight);
|
||||
|
||||
this.ambientLight = new THREE.AmbientLight(0xffffff, 0.1);
|
||||
this.scene.add(this.ambientLight);
|
||||
|
||||
this.pointLight = new THREE.PointLight(0xfdfdfd, 1, 0);
|
||||
this.pointLight.position.set(32, -39, 35);
|
||||
this.pointLight.castShadow = true;
|
||||
this.scene.add(this.pointLight);
|
||||
};
|
||||
|
||||
ModelViewer.prototype.addModel = function(geometry) {
|
||||
var material = new THREE.MeshPhongMaterial({
|
||||
color: 0x136fc3,
|
||||
specular: 0x0D0D0D,
|
||||
shading: THREE.SmoothShading,
|
||||
shininess: 30,
|
||||
fog: false,
|
||||
side: THREE.DoubleSide,
|
||||
wireframe: this.wireframe,
|
||||
});
|
||||
|
||||
geometry.center();
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.scale.set(this.scale, this.scale, this.scale);
|
||||
|
||||
mesh.geometry.computeFaceNormals();
|
||||
mesh.geometry.computeVertexNormals();
|
||||
mesh.rotation.set(-Math.PI/2,0, 0);
|
||||
mesh.geometry.computeBoundingBox();
|
||||
|
||||
mesh.castShadow = true;
|
||||
// mesh.receiveShadow = true;
|
||||
|
||||
var dims = mesh.geometry.boundingBox.max.clone().sub(mesh.geometry.boundingBox.min);
|
||||
|
||||
maxDim = Math.max(Math.max(dims.x, dims.y), dims.z);
|
||||
|
||||
mesh.position.x = -(mesh.geometry.boundingBox.min.x + mesh.geometry.boundingBox.max.x) / 2 * this.scale;
|
||||
mesh.position.z = -(mesh.geometry.boundingBox.min.y + mesh.geometry.boundingBox.max.y) / 2 * this.scale;
|
||||
mesh.position.y = -mesh.geometry.boundingBox.min.z * this.scale;
|
||||
|
||||
var positionY = (mesh.geometry.boundingBox.max.z + mesh.geometry.boundingBox.min.z)/2 * this.scale;
|
||||
var positionZ = (mesh.geometry.boundingBox.max.y - mesh.geometry.boundingBox.min.y)/2 * this.scale;
|
||||
|
||||
mesh.position.set(0, positionY, positionZ);
|
||||
|
||||
this.object = mesh;
|
||||
|
||||
this.scene.add(mesh);
|
||||
|
||||
this.centerCamera(mesh);
|
||||
};
|
||||
|
||||
ModelViewer.prototype.loadStl = function(model) {
|
||||
var self = this;
|
||||
|
||||
var loader = new THREE.STLLoader();
|
||||
|
||||
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});
|
||||
self.addModel(geometry);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
ModelViewer.prototype.centerCamera = function(mesh) {
|
||||
|
||||
mesh.geometry.computeBoundingBox();
|
||||
var positionY = (mesh.geometry.boundingBox.max.y + mesh.geometry.boundingBox.min.y)/2;
|
||||
var boxHelper = new THREE.BoxHelper( mesh );
|
||||
|
||||
// mesh.position.set(0, positionY, 0);
|
||||
mesh.rotation.set(Math.PI, 0, 0);
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
scene.add(mesh);
|
||||
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
};
|
||||
var sceneCenter = this.objectCenter(mesh);
|
||||
|
||||
this.animate = function() {
|
||||
var geometry = mesh.geometry;
|
||||
|
||||
requestAnimationFrame( this.animate );
|
||||
this.render();
|
||||
};
|
||||
|
||||
this.render = function() {
|
||||
var distanceX = ((geometry.boundingBox.max.x - geometry.boundingBox.min.x) / 2) / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360);
|
||||
var distanceY = (geometry.boundingBox.max.y - geometry.boundingBox.min.y) / 2 / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360);
|
||||
var distanceZ = (geometry.boundingBox.max.z - geometry.boundingBox.min.z) / 2 / Math.tan(this.camera.fov * Math.PI / 360);
|
||||
|
||||
renderer.render(scene, camera);
|
||||
var maxDistance = Math.max(Math.max(distanceX, distanceY), distanceZ);
|
||||
maxDistance *= 1.9 * this.scale;
|
||||
|
||||
};
|
||||
var cameraPosition = this.camera.position.normalize().multiplyScalar(maxDistance);
|
||||
|
||||
this.controls.maxDistance = 3 * maxDistance;
|
||||
|
||||
this.controls.position0 = cameraPosition;
|
||||
this.controls.target0 = sceneCenter;
|
||||
this.controls.reset();
|
||||
};
|
||||
|
||||
ModelViewer.prototype.toggleRendering = function () {
|
||||
if($this.rendering) {
|
||||
$this.container.style.display = "none";
|
||||
$this.rendering = false;
|
||||
$this.toggleButton.html('<i class="cube icon"/>3D');
|
||||
$this.wireframeButton.hide();
|
||||
} else {
|
||||
$this.container.style.display = "block";
|
||||
$this.rendering = true;
|
||||
$this.toggleButton.html('<i class="close icon"/>Close');
|
||||
$this.wireframeButton.show();
|
||||
}
|
||||
};
|
||||
|
||||
ModelViewer.prototype.toggleMaterial = function () {
|
||||
if($this.wireframe) {
|
||||
$this.wireframe = false;
|
||||
$this.wireframeButton.html('<i class="eye icon"/>Wireframe')
|
||||
} else {
|
||||
$this.wireframe = true;
|
||||
$this.wireframeButton.html('<i class="eye icon"/>Solid')
|
||||
}
|
||||
|
||||
this.scene.traverse(function(object) {
|
||||
if (object instanceof THREE.Mesh) {
|
||||
object.material.wireframe = $this.wireframe;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ModelViewer.prototype.objectCenter = function (mesh) {
|
||||
var middle = new THREE.Vector3();
|
||||
var geometry = mesh.geometry;
|
||||
|
||||
geometry.center();
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
middle.x = (geometry.boundingBox.max.x + geometry.boundingBox.min.x) / 2;
|
||||
middle.y = (geometry.boundingBox.max.y + geometry.boundingBox.min.y) / 2;
|
||||
middle.z = (geometry.boundingBox.max.z + geometry.boundingBox.min.z) / 2;
|
||||
|
||||
mesh.localToWorld(middle);
|
||||
return middle;
|
||||
};
|
||||
|
||||
ModelViewer.prototype.resize = function(width, height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.camera.aspect = width / height;
|
||||
this.camera.updateProjectionMatrix();
|
||||
this.renderer.setSize(width, height);
|
||||
};
|
||||
|
||||
ModelViewer.prototype.render = function() {
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
};
|
@ -2,4 +2,27 @@ $(document).ready(function () {
|
||||
$('.ui.dropdown')
|
||||
.dropdown()
|
||||
;
|
||||
|
||||
$('.image.load img')
|
||||
.visibility({
|
||||
type : 'image',
|
||||
transition : 'fade in',
|
||||
duration : 1000
|
||||
})
|
||||
;
|
||||
|
||||
$('.ui.rating')
|
||||
.rating("disable")
|
||||
;
|
||||
|
||||
$('.tabular.menu .item').tab();
|
||||
|
||||
$('.message .close')
|
||||
.on('click', function() {
|
||||
$(this)
|
||||
.closest('.message')
|
||||
.transition('fade')
|
||||
;
|
||||
})
|
||||
;
|
||||
});
|
@ -1,3 +1,43 @@
|
||||
.ui.fixed + .ui.main {
|
||||
margin-top: 5em;
|
||||
.default-theme {
|
||||
|
||||
.ui.fixed + .ui.grid {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.ui.fixed + .ui.main {
|
||||
margin-top: 3em;
|
||||
padding-bottom: 4em;
|
||||
}
|
||||
|
||||
.link {
|
||||
padding-left: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.link:before {
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.link.brickset:before {
|
||||
content: '';
|
||||
background: url("/resources/images/brickset_logo.png");
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.link.rebrickable:before {
|
||||
content: '';
|
||||
background: url("/resources/images/rebrickable_logo.png");
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
}
|
34
app/Resources/assets/style/modelviewer.scss
Normal file
34
app/Resources/assets/style/modelviewer.scss
Normal file
@ -0,0 +1,34 @@
|
||||
.model-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
border: 1px solid #DDDDDD;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modelviewer-buttons {
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 35px;
|
||||
width: 100%;
|
||||
padding: 3px 4px;
|
||||
|
||||
> button {
|
||||
border: none;
|
||||
height: 100%;
|
||||
margin-left: 5px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.model-view {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
@import "variables";
|
||||
|
||||
@import "main";
|
||||
|
||||
@import "modelviewer";
|
||||
|
@ -46,6 +46,8 @@
|
||||
4168950: 3815c01
|
||||
73418: 3815c01
|
||||
|
||||
82359: 3626b
|
||||
|
||||
122c02: 122c01
|
||||
|
||||
# Bucket 1 x 1 x 1 Cylindrical
|
||||
@ -119,6 +121,22 @@ u9147p01c06: u9147p01c02
|
||||
u9147p02c02: u9147p01c02
|
||||
u9147p03c02: u9147p01c02
|
||||
|
||||
# Figure Fabuland Monkey
|
||||
u595p01c08: u595p01c04
|
||||
u595p01c07: u595p01c04
|
||||
u595p01c06: u595p01c04
|
||||
u595p01c05: u595p01c04
|
||||
|
||||
# Figure Fabuland Monkey Head
|
||||
u595p02c03: u595p02c02
|
||||
|
||||
# Figure Fabuland Monkey 2
|
||||
u595p02c05: u595p02c04
|
||||
|
||||
# Figure Fabuland Mouse 1
|
||||
u9105p01c06: u9105p01c02
|
||||
u9105p01c03: u9105p01c02
|
||||
|
||||
# Figure Fabuland Elephant Head
|
||||
u588p02c02: u588p01c02
|
||||
|
||||
@ -164,4 +182,39 @@ u588p02c02: u588p01c02
|
||||
|
||||
# Hinge Control Stick and Base
|
||||
73587: 4592c01
|
||||
4296152: 4592c01
|
||||
4296152: 4592c01
|
||||
|
||||
4505: 4505a
|
||||
6093: 6093a
|
||||
|
||||
90462a: 90462
|
||||
|
||||
# Minifig Mechanical SW Battle Droid
|
||||
30375cs1: 30375cs0
|
||||
30375cs2: 30375cs0
|
||||
30375cs3: 30375cs0
|
||||
|
||||
2958c01: 2723
|
||||
|
||||
32181c03: 32181c01
|
||||
|
||||
76019: 76244
|
||||
4107539: 76244
|
||||
|
||||
3680c02: 3680c01
|
||||
4221774: 3680c01
|
||||
9245: 3680c01
|
||||
9246: 3680c01
|
||||
9258: 3680c01
|
||||
9328: 3680c01
|
||||
9352: 3680c01
|
||||
|
||||
4508c01: 251c01
|
||||
|
||||
4100338: 2557c01
|
||||
4100340: 6051c01
|
||||
|
||||
4100339: 2559c01
|
||||
75192: 2977c01
|
||||
|
||||
4539364: 64776
|
@ -89,7 +89,6 @@
|
||||
10119: 51704
|
||||
3149: 3149d
|
||||
75998: 4493c00
|
||||
10119: 51704
|
||||
30658: 3404
|
||||
|
||||
59275: 2599
|
||||
@ -153,4 +152,59 @@ wheel2a: 568c01
|
||||
11895pr0001c01: 11895
|
||||
92456pr0021c01: 92241p03c01
|
||||
|
||||
15672: 92946
|
||||
15672: 92946
|
||||
|
||||
3614a: 3614
|
||||
3614b: 3614
|
||||
|
||||
75215: 4694c01
|
||||
|
||||
6093: 6093a
|
||||
|
||||
3626bpr0895: 82359
|
||||
|
||||
6272c01: 6272
|
||||
|
||||
76320: 32181c02
|
||||
|
||||
95292c01: 75348
|
||||
2909c03: 75348
|
||||
2909c02: 75348
|
||||
|
||||
# Technic figures
|
||||
tech001: 2698c01
|
||||
tech002: 2698c01
|
||||
tech003: 2698c01
|
||||
tech004: 2698c01
|
||||
tech005: 2698c01
|
||||
tech006: 2698c01
|
||||
tech007: 2698c01
|
||||
tech008: 2698c01
|
||||
tech009: 2698c01
|
||||
tech010: 2698c01
|
||||
tech011: 2698c01
|
||||
tech011a: 2698c01
|
||||
tech012: 2698c01
|
||||
tech013: 2698c01
|
||||
tech014: 2698c01
|
||||
tech014a: 2698c01
|
||||
tech015: 2698c01
|
||||
tech016: 2698c01
|
||||
tech016a: 2698c01
|
||||
tech017: 2698c01
|
||||
tech017a: 2698c01
|
||||
tech018: 2698c01
|
||||
tech019: 2698c01
|
||||
tech020: 2698c01
|
||||
tech021: 2698c01
|
||||
tech022: 2698c01
|
||||
tech023: 2698c01
|
||||
tech024: 2698c01
|
||||
tech025: 2698c01
|
||||
tech026: 2698c01
|
||||
tech027: 2698c01
|
||||
tech028: 2698c01
|
||||
tech029: 2698c01
|
||||
|
||||
33299a: 33299
|
||||
33299b: 33299
|
@ -1,40 +1,48 @@
|
||||
{% extends 'html.html.twig' %}
|
||||
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="{{ asset('resources/css/main.css') }}">
|
||||
{% endblock %}
|
||||
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}
|
||||
<div class="ui fixed inverted menu">
|
||||
{{ knp_menu_render('mainMenu') }}
|
||||
{% block body %}
|
||||
<div class="ui fixed inverted menu">
|
||||
{{ knp_menu_render('mainMenu') }}
|
||||
</div>
|
||||
{% block page %}
|
||||
<div class="ui main">
|
||||
<div class="ui container">
|
||||
<div class="ui masthead vertical segment">
|
||||
<div class="introduction">
|
||||
<div class="ui small breadcrumb">
|
||||
{% for breadcrumb_item in knp_menu_get_breadcrumbs_array(knp_menu_get_current_item('mainMenu')) %}
|
||||
{% if not loop.last %}
|
||||
<a class="section" href="{{ breadcrumb_item.uri }}">{{ breadcrumb_item.label }}</a>
|
||||
<i class="right chevron icon divider"></i>
|
||||
{% else %}
|
||||
<a class="active section">{{ breadcrumb_item.label }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h1 class="ui header">{% block header %}{% endblock %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui vertical segment content">
|
||||
{% for label, flashes in app.session.flashbag.all %}
|
||||
{% for flash in flashes %}
|
||||
{{ elements.flash(label,flash) }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui main container">
|
||||
{% for label, flashes in app.session.flashbag.all %}
|
||||
{% for flash in flashes %}
|
||||
{{ elements.flash(label,flash) }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% block content %}
|
||||
</div>
|
||||
{% endblock page %}
|
||||
<div class="ui black inverted vertical footer segment stripe">
|
||||
{% block footer %}
|
||||
<div class="ui center aligned container">
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script type="text/javascript" src="{{ asset('resources/js/three.js') }}"></script>
|
||||
|
||||
<script type="text/javascript" src="{{ asset('resources/js/OrbitControls.js') }}"></script>
|
||||
|
||||
|
||||
<script src="{{ asset('resources/js/main.js') }}"></script>
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
@ -14,12 +14,14 @@
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
|
||||
<h3>{{ sets|length }}</h3>
|
||||
|
||||
<div class="ui seven column grid">
|
||||
<div class="row">
|
||||
{% for set in sets %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.number~'-'~set.numberVariant, 'name' : set.name|escape('url') }) }}">
|
||||
<img style="width: 100%" src="{{ set.largeThumbnailURL }}">
|
||||
<img style="width: 100%" src="{{ set.legoSetID|setImage|imagine_filter('rebrickable_set_min') }}">
|
||||
<p>{{ set.LegoSetID }} - {{ set.name }}</p>
|
||||
</a>
|
||||
</div>
|
||||
|
9
app/Resources/views/brickset/images.html.twig
Normal file
9
app/Resources/views/brickset/images.html.twig
Normal file
@ -0,0 +1,9 @@
|
||||
<div class="ui six doubling cards">
|
||||
{% for image in images %}
|
||||
<div class="card">
|
||||
<a class="ui bordered fluid image" href="{{ image.imageURL }}" data-lightbox="setImages">
|
||||
<img src="{{ image.thumbnailURL }}">
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
30
app/Resources/views/brickset/instructions.html.twig
Normal file
30
app/Resources/views/brickset/instructions.html.twig
Normal file
@ -0,0 +1,30 @@
|
||||
{% import 'macros/utils.html.twig' as utils %}
|
||||
|
||||
{% if instructions|length != 0 %}
|
||||
<p>
|
||||
{{ 'set.instructions.text' | trans }}
|
||||
</p>
|
||||
|
||||
<table class="ui celled padded table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'set.instructions.description' | trans }}</th>
|
||||
<th>{{ 'set.instructions.filesize' | trans }}</th>
|
||||
<th>{{ 'set.instructions.filename' | trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instruction in instructions %}
|
||||
<tr>
|
||||
<td>{{ instruction.description }}</td>
|
||||
<td>{{ utils.bytesToSize( remoteSize(instruction.uRL)) }}</td>
|
||||
<td><a href="{{ instruction.uRL }}">{{ remoteFilename(instruction.uRL) }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<h2 class="ui center aligned icon">
|
||||
<i class="circular warning icon"></i>
|
||||
</h2>
|
||||
{% endif %}
|
26
app/Resources/views/brickset/reviews.html.twig
Normal file
26
app/Resources/views/brickset/reviews.html.twig
Normal file
@ -0,0 +1,26 @@
|
||||
<div class="ui comments">
|
||||
{% for review in reviews %}
|
||||
<div class="comment">
|
||||
<a class="avatar">
|
||||
{#<img src="/images/avatar/small/matt.jpg">#}
|
||||
</a>
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<h4>{{ review.title }}</h4>
|
||||
</div>
|
||||
<span class="author">{{ review.author }}</span> {{ review.hTML }}
|
||||
<div class="metadata">
|
||||
<span class="date">{{ review.datePosted|date("Y.m.d H:m:i")}}</span>
|
||||
|
||||
</div>
|
||||
<div class="text">
|
||||
{{ review.review|raw }}
|
||||
</div>
|
||||
<div>
|
||||
Overall rating <div class="ui star rating" data-rating="{{ review.overallRating }}" data-max-rating="5"></div>
|
||||
{#Value for money <div class="ui star rating" data-rating="{{ review.valueForMoney }}" data-max-rating="5"></div>#}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
@ -1,6 +1,14 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block page %}
|
||||
<div class="ui grid massive message vertical">
|
||||
<div class="ui container">
|
||||
<div class="row">
|
||||
<div class="h1 ui huge header">
|
||||
Hello, world!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -3,9 +3,9 @@
|
||||
{% block title %}{{ 'page.error.title'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="ui center aligned icon header">
|
||||
<h1 class="ui center aligned icon header">
|
||||
<i class="circular warning icon"></i>
|
||||
{{ 'page.error.large'|trans }}
|
||||
</h2>
|
||||
</h1>
|
||||
<p class="ui center aligned">{{ 'page.error.text'|trans }}</p>
|
||||
{% endblock %}
|
25
app/Resources/views/html.html.twig
Normal file
25
app/Resources/views/html.html.twig
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>{% block title %}PrintABrick{% endblock %}</title>
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="{{ asset('resources/css/main.css') }}">
|
||||
{% endblock %}
|
||||
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
|
||||
</head>
|
||||
<body class="default-theme">
|
||||
{% block body %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script type="text/javascript" src="{{ asset('resources/js/three.js') }}"></script>
|
||||
|
||||
<script type="text/javascript" src="{{ asset('resources/js/OrbitControls.js') }}"></script>
|
||||
|
||||
<script src="{{ asset('resources/js/main.js') }}"></script>
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
@ -1,85 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block content %}
|
||||
{% if model %}
|
||||
<dl>
|
||||
<dt>number:</dt><dd>{{ model.number }}</dd>
|
||||
<dt>name:</dt><dd>{{ model.name }}</dd>
|
||||
<dt>category:</dt><dd>{{ model.category ? model.category.name }}</dd>
|
||||
<dt>type:</dt><dd>{{ model.type ? model.type.name }}</dd>
|
||||
<dt>model:</dt><dd>{{ model.path }}</dd>
|
||||
<dt>author:</dt><dd>{{ model.author }}</dd>
|
||||
<dt>keywords:</dt>
|
||||
<dd>
|
||||
{% for keyword in model.keywords %}
|
||||
<span class="ui label">{{ keyword.name }}</span>
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dt>aliases:</dt>
|
||||
<dd>
|
||||
{% for alias in model.aliases %}
|
||||
<span class="ui label">{{ alias.number }}</span>
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dd>Download:</dd>
|
||||
<dt><a href="{{ path('model_stl', {'number' : model.number })}}">{{ model.number }}</a></dt>
|
||||
<dt>rebrickable parts ({{ rbParts|length }}):</dt>
|
||||
<dd>
|
||||
<p>
|
||||
<div class="ui eight doubling cards">
|
||||
{% for alias in rbParts %}
|
||||
<a href="{{ url('rebrickable_part_show', {number:alias.number}) }}" class="ui label">{{ alias.number }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</p>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
{% endif %}
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap">
|
||||
<div id="model" style="height: 300px; width: 300px; padding: 5px; display: inline-block"></div>
|
||||
<div style="height: 300px; width: 300px; padding: 5px; display: inline-block">
|
||||
<img src="{{ url('model_image', {'number': model.number}) }}" style="max-height: 90%; max-width: 100%">
|
||||
</div>
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="puzzle icon"></i> Subparts of this model
|
||||
</h4>
|
||||
|
||||
{% for subpart in model.subparts %}
|
||||
{{ elements.part(subpart.subpart) }}
|
||||
{% endfor %}
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="cube icon"></i> Model is subpart of
|
||||
</h4>
|
||||
|
||||
{% for subpart in model.parents %}
|
||||
{{ elements.part(subpart.parent) }}
|
||||
{% endfor %}
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="cubes icon"></i> Sets ({{ sets|length }})
|
||||
</h4>
|
||||
|
||||
{% for set in sets %}
|
||||
<span style="margin: 5px"><a href="{{ url('set_detail', {number:set.number}) }}">{{ set.number }}</a></span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
modelView = new ModelViewer();
|
||||
var scene = modelView.initScene($('#model'));
|
||||
modelView.loadStl('{{ path('model_stl', {'number' : model.number })}}');
|
||||
modelView.render();
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
@ -1,7 +1,13 @@
|
||||
{% macro part(model) %}
|
||||
<div style="height: 100px; width: 100px; padding: 5px; display: inline-block;">
|
||||
<img src="{{ url('model_image', {'number': model.number }) }}" style="max-height: 90%; max-width: 100%;">
|
||||
<p><a href="{{ url('model_detail', {'number': model.number}) }}">{{ model.number }}</a></p>
|
||||
<div class="column">
|
||||
<div class="ui bordered fluid image">
|
||||
<a href="{{ url('model_detail', {'number': model.number})}}">
|
||||
<div class="image">
|
||||
<img src="{{ asset('/ldraw/images/'~model.number~'.png') | imagine_filter('model_min') }}" data-src="{{ asset('/ldraw/images/'~model.number~'.png') | imagine_filter('model_min') }}" class="transition visible">
|
||||
</div>
|
||||
<div class="ui bottom attached label {% if model.parts|length == 0 %}black{% endif %}">{{ model.number }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
21
app/Resources/views/macros/utils.html.twig
Normal file
21
app/Resources/views/macros/utils.html.twig
Normal file
@ -0,0 +1,21 @@
|
||||
{#http://stackoverflow.com/a/15303004#}
|
||||
{% macro bytesToSize(bytes) %}
|
||||
{% spaceless %}
|
||||
{% set kilobyte = 1024 %}
|
||||
{% set megabyte = kilobyte * 1024 %}
|
||||
{% set gigabyte = megabyte * 1024 %}
|
||||
{% set terabyte = gigabyte * 1024 %}
|
||||
|
||||
{% if bytes < kilobyte %}
|
||||
{{ bytes ~ ' B' }}
|
||||
{% elseif bytes < megabyte %}
|
||||
{{ (bytes / kilobyte)|number_format(2, '.') ~ ' KB' }}
|
||||
{% elseif bytes < gigabyte %}
|
||||
{{ (bytes / megabyte)|number_format(2, '.') ~ ' MB' }}
|
||||
{% elseif bytes < terabyte %}
|
||||
{{ (bytes / gigabyte)|number_format(2, '.') ~ ' GB' }}
|
||||
{% else %}
|
||||
{{ (bytes / terabyte)|number_format(2, '.') ~ ' TB' }}
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
{% endmacro %}
|
122
app/Resources/views/model/detail.html.twig
Normal file
122
app/Resources/views/model/detail.html.twig
Normal file
@ -0,0 +1,122 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block title %}#{{ model.number }} - {{ model.name }}{% endblock %}
|
||||
|
||||
{% block header %}#{{ model.number }} - {{ model.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="ui grid">
|
||||
<div class="column ten wide">
|
||||
<div id="model-viewer" class="model-container">
|
||||
<img src="{{ asset('ldraw/images/'~model.number~'.png') | imagine_filter('model_large')}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="column six wide">
|
||||
<div class="grey">
|
||||
<table>
|
||||
<tr>
|
||||
<th>category</th><td>{{ model.category ? model.category.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>model</th><td>{{ model.path }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>author</th><td>{{ model.author.name }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<dl>
|
||||
<dt>keywords:</dt>
|
||||
<dd>
|
||||
{% for keyword in model.keywords %}
|
||||
<span class="ui label">{{ keyword.name }}</span>
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dt>aliases:</dt>
|
||||
<dd>
|
||||
{% for alias in model.aliases %}
|
||||
<span>{{ alias.number }}</span>{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dd>Download:</dd>
|
||||
<dt><a href="{{ url('media_file', {'path': model.path}) }}">{{ model.number }}</a></dt>
|
||||
<dt>rebrickable parts ({{ rbParts|length }}):</dt>
|
||||
<dd>
|
||||
{#<p>#}
|
||||
{#<div class="ui eight doubling cards">#}
|
||||
{#{% for alias in rbParts %}#}
|
||||
{#<a href="{{ url('reb_part_detail', {number:alias.number}) }}" class="ui label">{{ alias.number }}</a>#}
|
||||
{#{% endfor %}#}
|
||||
{#</div>#}
|
||||
{#</p>#}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
Related Models
|
||||
</h4>
|
||||
|
||||
|
||||
<h5 class="ui horizontal divider header">
|
||||
Subparts of this model
|
||||
</h5>
|
||||
|
||||
<div class="ui eight column grid">
|
||||
{% for subpart in model.subparts %}
|
||||
<div class="column">
|
||||
{{ elements.part(subpart.subpart) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h5 class="ui horizontal divider header">
|
||||
Model is subpart of
|
||||
</h5>
|
||||
|
||||
<div class="ui eight column grid">
|
||||
{% for subpart in model.parents %}
|
||||
<div class="column">
|
||||
{{ elements.part(subpart.parent) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h5 class="ui horizontal divider header">
|
||||
Model pairs with
|
||||
</h5>
|
||||
|
||||
<div class="ui eight column grid">
|
||||
{% for subpart in related %}
|
||||
<div class="column">
|
||||
{{ elements.part(subpart) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="cubes icon"></i> Sets ({{ sets|length }})
|
||||
</h4>
|
||||
|
||||
{% for set in sets %}
|
||||
<span style="margin: 5px"><a href="{{ url('set_detail', {number:set.number}) }}">{{ set.number }}</a></span>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
modelView = new ModelViewer($('#model-viewer'), '{{ url('media_file', {'path': model.path }) }}');
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
@ -2,8 +2,14 @@
|
||||
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block title %}{{ 'page.model.index' | trans }}{% endblock %}
|
||||
|
||||
{% block header %}{{ 'page.model.index' | trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="get" action="." class="ui form">
|
||||
<div class="ui container stackable grid">
|
||||
<div class="column four wide">
|
||||
<form method="get" action="" class="ui form">
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.search) }}
|
||||
@ -16,18 +22,17 @@
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="column twelve wide">
|
||||
{{ knp_pagination_render(models) }}
|
||||
<p>{{ models.getTotalItemCount }}</p>
|
||||
<div class="ui ten column grid">
|
||||
<div class="row">
|
||||
{% for model in models %}
|
||||
<div class="column">
|
||||
{{ elements.part(model) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="ui eight column grid">
|
||||
{% for model in models %}
|
||||
{{ elements.part(model) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{{ knp_pagination_render(models) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -2,7 +2,7 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<table class="ui celled padded table">
|
||||
<table class="ui celled small padded table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
@ -9,28 +9,33 @@
|
||||
<dt>category:</dt><dd>{{ part.category ? part.category.name }}</dd>
|
||||
</dl>
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap">
|
||||
{% if apiPart is not null %}
|
||||
<div style="height: 300px; width: 300px; padding: 5px; display: inline-block">
|
||||
<img src="{{ apiPart.imgUrl }}" style="max-height: 90%; max-width: 100%">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div style="height: 300px; width: 300px; padding: 5px; display: inline-block">
|
||||
<img src="{{ url('model_image', {number:part.number}) }}" style="max-height: 90%; max-width: 100%">
|
||||
</div>
|
||||
|
||||
{% if part.model %}
|
||||
{{ elements.part(part.model) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if apiPart is not null %}
|
||||
<a href="{{ apiPart.url }}">Rebrickable</a>
|
||||
|
||||
<img class="image ui middle" src="{{ apiPart.imgUrl }}" style="max-height: 90%; max-width: 100%">
|
||||
{% endif %}
|
||||
|
||||
{% if part.model %}
|
||||
{{ elements.part(part.model) }}
|
||||
{% endif %}
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="puzzle icon"></i> Sets
|
||||
</h4>
|
||||
|
||||
<div class="ui eight column grid">
|
||||
{% for set in sets %}
|
||||
<span style="margin: 5px"><a href="{{ url('set_detail', {number:set.number}) }}">{{ set.number }}</a></span>
|
||||
<div class="column">
|
||||
<div class="ui fluid bordered image">
|
||||
<a href="{{ url('set_detail', {number:set.number}) }}">
|
||||
<img class="ui bordered image" src="{{ set.number|setImage|imagine_filter('rebrickable_set_min') }}">
|
||||
<div class="ui bottom attached label">{{ set.number }}<br></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div>
|
||||
|
||||
{{ dump(apiPart) }}
|
||||
|
||||
|
25
app/Resources/views/rebrickable/part/index.html.twig
Normal file
25
app/Resources/views/rebrickable/part/index.html.twig
Normal file
@ -0,0 +1,25 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="ui seven column grid">
|
||||
<div class="row">
|
||||
{% for part in parts %}
|
||||
<div class="column">
|
||||
<div class="ui fluid bordered image">
|
||||
<a href="{{ path('reb_part_detail', {number: part.number}) }}">
|
||||
<div class="image load">
|
||||
<img src="{{ part.number|partImage(-1)| imagine_filter('rebrickable_part_min') }}" data-src="{{ part.number|partImage(-1)| imagine_filter('rebrickable_part_min') }}" class="transition visible">
|
||||
</div>
|
||||
<div class="ui bottom attached label {{ part.model == null ? 'black' : 'red'}}">{{ part.number }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{{ parts.getTotalItemCount }}</p>
|
||||
|
||||
{{ knp_pagination_render(parts) }}
|
||||
{% endblock %}
|
@ -1,58 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% if set is not null %}
|
||||
<dl>
|
||||
<dt>number:</dt><dd>{{ set.number }}</dd>
|
||||
<dt>year:</dt><dd>{{ set.year }}</dd>
|
||||
<dt>name:</dt><dd>{{ set.name }}</dd>
|
||||
<dt>theme:</dt><dd>{{ set.theme.name }}</dd>
|
||||
<dt>count of parts:</dt><dd>{{ set.partCount }}</dd>
|
||||
</dl>
|
||||
|
||||
<img class="ui bordered image medium" src="{{ rbset ? rbset.imgUrl }}">
|
||||
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="cubes icon"></i> Parts {{ inventoryParts|length }}
|
||||
</h4>
|
||||
|
||||
<div class="ui eight column grid">
|
||||
{% for inventoryPart in inventoryParts %}
|
||||
<div class="column">
|
||||
<div class="ui fluid image {{ inventoryPart.part.model == null ? 'active dimmer'}}" style="height: 150px;">
|
||||
<a class="ui right red circular label">{{ inventoryPart.quantity }}</a>
|
||||
<a href="{{ path('rebrickable_part_show', {number: inventoryPart.part.number}) }}">
|
||||
<img src="https://rebrickable.com/media/parts/ldraw/{{inventoryPart.color ? inventoryPart.color.id }}/{{ inventoryPart.part.number }}.png">
|
||||
<div style="border-bottom: #{{ inventoryPart.color.rgb }} 5px solid" class="ui bottom attached label">{{ inventoryPart.part.number }}<br>{{ inventoryPart.isSpare ? 'Spare' : 'Regular' }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div>
|
||||
|
||||
|
||||
<h4 class="ui horizontal divider header">
|
||||
<i class="cubes icon"></i> Models {{ parts|length }}
|
||||
</h4>
|
||||
|
||||
<div class="ui eight column grid">
|
||||
{% for part in parts %}
|
||||
<div class="column">
|
||||
<div class="ui bordered fluid image">
|
||||
<a href="{{ path('model_detail', {number: part.number}) }}">
|
||||
<img src="https://rebrickable.com/media/parts/ldraw/-1/{{ part.number }}.png">
|
||||
<div class="ui bottom attached label">{{ part.number }} </div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div>
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
{{ brset ? dump(brset) }}
|
||||
|
||||
|
||||
{% endblock %}
|
@ -1,21 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="ui seven column grid">
|
||||
<div class="row">
|
||||
{% for set in sets %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.number, 'name' : set.name|escape('url') }) }}">
|
||||
|
||||
{#<img style="width: 100%" src="{{ set }}">#}
|
||||
<p>{{ set.number }} - {{ set.name }}</p>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{{ sets.getTotalItemCount }}</p>
|
||||
|
||||
{{ knp_pagination_render(sets) }}
|
||||
{% endblock %}
|
46
app/Resources/views/rebrickable/set/parts.html.twig
Normal file
46
app/Resources/views/rebrickable/set/parts.html.twig
Normal file
@ -0,0 +1,46 @@
|
||||
{% if regularParts|length > 0 %}
|
||||
<h4 class="ui horizontal divider header">
|
||||
Regular parts
|
||||
</h4>
|
||||
|
||||
<div class="ui ten column grid">
|
||||
{% for inventoryPart in regularParts %}
|
||||
{% if inventoryPart.part is defined %}
|
||||
<div class="column">
|
||||
<div class="ui fluid bordered image">
|
||||
<a class="ui right {{ inventoryPart.part.model == null ? 'black' : 'red'}} circular label">{{ inventoryPart.quantity }}</a>
|
||||
<a href="{{ path('reb_part_detail', {number: inventoryPart.part.number}) }}">
|
||||
<div class="image load">
|
||||
<img src="{{ inventoryPart.part.number|partImage(inventoryPart.color.id)| imagine_filter('rebrickable_part_min') }}" data-src="{{ inventoryPart.part.number|partImage(inventoryPart.color.id)| imagine_filter('rebrickable_part_min') }}" class="transition visible">
|
||||
</div>
|
||||
<div style="border-bottom: #{{ inventoryPart.color.rgb }} 5px solid" class="ui bottom attached label">{{ inventoryPart.part.number }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if spareParts|length > 0 %}
|
||||
<h4 class="ui horizontal divider header">
|
||||
Spare parts
|
||||
</h4>
|
||||
<div class="ui ten column grid">
|
||||
{% for inventoryPart in spareParts %}
|
||||
{% if inventoryPart.part is defined %}
|
||||
<div class="column">
|
||||
<div class="ui fluid bordered image">
|
||||
<a class="ui right {{ inventoryPart.part.model == null ? 'black' : 'red'}} circular label">{{ inventoryPart.quantity }}</a>
|
||||
<a href="{{ path('reb_part_detail', {number: inventoryPart.part.number}) }}">
|
||||
<div class="image load">
|
||||
<img src="{{ inventoryPart.part.number|partImage(inventoryPart.color.id)| imagine_filter('rebrickable_part_min') }}" data-src="{{ inventoryPart.part.number|partImage(inventoryPart.color.id)| imagine_filter('rebrickable_part_min') }}" class="transition visible">
|
||||
</div>
|
||||
<div style="border-bottom: #{{ inventoryPart.color.rgb }} 5px solid" class="ui bottom attached label">{{ inventoryPart.part.number }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
16
app/Resources/views/rebrickable/set/sets.html.twig
Normal file
16
app/Resources/views/rebrickable/set/sets.html.twig
Normal file
@ -0,0 +1,16 @@
|
||||
<h4 class="ui horizontal divider header">Sets</h4>
|
||||
<div class="ui seven column grid">
|
||||
<div class="row">
|
||||
{% for set in inventorySets %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.set.number}) }}">
|
||||
<div class="ui bordered image medium">
|
||||
<img src="{{ asset('resources/images/unknown_image.png') }}" data-src="{{ set.set.number|setImage|imagine_filter('rebrickable_set_min') }}" class="transition visible">
|
||||
</div>
|
||||
<p>{{ set.set.number }} - {{ set.set.name }}</p>
|
||||
<p>{{ set.quantity}}</p>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
138
app/Resources/views/set/detail.html.twig
Normal file
138
app/Resources/views/set/detail.html.twig
Normal file
@ -0,0 +1,138 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}{{ rbset ? rbset.number }} {{ rbset ? rbset.name }}{% endblock %}
|
||||
|
||||
{% block header %}{{ rbset ? rbset.number }} {{ rbset ? rbset.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="ui stackable grid">
|
||||
<div class="column nine wide">
|
||||
<div class="image bordered ui big">
|
||||
{% if brset %}
|
||||
<img class="big" src="{{ brset.imageURL }}">
|
||||
{% elseif rbset %}
|
||||
<img class="big" src="{{ rbset.number|setImage|imagine_filter('rebrickable') }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column seven wide">
|
||||
<div class="item-info black ui">
|
||||
<table class="ui table">
|
||||
<tr>
|
||||
<td>number</td><td>{{ brset ? brset.legoSetID : rbset ? rbset.number : null}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name</td><td>{{ brset ? brset.name : rbset ? rbset.name : null}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>year</td><td>{{ brset ? brset.year : rbset ? rbset.year : null}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>theme</td>
|
||||
{% if rbset %}
|
||||
<td><a href="#">{{ rbset.theme.parent ? rbset.theme.parent.name }}</a> <a href="#">{{ rbset.theme.name }}</a> </td>
|
||||
{% elseif brset %}
|
||||
<td>{{ brset.theme }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>parts</td><td>{{ brset ? brset.pieces : rbset ? rbset.partCount }}</td>
|
||||
</tr>
|
||||
{% if brset %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="brickset link" href="{{ brset.bricksetURL }}">Brickset</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if rbset %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="rebrickable link" href="http://rebrickable.com/sets/{{ rbset ? rbset.number }}">Rebrickable</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
{% if brset is not null %}
|
||||
<dl>
|
||||
<dt>themegroup:</dt><dd>{{ brset.themeGroup }}</dd>
|
||||
<dt>theme:</dt><dd>{{ brset.theme }}</dd>
|
||||
<dt>subtheme:</dt><dd>{{ brset.subtheme }}</dd>
|
||||
<dt>count of parts:</dt><dd>{{ brset.pieces }}</dd>
|
||||
<dt>minifigs:</dt><dd>{{ brset.minifigs }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="segment vertical item-info">
|
||||
<div class="ui tabular menu">
|
||||
<a class="item active" data-tab="parts"><i class="cubes icon"></i> Parts ({{ rbset ? rbset.partCount : 0}})</a>
|
||||
{% if brset %}
|
||||
<a class="item" data-tab="description"><i class="info icon"></i> Description</a>
|
||||
<a class="item" data-tab="images"> <i class="image icon"></i> Images ({{ brset.additionalImageCount }})</a>
|
||||
<a class="item" data-tab="instructions"> <i class="file pdf outline icon"></i> Instructions ({{ brset.instructionsCount }})</a>
|
||||
<a class="item" data-tab="reviews"><i class="write icon"></i> Reviews ({{ brset.reviewCount }})</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="ui tab active" data-tab="parts">
|
||||
{% if rbset %}
|
||||
|
||||
<div class="ajax-load" id="parts" data-src="{{ path('rebrickable_set_parts', { 'number': rbset.number }) }}"></div>
|
||||
|
||||
{#{{ render(controller('AppBundle:Rebrickable/Set:parts', { 'number': rbset.number })) }}#}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if brset %}
|
||||
<div class="ui tab" data-tab="images">
|
||||
{#<div class="ajax-load" id="images" data-src="{{ path('brickset_images', { 'id': brset.setID }) }}"></div>#}
|
||||
|
||||
{{ render(controller('AppBundle:Brickset/Set:images', { 'id': brset.setID })) }}
|
||||
</div>
|
||||
<div class="ui tab" data-tab="instructions">
|
||||
{#<div class="ajax-load" id="instructions" data-src="{{ path('brickset_instructions', { 'id': brset.setID }) }}"></div>#}
|
||||
|
||||
{{ render(controller('AppBundle:Brickset/Set:instructions', { 'id': brset.setID })) }}
|
||||
</div>
|
||||
<div class="ui tab" data-tab="reviews">
|
||||
{#<div class="ajax-load" id="reviews" data-src="{{ path('brickset_reviews', { 'id': brset.setID }) }}"></div>#}
|
||||
|
||||
{{ render(controller('AppBundle:Brickset/Set:reviews', { 'id': brset.setID })) }}
|
||||
</div>
|
||||
<div class="ui tab" data-tab="description">
|
||||
{{ brset.description }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('.ajax-load').each(function () {
|
||||
$self = $(this);
|
||||
|
||||
console.log($self);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType: 'json',
|
||||
url: $self.data('src'),
|
||||
async: true, //you won't need that if nothing in your following code is dependend of the result
|
||||
success: function(response){
|
||||
$self.html(response); //Change the html of the div with the id = "your_div"
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
36
app/Resources/views/set/index.html.twig
Normal file
36
app/Resources/views/set/index.html.twig
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="get" action="" class="ui form">
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.search) }}
|
||||
<div class="field fluid search selection">
|
||||
{{ form_label(form.theme.id) }}
|
||||
{{ form_widget(form.theme.id) }}
|
||||
</div>
|
||||
<div class="field">
|
||||
<input class="ui submit button" type="submit" value="filter"/>
|
||||
</div>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
</form>
|
||||
|
||||
<div class="ui seven column grid">
|
||||
<div class="row">
|
||||
{% for set in sets %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.number, 'name' : set.name|escape('url') }) }}">
|
||||
<img class="ui bordered image medium" src="{{ set.number|setImage|imagine_filter('rebrickable_set_min') }}">
|
||||
<p>{{ set.number }} - {{ set.name }}</p>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{{ sets.getTotalItemCount }}</p>
|
||||
|
||||
{{ knp_pagination_render(sets) }}
|
||||
{% endblock %}
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
||||
/** @var ClassLoader $loader */
|
||||
$loader = require __DIR__.'/../vendor/autoload.php';
|
||||
|
2564
app/config/brickset.xml
Normal file
2564
app/config/brickset.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,10 +7,8 @@ imports:
|
||||
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
|
||||
parameters:
|
||||
locale: en
|
||||
# rebrickable csv files root URL
|
||||
rebrickable_url: 'http://rebrickable.com/media/downloads/'
|
||||
# LDraw library zip file URL
|
||||
ldraw_url: 'http://www.ldraw.org/library/updates/complete.zip'
|
||||
# rebrickable csv files root URL (http://rebrickable.com/media/downloads/ or local dir containing csv files)
|
||||
rebrickable_csv_url: 'http://rebrickable.com/media/downloads/'
|
||||
|
||||
framework:
|
||||
#esi: ~
|
||||
@ -92,11 +90,56 @@ knp_paginator:
|
||||
pagination: KnpPaginatorBundle:Pagination:semantic_ui_pagination.html.twig # sliding pagination controls template
|
||||
sortable: KnpPaginatorBundle:Pagination:sortable_link.html.twig # sort link template
|
||||
|
||||
liip_imagine:
|
||||
loaders:
|
||||
media:
|
||||
flysystem:
|
||||
filesystem_service: oneup_flysystem.media_filesystem
|
||||
rebrickable:
|
||||
stream:
|
||||
wrapper: 'http://m.rebrickable.com/media/'
|
||||
|
||||
resolvers:
|
||||
default:
|
||||
web_path: ~
|
||||
|
||||
filter_sets:
|
||||
model_min:
|
||||
data_loader: media
|
||||
cache: ~
|
||||
quality: 80
|
||||
default_image: '/resources/images/unknown_image.png'
|
||||
filters:
|
||||
thumbnail: { size: [200, 200], mode: inset }
|
||||
background: { size: [250, 250], position: center, color: '#FFFFFF' }
|
||||
model_large:
|
||||
data_loader: media
|
||||
cache: ~
|
||||
quality: 92
|
||||
filters:
|
||||
thumbnail: { size: [800, 600], mode: inset }
|
||||
background: { size: [1100, 800], position: center, color: '#FFFFFF' }
|
||||
rebrickable:
|
||||
data_loader: rebrickable
|
||||
rebrickable_part_min:
|
||||
quality: 80
|
||||
data_loader: rebrickable
|
||||
cache: ~
|
||||
default_image: '/resources/images/unknown_image.png'
|
||||
filters:
|
||||
thumbnail: { size: [250, 250], mode: inset }
|
||||
rebrickable_set_min:
|
||||
quality: 80
|
||||
data_loader: rebrickable
|
||||
default_image: '/resources/images/unknown_image.png'
|
||||
cache: ~
|
||||
filters:
|
||||
thumbnail: { size: [250, 250], mode: inset }
|
||||
oneup_flysystem:
|
||||
adapters:
|
||||
media_adapter:
|
||||
media:
|
||||
local:
|
||||
directory: "%kernel.root_dir%/../var/media/"
|
||||
filesystems:
|
||||
media:
|
||||
adapter: media_adapter
|
||||
adapter: media
|
@ -12,15 +12,22 @@ web_profiler:
|
||||
intercept_redirects: false
|
||||
|
||||
monolog:
|
||||
channels: ['loader']
|
||||
handlers:
|
||||
main:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
channels: [!event]
|
||||
channels: [!event, !loader]
|
||||
console:
|
||||
type: console
|
||||
channels: [!event, !doctrine]
|
||||
loader:
|
||||
type: rotating_file
|
||||
path: "%kernel.logs_dir%/loader.log"
|
||||
level: debug
|
||||
channels: 'loader'
|
||||
max_files: 10
|
||||
# uncomment to get logging in your browser
|
||||
# you may have to allow bigger header sizes in your Web server configuration
|
||||
#firephp:
|
||||
|
@ -1,3 +1,5 @@
|
||||
app:
|
||||
resource: "@AppBundle/Controller/"
|
||||
type: annotation
|
||||
_liip_imagine:
|
||||
resource: "@LiipImagineBundle/Resources/config/routing.xml"
|
@ -1,7 +1,7 @@
|
||||
services:
|
||||
api.client.brickset:
|
||||
class: AppBundle\Api\Client\Brickset\Brickset
|
||||
arguments: ['%brickset_apikey%']
|
||||
arguments: ['%brickset_apikey%', '%kernel.root_dir%/config/brickset.xml']
|
||||
api.client.rebrickable:
|
||||
class: AppBundle\Api\Client\Rebrickable\Rebrickable_v3
|
||||
arguments: ['%rebrickable_apikey%']
|
||||
|
@ -1,7 +1,20 @@
|
||||
services:
|
||||
form.filter.category:
|
||||
class: AppBundle\Form\Filter\CategoryFilterType
|
||||
class: AppBundle\Form\Filter\Model\CategoryFilterType
|
||||
arguments:
|
||||
- '@manager.ldraw.category'
|
||||
- '@repository.ldraw.category'
|
||||
tags:
|
||||
- { name: form.type }
|
||||
- { name: form.type }
|
||||
|
||||
form.filter.brickset:
|
||||
class: AppBundle\Form\FilterSetType
|
||||
arguments: ['@api.manager.brickset']
|
||||
tags:
|
||||
- { name: form.type }
|
||||
|
||||
form.filter.theme:
|
||||
class: AppBundle\Form\Filter\Set\ThemeFilterType
|
||||
arguments:
|
||||
- '@repository.rebrickable.theme'
|
||||
tags:
|
||||
- { name: form.type }
|
||||
|
@ -1,29 +1,25 @@
|
||||
services:
|
||||
service.loader:
|
||||
service.loader.base:
|
||||
abstract: true
|
||||
class: AppBundle\Service\Loader\BaseLoaderService
|
||||
class: AppBundle\Service\Loader\BaseLoader
|
||||
calls:
|
||||
- [setArguments, ['@doctrine.orm.entity_manager', '@app.relation.mapper']]
|
||||
- [setArguments, ['@doctrine.orm.entity_manager', '@monolog.logger.loader']]
|
||||
|
||||
service.ldview:
|
||||
class: AppBundle\Service\LDViewService
|
||||
arguments: ['%ldview_bin%', '@oneup_flysystem.media_filesystem']
|
||||
|
||||
service.loader.rebrickable:
|
||||
class: AppBundle\Service\Loader\RebrickableLoaderService
|
||||
arguments: ['%rebrickable_url%']
|
||||
parent: service.loader
|
||||
class: AppBundle\Service\Loader\RebrickableLoader
|
||||
arguments: ['%rebrickable_csv_url%']
|
||||
parent: service.loader.base
|
||||
|
||||
util.dat.parser:
|
||||
class: AppBundle\Utils\DatParser
|
||||
arguments: ['@app.relation.mapper']
|
||||
|
||||
service.loader.ldraw:
|
||||
class: AppBundle\Service\Loader\LDrawLoaderService
|
||||
arguments: ['@service.ldview', '%ldraw_url%', '@manager.ldraw', '@util.dat.parser']
|
||||
parent: service.loader
|
||||
service.loader.model:
|
||||
class: AppBundle\Service\Loader\ModelLoader
|
||||
arguments: ['@service.ldview', '@app.relation.mapper']
|
||||
parent: service.loader.base
|
||||
|
||||
service.loader.relation:
|
||||
class: AppBundle\Service\Loader\RelationLoader
|
||||
arguments: ['@manager.ldraw.model', '@repository.rebrickable.part', '@api.manager.rebrickable']
|
||||
parent: service.loader
|
||||
arguments: ['@api.manager.rebrickable', '@app.relation.mapper']
|
||||
parent: service.loader.base
|
@ -1,28 +1 @@
|
||||
services:
|
||||
manager.ldraw.keyword:
|
||||
class: AppBundle\Manager\LDraw\KeywordManager
|
||||
arguments:
|
||||
- "@repository.ldraw.keyword"
|
||||
manager.ldraw.category:
|
||||
class: AppBundle\Manager\LDraw\CategoryManager
|
||||
arguments:
|
||||
- "@repository.ldraw.category"
|
||||
manager.ldraw.type:
|
||||
class: AppBundle\Manager\LDraw\TypeManager
|
||||
arguments:
|
||||
- "@repository.ldraw.type"
|
||||
manager.ldraw.subpart:
|
||||
class: AppBundle\Manager\LDraw\SubpartManager
|
||||
arguments:
|
||||
- "@repository.ldraw.subpart"
|
||||
manager.ldraw.model:
|
||||
class: AppBundle\Manager\LDraw\ModelManager
|
||||
arguments:
|
||||
- "@repository.ldraw.model"
|
||||
manager.ldraw.alias:
|
||||
class: AppBundle\Manager\LDraw\AliasManager
|
||||
arguments:
|
||||
- "@repository.ldraw.alias"
|
||||
|
||||
|
||||
|
||||
services:
|
@ -41,6 +41,13 @@ services:
|
||||
arguments:
|
||||
- AppBundle\Entity\LDraw\Alias
|
||||
|
||||
repository.ldraw.author:
|
||||
class: Doctrine\ORM\EntityRepository
|
||||
factory: ["@doctrine", getRepository]
|
||||
arguments:
|
||||
- AppBundle\Entity\LDraw\Author
|
||||
|
||||
|
||||
repository.rebrickable.category:
|
||||
class: Doctrine\ORM\EntityRepository
|
||||
factory: ["@doctrine", getRepository]
|
||||
|
@ -1,19 +1,10 @@
|
||||
services:
|
||||
manager.ldraw:
|
||||
class: AppBundle\Manager\LDrawManager
|
||||
arguments:
|
||||
- '@manager.ldraw.category'
|
||||
- '@manager.ldraw.keyword'
|
||||
- '@manager.ldraw.type'
|
||||
- '@manager.ldraw.subpart'
|
||||
- '@manager.ldraw.model'
|
||||
- '@manager.ldraw.alias'
|
||||
|
||||
app.form.filter_set:
|
||||
class: AppBundle\Form\FilterSetType
|
||||
arguments: ['@api.manager.brickset']
|
||||
app.twig_extension:
|
||||
class: AppBundle\Twig\AppExtension
|
||||
public: false
|
||||
arguments: ['@api.manager.rebrickable']
|
||||
tags:
|
||||
- { name: form.type }
|
||||
- { name: twig.extension }
|
||||
|
||||
app.relation.mapper:
|
||||
class: AppBundle\Utils\RelationMapper
|
||||
|
@ -23,10 +23,11 @@
|
||||
"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.1",
|
||||
"oneup/flysystem-bundle": "^1.7",
|
||||
"knplabs/knp-paginator-bundle": "^2.5",
|
||||
"lexik/form-filter-bundle": "~5.0"
|
||||
"lexik/form-filter-bundle": "~5.0",
|
||||
"liip/imagine-bundle": "^1.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"sensio/generator-bundle": "^3.0",
|
||||
|
441
composer.lock
generated
441
composer.lock
generated
@ -4,8 +4,67 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "6956e65252fd75b8d2e258fcc54fa3a9",
|
||||
"content-hash": "6a70240b303126447c6fc3c6f75bf6ff",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/ca-bundle.git",
|
||||
"reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/b17e6153cb7f33c7e44eb59578dc12eee5dc8e12",
|
||||
"reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"php": "^5.3.2 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.5",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/process": "^2.5 || ^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Composer\\CaBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
|
||||
"keywords": [
|
||||
"cabundle",
|
||||
"cacert",
|
||||
"certificate",
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"time": "2017-03-06T11:59:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "v1.2.7",
|
||||
@ -952,6 +1011,63 @@
|
||||
],
|
||||
"time": "2017-03-20T17:10:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "imagine/imagine",
|
||||
"version": "v0.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/avalanche123/Imagine.git",
|
||||
"reference": "149041d2a1b517107bfe270ca2b1a17aa341715d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/avalanche123/Imagine/zipball/149041d2a1b517107bfe270ca2b1a17aa341715d",
|
||||
"reference": "149041d2a1b517107bfe270ca2b1a17aa341715d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"sami/sami": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gd": "to use the GD implementation",
|
||||
"ext-gmagick": "to use the Gmagick implementation",
|
||||
"ext-imagick": "to use the Imagick implementation"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-develop": "0.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Imagine": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bulat Shakirzyanov",
|
||||
"email": "mallluhuct@gmail.com",
|
||||
"homepage": "http://avalanche123.com"
|
||||
}
|
||||
],
|
||||
"description": "Image processing for PHP 5.3",
|
||||
"homepage": "http://imagine.readthedocs.org/",
|
||||
"keywords": [
|
||||
"drawing",
|
||||
"graphics",
|
||||
"image manipulation",
|
||||
"image processing"
|
||||
],
|
||||
"time": "2015-09-19T16:54:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "incenteev/composer-parameter-handler",
|
||||
"version": "v2.1.2",
|
||||
@ -1053,6 +1169,94 @@
|
||||
],
|
||||
"time": "2014-01-12T16:20:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "knplabs/gaufrette",
|
||||
"version": "v0.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/KnpLabs/Gaufrette.git",
|
||||
"reference": "771ad16f4b2e7f9d35f44b201956e83c6fbf5dde"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/KnpLabs/Gaufrette/zipball/771ad16f4b2e7f9d35f44b201956e83c6fbf5dde",
|
||||
"reference": "771ad16f4b2e7f9d35f44b201956e83c6fbf5dde",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4"
|
||||
},
|
||||
"conflict": {
|
||||
"microsoft/windowsazure": "<0.4.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"amazonwebservices/aws-sdk-for-php": "1.5.*",
|
||||
"aws/aws-sdk-php": "^2.4.12",
|
||||
"doctrine/dbal": ">=2.3",
|
||||
"dropbox-php/dropbox-php": "*",
|
||||
"google/apiclient": "~1.1.3",
|
||||
"herzult/php-ssh": "*",
|
||||
"league/flysystem": "~1.0",
|
||||
"mikey179/vfsstream": "~1.2.0",
|
||||
"phpseclib/phpseclib": "^2.0",
|
||||
"phpspec/phpspec": "~2.4",
|
||||
"phpunit/phpunit": "3.7.*",
|
||||
"rackspace/php-opencloud": "^1.9.2"
|
||||
},
|
||||
"suggest": {
|
||||
"amazonwebservices/aws-sdk-for-php": "to use the legacy Amazon S3 adapters",
|
||||
"aws/aws-sdk-php": "to use the Amazon S3 adapter",
|
||||
"doctrine/dbal": "to use the Doctrine DBAL adapter",
|
||||
"dropbox-php/dropbox-php": "to use the Dropbox adapter",
|
||||
"ext-apc": "to use the APC adapter",
|
||||
"ext-curl": "*",
|
||||
"ext-fileinfo": "This extension is used to automatically detect the content-type of a file in the AwsS3, OpenCloud, AzureBlogStorage and GoogleCloudStorage adapters",
|
||||
"ext-mbstring": "*",
|
||||
"ext-mongo": "*",
|
||||
"ext-zip": "to use the Zip adapter",
|
||||
"google/apiclient": "to use GoogleCloudStorage adapter",
|
||||
"herzult/php-ssh": "to use SFtp adapter",
|
||||
"knplabs/knp-gaufrette-bundle": "to use with Symfony2",
|
||||
"league/flysystem": "to use Flysystem adapters",
|
||||
"microsoft/windowsazure": "to use Microsoft Azure Blob Storage adapter",
|
||||
"phpseclib/phpseclib": "to use PhpseclibSftp adapter",
|
||||
"rackspace/php-opencloud": "to use Opencloud adapter"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Gaufrette": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The contributors",
|
||||
"homepage": "http://github.com/knplabs/Gaufrette/contributors"
|
||||
},
|
||||
{
|
||||
"name": "KnpLabs Team",
|
||||
"homepage": "http://knplabs.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP5 library that provides a filesystem abstraction layer",
|
||||
"homepage": "http://knplabs.com",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"file",
|
||||
"filesystem",
|
||||
"media"
|
||||
],
|
||||
"time": "2017-03-20T01:23:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "knplabs/knp-components",
|
||||
"version": "1.3.4",
|
||||
@ -1124,6 +1328,64 @@
|
||||
],
|
||||
"time": "2016-12-06T18:10:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "knplabs/knp-gaufrette-bundle",
|
||||
"version": "v0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/KnpLabs/KnpGaufretteBundle.git",
|
||||
"reference": "06d91a8a575773cd0361c1246c9c499b6bdd5d68"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/KnpLabs/KnpGaufretteBundle/zipball/06d91a8a575773cd0361c1246c9c499b6bdd5d68",
|
||||
"reference": "06d91a8a575773cd0361c1246c9c499b6bdd5d68",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"knplabs/gaufrette": "~0.1.7|~0.2|~0.3",
|
||||
"symfony/framework-bundle": "~2.0|~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2",
|
||||
"symfony/console": "~2.0|~3.0",
|
||||
"symfony/yaml": "~2.0|~3.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Knp\\Bundle\\GaufretteBundle\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The contributors",
|
||||
"homepage": "https://github.com/knplabs/KnpGaufretteBundle/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Antoine Hérault",
|
||||
"email": "antoine.herault@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Allows to easily use the Gaufrette library in a Symfony project",
|
||||
"homepage": "http://knplabs.com",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"file",
|
||||
"filesystem",
|
||||
"media"
|
||||
],
|
||||
"time": "2017-03-16T21:01:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "knplabs/knp-menu",
|
||||
"version": "2.2.0",
|
||||
@ -1394,16 +1656,16 @@
|
||||
},
|
||||
{
|
||||
"name": "lexik/form-filter-bundle",
|
||||
"version": "v5.0.3",
|
||||
"version": "v5.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lexik/LexikFormFilterBundle.git",
|
||||
"reference": "124a6c8e9eb109e7616a18d916bbc33137bb308d"
|
||||
"reference": "28c09d6d9f278875ca9648c4b66eeb457c37d3b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lexik/LexikFormFilterBundle/zipball/124a6c8e9eb109e7616a18d916bbc33137bb308d",
|
||||
"reference": "124a6c8e9eb109e7616a18d916bbc33137bb308d",
|
||||
"url": "https://api.github.com/repos/lexik/LexikFormFilterBundle/zipball/28c09d6d9f278875ca9648c4b66eeb457c37d3b6",
|
||||
"reference": "28c09d6d9f278875ca9648c4b66eeb457c37d3b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1444,13 +1706,113 @@
|
||||
"description": "This bundle aim to provide classes to build some form filters and then build a doctrine query from this form filter.",
|
||||
"homepage": "https://github.com/lexik/LexikFormFilterBundle",
|
||||
"keywords": [
|
||||
"Symfony2",
|
||||
"bundle",
|
||||
"doctrine",
|
||||
"filter",
|
||||
"form"
|
||||
"form",
|
||||
"symfony"
|
||||
],
|
||||
"time": "2017-01-24T13:03:45+00:00"
|
||||
"time": "2017-03-27T07:28:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "liip/imagine-bundle",
|
||||
"version": "1.7.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/liip/LiipImagineBundle.git",
|
||||
"reference": "105dd9c3446e3eb44e33161d4e636a3abafb6d7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/liip/LiipImagineBundle/zipball/105dd9c3446e3eb44e33161d4e636a3abafb6d7f",
|
||||
"reference": "105dd9c3446e3eb44e33161d4e636a3abafb6d7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"imagine/imagine": "^0.6.3,<0.7",
|
||||
"php": "^5.3.9|^7.0",
|
||||
"symfony/asset": "~2.3|~3.0",
|
||||
"symfony/filesystem": "~2.3|~3.0",
|
||||
"symfony/finder": "~2.3|~3.0",
|
||||
"symfony/framework-bundle": "~2.3|~3.0",
|
||||
"symfony/options-resolver": "~2.3|~3.0",
|
||||
"symfony/process": "~2.3|~3.0",
|
||||
"symfony/templating": "~2.3|~3.0",
|
||||
"symfony/translation": "~2.3|~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"amazonwebservices/aws-sdk-for-php": "~1.0",
|
||||
"aws/aws-sdk-php": "~2.4",
|
||||
"doctrine/cache": "~1.1",
|
||||
"doctrine/orm": "~2.3",
|
||||
"ext-gd": "*",
|
||||
"friendsofphp/php-cs-fixer": "~2.0",
|
||||
"phpunit/phpunit": "~4.3|~5.0",
|
||||
"psr/log": "~1.0",
|
||||
"satooshi/php-coveralls": "~1.0",
|
||||
"sllh/php-cs-fixer-styleci-bridge": "~2.1",
|
||||
"symfony/browser-kit": "~2.3|~3.0",
|
||||
"symfony/console": "~2.3|~3.0",
|
||||
"symfony/dependency-injection": "~2.3|~3.0",
|
||||
"symfony/form": "~2.3|~3.0",
|
||||
"symfony/phpunit-bridge": "~2.3|~3.0",
|
||||
"symfony/validator": "~2.3|~3.0",
|
||||
"symfony/yaml": "~2.3|~3.0",
|
||||
"twig/twig": "~1.12|~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"alcaeus/mongo-php-adapter": "required on PHP >= 7.0 to use mongo components with mongodb extension",
|
||||
"amazonwebservices/aws-sdk-for-php": "required to use AWS version 1 cache resolver",
|
||||
"aws/aws-sdk-php": "required to use AWS version 2/3 cache resolver",
|
||||
"doctrine/mongodb-odm": "required to use mongodb-backed doctrine components",
|
||||
"ext-exif": "required to read EXIF metadata from images",
|
||||
"ext-gd": "required to use gd driver",
|
||||
"ext-gmagick": "required to use gmagick driver",
|
||||
"ext-imagick": "required to use imagick driver",
|
||||
"ext-mongo": "required for mongodb components on PHP <7.0",
|
||||
"ext-mongodb": "required for mongodb components on PHP >=7.0",
|
||||
"league/flysystem": "required to use FlySystem data loader or cache resolver",
|
||||
"monolog/monolog": "A psr/log compatible logger is required to enable logging",
|
||||
"twig/twig": "required to use the provided Twig extension. Version 1.12 or greater needed"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-1.0": "1.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Liip\\ImagineBundle\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Liip and other contributors",
|
||||
"homepage": "https://github.com/liip/LiipImagineBundle/contributors"
|
||||
}
|
||||
],
|
||||
"description": "This bundle provides an image manipulation abstraction toolkit for Symfony-based projects.",
|
||||
"homepage": "http://liip.ch",
|
||||
"keywords": [
|
||||
"bundle",
|
||||
"image",
|
||||
"imagine",
|
||||
"liip",
|
||||
"manipulation",
|
||||
"photos",
|
||||
"pictures",
|
||||
"symfony",
|
||||
"transformation"
|
||||
],
|
||||
"time": "2017-03-02T20:18:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
@ -1532,16 +1894,16 @@
|
||||
},
|
||||
{
|
||||
"name": "oneup/flysystem-bundle",
|
||||
"version": "1.11.0",
|
||||
"version": "1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/1up-lab/OneupFlysystemBundle.git",
|
||||
"reference": "a68f83415e3af2313c529be6b22bfddfcfe8e90f"
|
||||
"reference": "2addd1077360790a7722fef09388a003576d585c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/1up-lab/OneupFlysystemBundle/zipball/a68f83415e3af2313c529be6b22bfddfcfe8e90f",
|
||||
"reference": "a68f83415e3af2313c529be6b22bfddfcfe8e90f",
|
||||
"url": "https://api.github.com/repos/1up-lab/OneupFlysystemBundle/zipball/2addd1077360790a7722fef09388a003576d585c",
|
||||
"reference": "2addd1077360790a7722fef09388a003576d585c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1562,6 +1924,7 @@
|
||||
"league/flysystem-ziparchive": "~1.0",
|
||||
"litipk/flysystem-fallback-adapter": "~0.1",
|
||||
"phpunit/phpunit": "^4.4",
|
||||
"superbalist/flysystem-google-storage": "~4.0",
|
||||
"symfony/asset": "~2.0|~3.0",
|
||||
"symfony/browser-kit": "~2.0|~3.0",
|
||||
"symfony/finder": "~2.0|~3.0",
|
||||
@ -1583,6 +1946,7 @@
|
||||
"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",
|
||||
"superbalist/flysystem-google-storage": "Allows you to use Google Cloud Storage buckets",
|
||||
"twistor/flysystem-stream-wrapper": "Allows you to use stream wrapper"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
@ -1611,7 +1975,7 @@
|
||||
"abstraction",
|
||||
"filesystem"
|
||||
],
|
||||
"time": "2017-03-03T13:41:53+00:00"
|
||||
"time": "2017-03-27T08:48:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
@ -1928,19 +2292,20 @@
|
||||
},
|
||||
{
|
||||
"name": "sensiolabs/security-checker",
|
||||
"version": "v4.0.2",
|
||||
"version": "v4.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensiolabs/security-checker.git",
|
||||
"reference": "56bded66985e22f6eac2cf86735fd21c625bff2f"
|
||||
"reference": "9e69eddf3bc49d1ee5c7908564da3141796d4bbc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/56bded66985e22f6eac2cf86735fd21c625bff2f",
|
||||
"reference": "56bded66985e22f6eac2cf86735fd21c625bff2f",
|
||||
"url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/9e69eddf3bc49d1ee5c7908564da3141796d4bbc",
|
||||
"reference": "9e69eddf3bc49d1ee5c7908564da3141796d4bbc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/ca-bundle": "^1.0",
|
||||
"symfony/console": "~2.7|~3.0"
|
||||
},
|
||||
"bin": [
|
||||
@ -1968,7 +2333,7 @@
|
||||
}
|
||||
],
|
||||
"description": "A security checker for your composer.lock",
|
||||
"time": "2017-03-09T17:33:20+00:00"
|
||||
"time": "2017-03-31T14:50:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
@ -2482,16 +2847,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/symfony",
|
||||
"version": "v3.2.6",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/symfony.git",
|
||||
"reference": "b0f8a7fa4b8baadf9db299cb6ac87c96a8977dbe"
|
||||
"reference": "1631040ea8fc5e0e405c00d35cbf2c0b7b555f64"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/symfony/zipball/b0f8a7fa4b8baadf9db299cb6ac87c96a8977dbe",
|
||||
"reference": "b0f8a7fa4b8baadf9db299cb6ac87c96a8977dbe",
|
||||
"url": "https://api.github.com/repos/symfony/symfony/zipball/1631040ea8fc5e0e405c00d35cbf2c0b7b555f64",
|
||||
"reference": "1631040ea8fc5e0e405c00d35cbf2c0b7b555f64",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2622,7 +2987,7 @@
|
||||
"keywords": [
|
||||
"framework"
|
||||
],
|
||||
"time": "2017-03-10T18:35:48+00:00"
|
||||
"time": "2017-04-05T12:52:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
@ -2690,49 +3055,59 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v2.1.2",
|
||||
"version": "v2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
|
||||
"reference": "c7de769d7b44f2c9de68e1f678b65efd8126f60b"
|
||||
"reference": "d6f17423412d33df6b69c9aaf12037b91703533b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/c7de769d7b44f2c9de68e1f678b65efd8126f60b",
|
||||
"reference": "c7de769d7b44f2c9de68e1f678b65efd8126f60b",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/d6f17423412d33df6b69c9aaf12037b91703533b",
|
||||
"reference": "d6f17423412d33df6b69c9aaf12037b91703533b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/annotations": "^1.2",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^5.3.6 || >=7.0 <7.2",
|
||||
"sebastian/diff": "^1.1",
|
||||
"symfony/console": "^2.3 || ^3.0",
|
||||
"symfony/console": "^2.4 || ^3.0",
|
||||
"symfony/event-dispatcher": "^2.1 || ^3.0",
|
||||
"symfony/filesystem": "^2.4 || ^3.0",
|
||||
"symfony/finder": "^2.2 || ^3.0",
|
||||
"symfony/options-resolver": "^2.6 || ^3.0",
|
||||
"symfony/polyfill-php54": "^1.0",
|
||||
"symfony/polyfill-php55": "^1.3",
|
||||
"symfony/polyfill-php70": "^1.0",
|
||||
"symfony/polyfill-xml": "^1.3",
|
||||
"symfony/process": "^2.3 || ^3.0",
|
||||
"symfony/stopwatch": "^2.5 || ^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"hhvm": "<3.9"
|
||||
"hhvm": "<3.18"
|
||||
},
|
||||
"require-dev": {
|
||||
"gecko-packages/gecko-php-unit": "^2.0",
|
||||
"justinrainbow/json-schema": "^5.0",
|
||||
"phpunit/phpunit": "^4.5 || ^5.0",
|
||||
"satooshi/php-coveralls": "^1.0",
|
||||
"symfony/phpunit-bridge": "^3.2"
|
||||
"symfony/phpunit-bridge": "^3.2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-xml": "For better performance."
|
||||
"ext-mbstring": "For handling non-UTF8 characters in cache signature.",
|
||||
"ext-xml": "For better performance.",
|
||||
"symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
|
||||
},
|
||||
"bin": [
|
||||
"php-cs-fixer"
|
||||
],
|
||||
"type": "application",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpCsFixer\\": "src/"
|
||||
@ -2753,7 +3128,7 @@
|
||||
}
|
||||
],
|
||||
"description": "A tool to automatically fix PHP code style",
|
||||
"time": "2017-03-15T17:13:07+00:00"
|
||||
"time": "2017-03-31T16:16:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ircmaxell/password-compat",
|
||||
@ -2905,7 +3280,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/phpunit-bridge",
|
||||
"version": "v3.2.6",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/phpunit-bridge.git",
|
||||
|
23
gulpfile.js
23
gulpfile.js
@ -4,6 +4,7 @@ var gulp = require('gulp'),
|
||||
gulp.task('css', function() {
|
||||
return gulp.src([
|
||||
'node_modules/semantic-ui/dist/semantic.css',
|
||||
'node_modules/lightbox2/dist/css/lightbox.css',
|
||||
'app/Resources/assets/style/style.scss',
|
||||
])
|
||||
.pipe(plugins.sass().on('error', plugins.sass.logError))
|
||||
@ -31,23 +32,35 @@ gulp.task('js', function() {
|
||||
return gulp.src([
|
||||
'node_modules/jquery/dist/jquery.js',
|
||||
'node_modules/semantic-ui/dist/semantic.js',
|
||||
'node_modules/lightbox2/dist/js/lightbox.js',
|
||||
'app/Resources/assets/js/**.js',
|
||||
'node_modules/three/examples/js/libs/stats.min.js'
|
||||
])
|
||||
.pipe(plugins.concat('main.js'))
|
||||
.pipe(gulp.dest('web/resources/js'));
|
||||
});
|
||||
|
||||
gulp.task('files', function () {
|
||||
return gulp.src('node_modules/semantic-ui/dist/themes/**')
|
||||
.pipe(plugins.newer('web/resources/css/themes'))
|
||||
gulp.task('files:semantic', function () {
|
||||
return gulp.src(
|
||||
'node_modules/semantic-ui/dist/themes/**'
|
||||
)
|
||||
.pipe(gulp.dest('web/resources/css/themes'));
|
||||
});
|
||||
|
||||
gulp.task('files:images', function () {
|
||||
return gulp.src([
|
||||
'node_modules/lightbox2/dist/images/**',
|
||||
'app/Resources/assets/images/**'
|
||||
])
|
||||
.pipe(gulp.dest('web/resources/images'));
|
||||
});
|
||||
|
||||
|
||||
gulp.task('watch', ['js', 'css', 'three'], function () {
|
||||
gulp.watch('app/Resources/assets/js/**.js' , ['js']);
|
||||
gulp.watch('app/Resources/assets/style/**/*.sass' , ['css']);
|
||||
gulp.watch('app/Resources/assets/style/**/*.scss' , ['css']);
|
||||
});
|
||||
|
||||
gulp.task('default', function () {
|
||||
return gulp.start(['files', 'js', 'css', 'three']);
|
||||
return gulp.start(['files:semantic', 'files:images', 'js', 'css', 'three']);
|
||||
});
|
@ -11,6 +11,7 @@
|
||||
"gulp-sass": "^2.3.2",
|
||||
"gulp-watch": "^4.3.11",
|
||||
"jquery": "^3.2.1",
|
||||
"lightbox2": "^2.9.0",
|
||||
"semantic-ui": "^2.2.9",
|
||||
"three": "^0.84.0"
|
||||
},
|
||||
|
@ -13,7 +13,6 @@ use AppBundle\Api\Exception\ApiException;
|
||||
use AppBundle\Api\Exception\AuthenticationFailedException;
|
||||
use AppBundle\Api\Exception\CallFailedException;
|
||||
use AppBundle\Api\Exception\EmptyResponseException;
|
||||
use Symfony\Component\Asset\Exception\LogicException;
|
||||
use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
|
||||
class Brickset extends \SoapClient
|
||||
@ -47,6 +46,7 @@ class Brickset extends \SoapClient
|
||||
$this->apiKey = $apikey;
|
||||
|
||||
$options['cache_wsdl'] = WSDL_CACHE_NONE;
|
||||
$options['exceptions'] = true;
|
||||
|
||||
foreach (self::$classmap as $key => $value) {
|
||||
if (!isset($options['classmap'][$key])) {
|
||||
@ -56,7 +56,12 @@ class Brickset extends \SoapClient
|
||||
if (!$wsdl) {
|
||||
$wsdl = self::WSDL;
|
||||
}
|
||||
parent::__construct($wsdl, $options);
|
||||
|
||||
try {
|
||||
parent::__construct($wsdl, $options);
|
||||
} catch (\Exception $exception) {
|
||||
throw new ApiException(ApiException::BRICKSET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,11 +78,14 @@ class Brickset extends \SoapClient
|
||||
|
||||
try {
|
||||
$this->checkApiKey();
|
||||
|
||||
return $this->__soapCall($method, [$parameters])->{$method.'Result'};
|
||||
} catch (\SoapFault $e) {
|
||||
throw new CallFailedException(ApiException::BRICKSET);
|
||||
} catch (ContextErrorException $e) {
|
||||
throw new EmptyResponseException(ApiException::BRICKSET);
|
||||
} catch (\Exception $e) {
|
||||
throw new ApiException(ApiException::BRICKSET);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +113,7 @@ class Brickset extends \SoapClient
|
||||
|
||||
$response = $this->call('getSets', $parameters)->sets;
|
||||
|
||||
return is_array($response) ? $response : [$response];
|
||||
return is_array($response) ? $response : [$this->getSet($response->getSetID())];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,7 +266,7 @@ class Brickset extends \SoapClient
|
||||
{
|
||||
$parameters['apiKey'] = $this->apiKey;
|
||||
|
||||
if($this->__soapCall('checkKey', [$parameters])->checkKeyResult != 'OK') {
|
||||
if ($this->__soapCall('checkKey', [$parameters])->checkKeyResult != 'OK') {
|
||||
throw new AuthenticationFailedException(ApiException::BRICKSET);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ use AppBundle\Api\Exception\EmptyResponseException;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Symfony\Component\Asset\Exception\LogicException;
|
||||
|
||||
class Rebrickable_v3
|
||||
{
|
||||
@ -59,11 +58,11 @@ class Rebrickable_v3
|
||||
} catch (ClientException $e) {
|
||||
if ($e->getCode() == 404) {
|
||||
throw new EmptyResponseException(ApiException::REBRICKABLE);
|
||||
} else if ($e->getCode() == 401) {
|
||||
} elseif ($e->getCode() == 401) {
|
||||
throw new AuthenticationFailedException(ApiException::REBRICKABLE);
|
||||
}
|
||||
|
||||
throw new ApiException(ApiException::REBRICKABLE,$e,$e->getCode());
|
||||
throw new ApiException(ApiException::REBRICKABLE, $e, $e->getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,4 +47,19 @@ class BricksetManager
|
||||
|
||||
return isset($sets[0]) ? $sets[0] : null;
|
||||
}
|
||||
|
||||
public function getSetInstructions($id)
|
||||
{
|
||||
return $this->bricksetClient->getInstructions($id);
|
||||
}
|
||||
|
||||
public function getSetReviews($id)
|
||||
{
|
||||
return $this->bricksetClient->getReviews($id);
|
||||
}
|
||||
|
||||
public function getAdditionalImages($id)
|
||||
{
|
||||
return $this->bricksetClient->getAdditionalImages($id);
|
||||
}
|
||||
}
|
||||
|
@ -119,18 +119,19 @@ class RebrickableManager
|
||||
return $this->serializer->deserialize($data, PartCategory::class, self::FORMAT);
|
||||
}
|
||||
|
||||
public function getPartsByLDrawNumber($number) {
|
||||
public function getPartsByLDrawNumber($number)
|
||||
{
|
||||
$options = [
|
||||
'query' => [
|
||||
'ldraw_id' => $number
|
||||
'ldraw_id' => $number,
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->rebrickableClient->call('GET','lego/parts', $options);
|
||||
$response = $this->rebrickableClient->call('GET', 'lego/parts', $options);
|
||||
|
||||
$data = json_decode($response, true)['results'];
|
||||
|
||||
return $this->serializer->denormalize($data,Part::class.'[]',self::FORMAT);
|
||||
return $this->serializer->denormalize($data, Part::class.'[]', self::FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,39 +0,0 @@
|
||||
<?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 LoadLDRawLibraryCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('app:load:ldraw')
|
||||
->setDescription('Loads LDraw library parts')
|
||||
->setHelp('This command allows you to..')
|
||||
->addArgument('ldraw_path', InputArgument::OPTIONAL, 'Path to LDraw library folder');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$ldrawLoader = $this->getContainer()->get('service.loader.ldraw');
|
||||
$ldrawLoader->setOutput($output);
|
||||
|
||||
//TODO log errors
|
||||
|
||||
try {
|
||||
// TODO handle relative path to dir
|
||||
if (($ldrawPath = $input->getArgument('ldraw_path')) == null) {
|
||||
$ldrawPath = $ldrawLoader->downloadLibrary();
|
||||
}
|
||||
|
||||
$ldrawLoader->loadData($ldrawPath);
|
||||
} catch (\Exception $e) {
|
||||
printf($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
89
src/AppBundle/Command/LoadModelsCommand.php
Normal file
89
src/AppBundle/Command/LoadModelsCommand.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Command\LockableTrait;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class LoadModelsCommand extends ContainerAwareCommand
|
||||
{
|
||||
use LockableTrait;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('app:load:models')
|
||||
->setDescription('Loads LDraw library models into database')
|
||||
->setHelp('This command allows you to load LDraw library models into database while converting .dat files to .stl format.')
|
||||
->setDefinition(
|
||||
new InputDefinition([
|
||||
new InputArgument('ldraw', InputArgument::REQUIRED, 'Path to LDraw library directory'),
|
||||
// new InputOption('images', 'i', InputOption::VALUE_NONE, 'Do you want to generate images of models?'),
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Load all models from LDraw libary folder (/parts directory)'),
|
||||
new InputOption('file', 'f', InputOption::VALUE_REQUIRED, 'Load single modle into database'),
|
||||
new InputOption('update', 'u', InputOption::VALUE_NONE, 'Overwrite already loaded models'),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (!$this->lock()) {
|
||||
$output->writeln('The command is already running in another process.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$modelLoader = $this->getContainer()->get('service.loader.model');
|
||||
$modelLoader->setOutput($output);
|
||||
$modelLoader->setRewite($input->getOption('update'));
|
||||
|
||||
$ldraw = $input->getArgument('ldraw');
|
||||
|
||||
if ($ldrawPath = realpath($ldraw)) {
|
||||
$modelLoader->setLDrawLibraryContext($ldrawPath);
|
||||
|
||||
if (($path = $input->getOption('file')) != null) {
|
||||
if ($file = realpath($path)) {
|
||||
$output->writeln([
|
||||
'Loading model',
|
||||
'path: '.$file,
|
||||
'------------------------------------------------------------------------------',
|
||||
]);
|
||||
|
||||
$modelLoader->loadOneModel($file);
|
||||
|
||||
$errorCount = $this->getContainer()->get('monolog.logger.loader')->countErrors();
|
||||
$errors = $errorCount ? '<error>'.$errorCount.'</error>' : '<info>0</info>';
|
||||
|
||||
$output->writeln(['Done with "'.$errors.'" errors.']);
|
||||
} else {
|
||||
$output->writeln("File $path not found");
|
||||
}
|
||||
}
|
||||
|
||||
// Load all models inside ldraw/parts directory
|
||||
if ($input->getOption('all')) {
|
||||
$output->writeln([
|
||||
'Loading models from LDraw library: <comment>'.$ldrawPath.'</comment>',
|
||||
]);
|
||||
|
||||
$modelLoader->loadAllModels();
|
||||
|
||||
$errorCount = $this->getContainer()->get('monolog.logger.loader')->countErrors();
|
||||
$errors = $errorCount ? '<error>'.$errorCount.'</error>' : '<info>0</info>';
|
||||
|
||||
$output->writeln(['Done with "'.$errors.'" errors.']);
|
||||
}
|
||||
} else {
|
||||
$output->writeln($ldraw.' is not valid path');
|
||||
}
|
||||
|
||||
$this->release();
|
||||
}
|
||||
}
|
@ -12,8 +12,8 @@ class LoadRebrickableDataCommand extends ContainerAwareCommand
|
||||
{
|
||||
$this
|
||||
->setName('app:load:rebrickable')
|
||||
->setDescription('Loads Rebrickable database')
|
||||
->setHelp('This command allows you to..');
|
||||
->setDescription('Loads Rebrickable data about sets and parts into database.')
|
||||
->setHelp('This command allows you to load Rebrickable CSV files containing information about sets and parts into database.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
|
@ -12,8 +12,8 @@ class LoadRelationCommand extends ContainerAwareCommand
|
||||
{
|
||||
$this
|
||||
->setName('app:load:relations')
|
||||
->setDescription('Loads relations between LDraw models and Rebrickable parts')
|
||||
->setHelp('This command allows you to..');
|
||||
->setDescription('Loads relations between LDraw models and Rebrickable parts.')
|
||||
->setHelp('This command allows you to load relation between models and parts into database.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
|
@ -1,10 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\Rebrickable;
|
||||
namespace AppBundle\Controller\Brickset;
|
||||
|
||||
use AppBundle\Entity\Rebrickable\Color;
|
||||
use AppBundle\Entity\Rebrickable\Inventory_Part;
|
||||
use AppBundle\Entity\Rebrickable\Part;
|
||||
use AppBundle\Api\Exception\EmptyResponseException;
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use AppBundle\Entity\Rebrickable\Theme;
|
||||
use AppBundle\Form\FilterSetType;
|
||||
@ -13,12 +11,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @Route("/brickset")
|
||||
* @Route("/brickset/sets")
|
||||
*/
|
||||
class SetController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="set_browse")
|
||||
* @Route("/", name="brickset_browse")
|
||||
*/
|
||||
public function browseAction(Request $request)
|
||||
{
|
||||
@ -30,11 +28,17 @@ class SetController extends Controller
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$data = $form->getData();
|
||||
|
||||
$sets = $this->get('api.client.brickset')->getSets([
|
||||
'theme' => $data['theme'] ? $data['theme']->getTheme() : '',
|
||||
'subtheme' => $data['subtheme'] ? $data['subtheme']->getSubtheme() : '',
|
||||
'year' => $data['years'] ? $data['years']->getYear() : '',
|
||||
]);
|
||||
try {
|
||||
$sets = $this->get('api.client.brickset')->getSets([
|
||||
'theme' => $data['theme'] ? $data['theme']->getTheme() : '',
|
||||
'subtheme' => $data['subtheme'] ? $data['subtheme']->getSubtheme() : '',
|
||||
'year' => $data['years'] ? $data['years']->getYear() : '',
|
||||
]);
|
||||
} catch (EmptyResponseException $e) {
|
||||
$this->addFlash('warning', 'No set found on '.$e->getService());
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('brickset/browse.html.twig', [
|
||||
@ -42,4 +46,61 @@ class SetController extends Controller
|
||||
'sets' => $sets,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/instructions", name="brickset_instructions")
|
||||
*/
|
||||
public function instructionsAction(Request $request, $id)
|
||||
{
|
||||
$instructions = [];
|
||||
try {
|
||||
$instructions = $this->get('api.manager.brickset')->getSetInstructions($id);
|
||||
} catch (EmptyResponseException $e) {
|
||||
// $this->addFlash('warning', 'No instruction found on Brickset.com');
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->render('brickset/instructions.html.twig', [
|
||||
'instructions' => $instructions,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/reviews", name="brickset_reviews")
|
||||
*/
|
||||
public function reviewsAction(Request $request, $id)
|
||||
{
|
||||
$reviews = [];
|
||||
try {
|
||||
$reviews = $this->get('api.manager.brickset')->getSetReviews($id);
|
||||
} catch (EmptyResponseException $e) {
|
||||
// $this->addFlash('warning', 'No review found on Brickset.com');
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->render('brickset/reviews.html.twig', [
|
||||
'reviews' => $reviews,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/images", name="brickset_images")
|
||||
*/
|
||||
public function imagesAction(Request $request, $id)
|
||||
{
|
||||
$images = [];
|
||||
try {
|
||||
$images = $this->get('api.manager.brickset')->getAdditionalImages($id);
|
||||
} catch (EmptyResponseException $e) {
|
||||
// $this->addFlash('warning', 'No images found on Brickset.com');
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->render('brickset/images.html.twig', [
|
||||
'images' => $images,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace AppBundle\Controller;
|
||||
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
|
||||
@ -11,59 +10,33 @@ use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* @Route("/media")
|
||||
* @Route("/files")
|
||||
*/
|
||||
class MediaController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/model/stl/{number}", name="model_stl")
|
||||
* @Route("/{path}", name="media_file", requirements={"path"=".+"})
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function stlAction(Model $model)
|
||||
public function stlAction($path)
|
||||
{
|
||||
$mediaFilesystem = $this->get('oneup_flysystem.media_filesystem');
|
||||
|
||||
if ($mediaFilesystem->has($model->getPath())) {
|
||||
$response = new BinaryFileResponse($mediaFilesystem->getAdapter()->getPathPrefix().DIRECTORY_SEPARATOR.$model->getPath());
|
||||
$response->headers->set('Content-Type', 'application/vnd.ms-pki.stl');
|
||||
if ($mediaFilesystem->has($path)) {
|
||||
$response = new BinaryFileResponse($mediaFilesystem->getAdapter()->getPathPrefix().DIRECTORY_SEPARATOR.$path);
|
||||
$response->headers->set('Content-Type', $mediaFilesystem->getMimetype($path));
|
||||
|
||||
// Create the disposition of the file
|
||||
$disposition = $response->headers->makeDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
$model->getNumber().'.stl'
|
||||
basename($path)
|
||||
);
|
||||
|
||||
$response->headers->set('Content-Disposition', $disposition);
|
||||
|
||||
return $response;
|
||||
}
|
||||
throw new FileNotFoundException($model->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/model/image/{number}", name="model_image")
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function imageAction(Model $model)
|
||||
{
|
||||
$mediaFilesystem = $this->get('oneup_flysystem.media_filesystem');
|
||||
|
||||
if ($mediaFilesystem->has('ldraw'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.$model->getNumber().'.png')) {
|
||||
$response = new BinaryFileResponse($mediaFilesystem->getAdapter()->getPathPrefix().DIRECTORY_SEPARATOR.'ldraw'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.$model->getNumber().'.png');
|
||||
$response->headers->set('Content-Type', 'image/png');
|
||||
|
||||
// Create the disposition of the file
|
||||
$disposition = $response->headers->makeDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
$model->getNumber().'png'
|
||||
);
|
||||
|
||||
$response->headers->set('Content-Disposition', $disposition);
|
||||
|
||||
return $response;
|
||||
}
|
||||
throw new FileNotFoundException($model->getNumber().'png');
|
||||
throw new FileNotFoundException($path);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\LDraw;
|
||||
namespace AppBundle\Controller;
|
||||
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use AppBundle\Entity\Rebrickable\Part;
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use AppBundle\Form\Filter\ModelFilterType;
|
||||
use AppBundle\Form\Filter\Model\ModelFilterType;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
@ -14,24 +14,21 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
/**
|
||||
* Part controller.
|
||||
*
|
||||
* @Route("ldraw")
|
||||
* @Route("models")
|
||||
*/
|
||||
class ModelController extends Controller
|
||||
{
|
||||
/**
|
||||
* Lists all part entities.
|
||||
*
|
||||
* @Route("/models/", name="ldraw_model_index")
|
||||
* @Route("/", name="model_index")
|
||||
* @Method("GET")
|
||||
*/
|
||||
public function indexAction(Request $request)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$form = $this->get('form.factory')->create(ModelFilterType::class);
|
||||
|
||||
$filterBuilder = $this->get('repository.ldraw.model')
|
||||
->createQueryBuilder('model');
|
||||
$filterBuilder = $this->get('repository.ldraw.model')->getFilteredQueryBuilder();
|
||||
|
||||
if ($request->query->has($form->getName())) {
|
||||
// manually bind values from the request
|
||||
@ -45,10 +42,10 @@ class ModelController extends Controller
|
||||
$models = $paginator->paginate(
|
||||
$filterBuilder->getQuery(),
|
||||
$request->query->getInt('page', 1)/*page number*/,
|
||||
$request->query->getInt('limit', 100)/*limit per page*/
|
||||
$request->query->getInt('limit', 40)/*limit per page*/
|
||||
);
|
||||
|
||||
return $this->render('ldraw/model/index.html.twig', [
|
||||
return $this->render('model/index.html.twig', [
|
||||
'models' => $models,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@ -57,27 +54,29 @@ class ModelController extends Controller
|
||||
/**
|
||||
* Finds and displays a part entity.
|
||||
*
|
||||
* @Route("/models/{number}", name="model_detail")
|
||||
* @Route("/{number}", name="model_detail")
|
||||
* @Method("GET")
|
||||
*/
|
||||
public function detailAction($number)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
if($model = $this->get('manager.ldraw.model')->findByNumber($number)) {
|
||||
if ($model = $this->get('repository.ldraw.model')->findOneByNumber($number)) {
|
||||
try {
|
||||
$rbParts = $model != null ? $em->getRepository(Part::class)->findAllByModel($model) : null;
|
||||
$sets = $model != null ? $em->getRepository(Set::class)->findAllByModel($model) : null;
|
||||
|
||||
return $this->render('ldraw/model/detail.html.twig', [
|
||||
$related = $em->getRepository(Model::class)->findAllRelatedModels($model->getNumber());
|
||||
|
||||
return $this->render('model/detail.html.twig', [
|
||||
'model' => $model,
|
||||
'rbParts' => $rbParts,
|
||||
'sets' => $sets,
|
||||
'related' => $related,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->render('error/error.html.twig');
|
@ -3,8 +3,8 @@
|
||||
namespace AppBundle\Controller\Rebrickable;
|
||||
|
||||
use AppBundle\Entity\Rebrickable\Color;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
/**
|
||||
* Part controller.
|
||||
@ -14,10 +14,10 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
class ColorController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @Route("/", name="color_index")
|
||||
*/
|
||||
public function indexAction() {
|
||||
public function indexAction()
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$colors = $em->getRepository(Color::class)->findAll();
|
||||
@ -26,4 +26,4 @@ class ColorController extends Controller
|
||||
'colors' => $colors,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@
|
||||
namespace AppBundle\Controller\Rebrickable;
|
||||
|
||||
use AppBundle\Api\Exception\EmptyResponseException;
|
||||
use AppBundle\Entity\Rebrickable\Category;
|
||||
use AppBundle\Entity\Rebrickable\Part;
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Part controller.
|
||||
@ -16,19 +18,41 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
*/
|
||||
class PartController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="part_index")
|
||||
*/
|
||||
public function indexAction(Request $request)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$queryBuilder = $em->getRepository(Part::class)->createQueryBuilder('part');
|
||||
$queryBuilder->where('part.category = 17');
|
||||
|
||||
$paginator = $this->get('knp_paginator');
|
||||
$sets = $paginator->paginate(
|
||||
$queryBuilder->getQuery(),
|
||||
$request->query->getInt('page', 1)/*page number*/,
|
||||
$request->query->getInt('limit', 30)/*limit per page*/
|
||||
);
|
||||
|
||||
return $this->render(':rebrickable/part:index.html.twig', [
|
||||
'parts' => $sets,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and displays a part entity.
|
||||
*
|
||||
* @Route("/{number}", name="rebrickable_part_show")
|
||||
* @Route("/{number}", name="reb_part_detail")
|
||||
* @Method("GET")
|
||||
*/
|
||||
public function showAction(Part $part = null)
|
||||
public function detailAction(Part $part)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$apiPart = null;
|
||||
|
||||
if($part) {
|
||||
if ($part) {
|
||||
try {
|
||||
$apiPart = $this->get('api.manager.rebrickable')->getPart($part->getNumber());
|
||||
} catch (EmptyResponseException $e) {
|
||||
|
@ -2,17 +2,13 @@
|
||||
|
||||
namespace AppBundle\Controller\Rebrickable;
|
||||
|
||||
use AppBundle\Api\Exception\EmptyResponseException;
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use AppBundle\Entity\Rebrickable\Color;
|
||||
use AppBundle\Entity\Rebrickable\Inventory_Part;
|
||||
use AppBundle\Entity\Rebrickable\Inventory_Set;
|
||||
use AppBundle\Entity\Rebrickable\Part;
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use AppBundle\Entity\Rebrickable\Theme;
|
||||
use AppBundle\Form\FilterSetType;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
@ -21,87 +17,46 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
class SetController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="set_index")
|
||||
* @Route("/{number}/parts", name="rebrickable_set_parts")
|
||||
*/
|
||||
public function indexAction(Request $request)
|
||||
public function partsAction(Set $set)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$qb = $em->getRepository(Set::class)->createQueryBuilder('s');
|
||||
|
||||
$paginator = $this->get('knp_paginator');
|
||||
$sets = $paginator->paginate(
|
||||
$qb->getQuery(),
|
||||
$request->query->getInt('page', 1)/*page number*/,
|
||||
$request->query->getInt('limit', 30)/*limit per page*/
|
||||
);
|
||||
|
||||
return $this->render('rebrickable/set/index.html.twig', [
|
||||
'sets' => $sets,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/detail/{number}_{name}", name="set_detail")
|
||||
*/
|
||||
public function detailAction(Request $request, $number, $name = null)
|
||||
{
|
||||
$brset = null;
|
||||
try {
|
||||
$brset = $this->get('api.manager.brickset')->getSetByNumber($number);
|
||||
} catch (EmptyResponseException $e) {
|
||||
$this->addFlash('warning', 'Set not found in Brickset database');
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
$set = $this->getDoctrine()->getManager()->getRepository(Set::class)->find($number);
|
||||
|
||||
$rbset = $this->get('api.manager.rebrickable')->getSet($number);
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->getRepository(Color::class)->findAll();
|
||||
$em->getRepository(Theme::class)->findAll();
|
||||
$em->getRepository(Part::class)->findAllBySetNumber($set->getNumber());
|
||||
|
||||
return $this->render('rebrickable/set/detail.html.twig', [
|
||||
'set' => $set,
|
||||
'brset' => $brset,
|
||||
'rbset' => $rbset,
|
||||
'parts' => $em->getRepository(Model::class)->findAllBySetNumber($number),
|
||||
'inventoryParts' => $em->getRepository(Inventory_Part::class)->findAllBySetNumber($number),
|
||||
$regularParts = $em->getRepository(Inventory_Part::class)->findAllRegularBySetNumber($set->getNumber());
|
||||
$spareParts = $em->getRepository(Inventory_Part::class)->findAllSpareBySetNumber($set->getNumber());
|
||||
|
||||
$template = $this->render('rebrickable/set/parts.html.twig', [
|
||||
'regularParts' => $regularParts,
|
||||
'spareParts' => $spareParts,
|
||||
]);
|
||||
|
||||
$json = json_encode($template->getContent());
|
||||
$response = new Response($json, 200);
|
||||
$response->headers->set('Content-Type', 'application/json');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Route("/download/{number}", name="set_download")
|
||||
* @Route("/{number}/sets", name="rebrickable_set_sets")
|
||||
*/
|
||||
public function downloadZipAction(Request $request, $number) {
|
||||
public function setsAction(Set $set)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$inventoryParts = $em->getRepository(Inventory_Part::class)->findAllBySetNumber($number);
|
||||
$inventorySets = $em->getRepository(Inventory_Set::class)->findAllBySetNumber($set->getNumber());
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zipName = 'set_'.$number.'.zip';
|
||||
$zip->open($zipName, \ZipArchive::CREATE);
|
||||
/** @var Inventory_Part $part */
|
||||
foreach ($inventoryParts as $part) {
|
||||
$filename = $part->getPart()->getNumber().'_('.$part->getColor()->getName().'_'.$part->getQuantity().'x).stl';
|
||||
$template = $this->render('rebrickable/set/sets.html.twig', [
|
||||
'inventorySets' => $inventorySets,
|
||||
]);
|
||||
|
||||
try {
|
||||
if($part->getPart()->getModel()) {
|
||||
$zip->addFromString($filename, $this->get('oneup_flysystem.media_filesystem')->read($part->getPart()->getModel()->getPath()));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
dump($e);
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
$response = new Response(file_get_contents($zipName));
|
||||
$response->headers->set('Content-Type', 'application/zip');
|
||||
$response->headers->set('Content-Disposition', 'attachment;filename="' . $zipName . '"');
|
||||
$response->headers->set('Content-length', filesize($zipName));
|
||||
$json = json_encode($template->getContent());
|
||||
$response = new Response($json, 200);
|
||||
$response->headers->set('Content-Type', 'application/json');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
82
src/AppBundle/Controller/SetController.php
Normal file
82
src/AppBundle/Controller/SetController.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller;
|
||||
|
||||
use AppBundle\Api\Exception\ApiException;
|
||||
use AppBundle\Api\Exception\EmptyResponseException;
|
||||
use AppBundle\Entity\Rebrickable\Inventory_Part;
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use AppBundle\Form\Filter\Set\SetFilterType;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* @Route("/sets")
|
||||
*/
|
||||
class SetController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="set_index")
|
||||
*/
|
||||
public function indexAction(Request $request)
|
||||
{
|
||||
$form = $this->get('form.factory')->create(SetFilterType::class);
|
||||
|
||||
$filterBuilder = $this->get('repository.rebrickable.set')
|
||||
->createQueryBuilder('s');
|
||||
|
||||
if ($request->query->has($form->getName())) {
|
||||
// manually bind values from the request
|
||||
$form->submit($request->query->get($form->getName()));
|
||||
|
||||
// build the query from the given form object
|
||||
$this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $filterBuilder);
|
||||
}
|
||||
|
||||
$paginator = $this->get('knp_paginator');
|
||||
$sets = $paginator->paginate(
|
||||
$filterBuilder->getQuery(),
|
||||
$request->query->getInt('page', 1)/*page number*/,
|
||||
$request->query->getInt('limit', 30)/*limit per page*/
|
||||
);
|
||||
|
||||
return $this->render('set/index.html.twig', [
|
||||
'sets' => $sets,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{number}", name="set_detail")
|
||||
*/
|
||||
public function detailAction(Request $request, $number)
|
||||
{
|
||||
$rebrickableSet = null;
|
||||
$bricksetSet = null;
|
||||
try {
|
||||
if (($rebrickableSet = $this->getDoctrine()->getManager()->getRepository(Set::class)->find($number)) == null) {
|
||||
$this->addFlash('warning', 'Set not found in Rebrickable database');
|
||||
}
|
||||
|
||||
$bricksetSet = $this->get('api.manager.brickset')->getSetByNumber($number);
|
||||
dump($bricksetSet);
|
||||
} catch (EmptyResponseException $e) {
|
||||
$this->addFlash('warning', 'Set not found in Brickset database');
|
||||
} catch (ApiException $e) {
|
||||
$this->addFlash('error', $e->getService());
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
if (!$rebrickableSet && !$bricksetSet) {
|
||||
return $this->render('error/error.html.twig');
|
||||
}
|
||||
|
||||
return $this->render('set/detail.html.twig', [
|
||||
'rbset' => $rebrickableSet,
|
||||
'brset' => $bricksetSet,
|
||||
]);
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ class Alias
|
||||
/**
|
||||
* @var Model
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\LDraw\Model", inversedBy="aliases", cascade={"persist"})
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\LDraw\Model", inversedBy="aliases")
|
||||
*/
|
||||
private $model;
|
||||
|
||||
|
34
src/AppBundle/Entity/LDraw/Author.php
Normal file
34
src/AppBundle/Entity/LDraw/Author.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Entity\LDraw;
|
||||
|
||||
use AppBundle\Entity\Traits\IdentityTrait;
|
||||
use AppBundle\Entity\Traits\UniqueNameTrait;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Author.
|
||||
*
|
||||
* @ORM\Table(name="ldraw_author")
|
||||
* @ORM\Entity(repositoryClass="AppBundle\Repository\LDraw\AuthorRepository")
|
||||
*/
|
||||
class Author
|
||||
{
|
||||
use IdentityTrait;
|
||||
use UniqueNameTrait;
|
||||
|
||||
/**
|
||||
* @var Author
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="AppBundle\Entity\LDraw\Model", mappedBy="author")
|
||||
*/
|
||||
private $models;
|
||||
|
||||
/**
|
||||
* @return Author
|
||||
*/
|
||||
public function getModels()
|
||||
{
|
||||
return $this->models;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
namespace AppBundle\Entity\LDraw;
|
||||
|
||||
use AppBundle\Entity\Traits\IdentityTrait;
|
||||
use AppBundle\Entity\Traits\NameTrait;
|
||||
use AppBundle\Entity\Traits\UniqueNameTrait;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
@ -17,7 +17,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
class Category
|
||||
{
|
||||
use IdentityTrait;
|
||||
use NameTrait;
|
||||
use UniqueNameTrait;
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace AppBundle\Entity\LDraw;
|
||||
|
||||
use AppBundle\Entity\Traits\IdentityTrait;
|
||||
use AppBundle\Entity\Traits\NameTrait;
|
||||
use AppBundle\Entity\Traits\UniqueNameTrait;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
@ -16,7 +16,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
class Keyword
|
||||
{
|
||||
use IdentityTrait;
|
||||
use NameTrait;
|
||||
use UniqueNameTrait;
|
||||
|
||||
/**
|
||||
* @var ArrayCollection
|
||||
|
@ -17,13 +17,6 @@ class Model
|
||||
{
|
||||
use NumberTrait;
|
||||
|
||||
/**
|
||||
* @var Type
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\LDraw\Type", inversedBy="models", cascade={"persist"})
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
@ -48,7 +41,7 @@ class Model
|
||||
/**
|
||||
* @var ArrayCollection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="AppBundle\Entity\LDraw\Subpart", mappedBy="parent")
|
||||
* @ORM\OneToMany(targetEntity="AppBundle\Entity\LDraw\Subpart", mappedBy="parent", cascade={"persist"})
|
||||
*/
|
||||
private $subparts;
|
||||
|
||||
@ -74,9 +67,9 @@ class Model
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var Author
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\LDraw\Author", cascade={"persist"}, inversedBy="models")
|
||||
*/
|
||||
private $author;
|
||||
|
||||
@ -122,7 +115,7 @@ class Model
|
||||
/**
|
||||
* Set author.
|
||||
*
|
||||
* @param string $author
|
||||
* @param Author $author
|
||||
*
|
||||
* @return Model
|
||||
*/
|
||||
@ -136,7 +129,7 @@ class Model
|
||||
/**
|
||||
* Get author.
|
||||
*
|
||||
* @return string
|
||||
* @return Author
|
||||
*/
|
||||
public function getAuthor()
|
||||
{
|
||||
@ -163,22 +156,6 @@ class Model
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -292,6 +269,20 @@ class Model
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Subpart $subpart
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubpart($subpart)
|
||||
{
|
||||
if (!$this->subparts->contains($subpart)) {
|
||||
$this->subparts->add($subpart);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
|
@ -16,7 +16,7 @@ class Subpart
|
||||
* @var Model
|
||||
*
|
||||
* @ORM\Id
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\LDraw\Model", inversedBy="subparts", cascade={"persist"})
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\LDraw\Model", inversedBy="subparts")
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
|
@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Entity\LDraw;
|
||||
|
||||
use AppBundle\Entity\Traits\IdentityTrait;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Type.
|
||||
*
|
||||
* @ORM\Table(name="ldraw_type")
|
||||
* @ORM\Entity(repositoryClass="AppBundle\Repository\LDraw\TypeRepository")
|
||||
*/
|
||||
class Type
|
||||
{
|
||||
use IdentityTrait;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", length=60, unique=true)
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="Model", mappedBy="type")
|
||||
*/
|
||||
private $models;
|
||||
|
||||
/**
|
||||
* BuildingKit constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->models = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get models.
|
||||
*
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function getModels()
|
||||
{
|
||||
return $this->models;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*
|
||||
* @return Type
|
||||
*/
|
||||
public function addModel(Model $model)
|
||||
{
|
||||
$this->models->add($model);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*
|
||||
* @return Type
|
||||
*/
|
||||
public function removeModel(Model $model)
|
||||
{
|
||||
$this->models->remove($model);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -38,9 +38,17 @@ class Inventory
|
||||
*/
|
||||
protected $inventoryParts;
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Rebrickable\Inventory_Set", mappedBy="inventory")
|
||||
*/
|
||||
protected $inventorySets;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->inventoryParts = new ArrayCollection();
|
||||
$this->inventorySets = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,4 +98,20 @@ class Inventory
|
||||
{
|
||||
$this->inventoryParts = $inventoryParts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInventorySets()
|
||||
{
|
||||
return $this->inventorySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $inventorySets
|
||||
*/
|
||||
public function setInventorySets($inventorySets)
|
||||
{
|
||||
$this->inventorySets = $inventorySets;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class Inventory_Part
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
protected $spare;
|
||||
|
81
src/AppBundle/Entity/Rebrickable/Inventory_Set.php
Normal file
81
src/AppBundle/Entity/Rebrickable/Inventory_Set.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Entity\Rebrickable;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Inventory_Set.
|
||||
*
|
||||
* @ORM\Table(name="rebrickable_inventory_sets")
|
||||
* @ORM\Entity(repositoryClass="AppBundle\Repository\Rebrickable\Inventory_SetRepository")
|
||||
*/
|
||||
class Inventory_Set
|
||||
{
|
||||
/**
|
||||
* @var Inventory
|
||||
* @ORM\Id
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Rebrickable\Inventory", inversedBy="inventorySets")
|
||||
*/
|
||||
protected $inventory;
|
||||
|
||||
/**
|
||||
* @var Set
|
||||
* @ORM\Id
|
||||
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Rebrickable\Set", inversedBy="inventorySets")
|
||||
*/
|
||||
protected $set;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
protected $quantity;
|
||||
|
||||
/**
|
||||
* Get count.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getQuantity()
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Set
|
||||
*/
|
||||
public function getSet()
|
||||
{
|
||||
return $this->set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Set $set
|
||||
*/
|
||||
public function setSet($set)
|
||||
{
|
||||
$this->set = $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Inventory
|
||||
*/
|
||||
public function getInventory()
|
||||
{
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Inventory $inventory
|
||||
*
|
||||
* @return Inventory_Set
|
||||
*/
|
||||
public function setInventory(Inventory $inventory)
|
||||
{
|
||||
$this->inventory = $inventory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -47,12 +47,20 @@ class Set
|
||||
*/
|
||||
protected $theme;
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Rebrickable\Inventory_Set", mappedBy="set")
|
||||
*/
|
||||
protected $inventorySets;
|
||||
|
||||
/**
|
||||
* Set constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->inventories = new ArrayCollection();
|
||||
$this->inventorySets = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,6 +141,22 @@ class Set
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInventorySets()
|
||||
{
|
||||
return $this->inventorySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $inventorySets
|
||||
*/
|
||||
public function setInventorySets($inventorySets)
|
||||
{
|
||||
$this->inventorySets = $inventorySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Theme
|
||||
*/
|
||||
|
33
src/AppBundle/Entity/Traits/UniqueNameTrait.php
Normal file
33
src/AppBundle/Entity/Traits/UniqueNameTrait.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Entity\Traits;
|
||||
|
||||
trait UniqueNameTrait
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true, unique=true)
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
35
src/AppBundle/Exception/ConvertingFailedException.php
Normal file
35
src/AppBundle/Exception/ConvertingFailedException.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ConvertingFailedException extends \Exception
|
||||
{
|
||||
private $filepath;
|
||||
|
||||
public function __construct($form = '', $to = '', $message = '', $code = 0, Exception $previous = null)
|
||||
{
|
||||
$message = sprintf('Error converting "%s" file to "%s".', $form, $to);
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->filepath = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFilepath()
|
||||
{
|
||||
return $this->filepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $filepath
|
||||
*/
|
||||
public function setFilepath($filepath)
|
||||
{
|
||||
$this->filepath = $filepath;
|
||||
}
|
||||
}
|
15
src/AppBundle/Exception/ErrorParsingLineException.php
Normal file
15
src/AppBundle/Exception/ErrorParsingLineException.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ErrorParsingLineException extends FileException
|
||||
{
|
||||
public function __construct($path, $line, $message = '', $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$message = sprintf('Error parsing line \""%s"\" "%s" file.',$line, $path);
|
||||
|
||||
parent::__construct($path, $message, $code, $previous);
|
||||
}
|
||||
}
|
17
src/AppBundle/Exception/FileException.php
Normal file
17
src/AppBundle/Exception/FileException.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class FileException extends \Exception
|
||||
{
|
||||
protected $path;
|
||||
|
||||
public function __construct($path, $message = '', $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$this->path = $path;
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
15
src/AppBundle/Exception/FileNotFoundException.php
Normal file
15
src/AppBundle/Exception/FileNotFoundException.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class FileNotFoundException extends FileException
|
||||
{
|
||||
public function __construct($path, $message = '', $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$message = sprintf('File "%s" not found.', $path);
|
||||
|
||||
parent::__construct($path, $message, $code, $previous);
|
||||
}
|
||||
}
|
15
src/AppBundle/Exception/ParseErrorException.php
Normal file
15
src/AppBundle/Exception/ParseErrorException.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ParseErrorException extends FileException
|
||||
{
|
||||
public function __construct($path, $message = '', $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$message = sprintf('Error parsing "%s" file.', $path);
|
||||
|
||||
parent::__construct($path, $message, $code, $previous);
|
||||
}
|
||||
}
|
15
src/AppBundle/Exception/WriteErrorException.php
Normal file
15
src/AppBundle/Exception/WriteErrorException.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class WriteErrorException extends FileException
|
||||
{
|
||||
public function __construct($file, $message = '', $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$message = sprintf('Could not write into "%s" file.', $file);
|
||||
|
||||
parent::__construct($file, $message, $code, $previous);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Form\Filter;
|
||||
namespace AppBundle\Form\Filter\Model;
|
||||
|
||||
use AppBundle\Entity\LDraw\Category;
|
||||
use AppBundle\Manager\LDraw\CategoryManager;
|
||||
use AppBundle\Repository\LDraw\CategoryRepository;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type as Filters;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@ -11,17 +11,17 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class CategoryFilterType extends AbstractType
|
||||
{
|
||||
private $categoryManager;
|
||||
private $categoryRepository;
|
||||
|
||||
public function __construct(CategoryManager $categoryManager)
|
||||
public function __construct(CategoryRepository $categoryRepository)
|
||||
{
|
||||
$this->categoryManager = $categoryManager;
|
||||
$this->categoryRepository = $categoryRepository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add('id', Filters\ChoiceFilterType::class, [
|
||||
'choices' => $this->categoryManager->findAll(),
|
||||
'choices' => $this->categoryRepository->findAll(),
|
||||
'choice_label' => 'name',
|
||||
'label' => 'filter.part.category',
|
||||
]);
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Form\Filter;
|
||||
namespace AppBundle\Form\Filter\Model;
|
||||
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\FilterBuilderExecuterInterface;
|
58
src/AppBundle/Form/Filter/Set/SetFilterType.php
Normal file
58
src/AppBundle/Form/Filter/Set/SetFilterType.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Form\Filter\Set;
|
||||
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\FilterBuilderExecuterInterface;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type as Filters;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class SetFilterType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add('search', Filters\TextFilterType::class, [
|
||||
'apply_filter' => [$this, 'setSearchCallback'],
|
||||
'label' => 'filter.part.search',
|
||||
]);
|
||||
|
||||
$builder->add('theme', ThemeFilterType::class, [
|
||||
'add_shared' => function (FilterBuilderExecuterInterface $builderExecuter) {
|
||||
$builderExecuter->addOnce($builderExecuter->getAlias().'.theme', 'c', function (QueryBuilder $filterBuilder, $alias, $joinAlias, $expr) {
|
||||
$filterBuilder->leftJoin($alias.'.theme', $joinAlias);
|
||||
});
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'model_filter';
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'csrf_protection' => false,
|
||||
'validation_groups' => ['filtering'], // avoid NotBlank() constraint-related message
|
||||
]);
|
||||
}
|
||||
|
||||
public function setSearchCallback(QueryInterface $filterQuery, $field, $values)
|
||||
{
|
||||
if (empty($values['value'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// expression that represent the condition
|
||||
$expression = $filterQuery->getExpr()->orX(
|
||||
$filterQuery->getExpr()->like('s.name', ':value'),
|
||||
$filterQuery->getExpr()->like('s.number', ':value')
|
||||
);
|
||||
|
||||
return $filterQuery->createCondition($expression, ['value' => '%'.$values['value'].'%']);
|
||||
}
|
||||
}
|
63
src/AppBundle/Form/Filter/Set/ThemeFilterType.php
Normal file
63
src/AppBundle/Form/Filter/Set/ThemeFilterType.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Form\Filter\Set;
|
||||
|
||||
use AppBundle\Entity\Rebrickable\Theme;
|
||||
use AppBundle\Repository\Rebrickable\ThemeRepository;
|
||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type as Filters;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class ThemeFilterType extends AbstractType
|
||||
{
|
||||
private $themeRepository;
|
||||
|
||||
public function __construct(ThemeRepository $themeRepository)
|
||||
{
|
||||
$this->themeRepository = $themeRepository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add('id', Filters\ChoiceFilterType::class, [
|
||||
'choices' => $this->themeRepository->findAll(),
|
||||
'choice_label' => function ($theme, $currentChoiceKey) {
|
||||
if ($parent = $theme->getParent()) {
|
||||
if ($parentParent = $parent->getParent()) {
|
||||
if ($parentParentParent = $parentParent->getParent()) {
|
||||
return $parentParentParent->getName().' > '.$parentParent->getName().' > '.$parent->getName().' > '.$theme->getName();
|
||||
}
|
||||
|
||||
return $parentParent->getName().' > '.$parent->getName().' > '.$theme->getName();
|
||||
}
|
||||
|
||||
return $parent->getName().' > '.$theme->getName();
|
||||
}
|
||||
|
||||
return $theme->getName();
|
||||
},
|
||||
'label' => 'filter.set.theme',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getParent()
|
||||
{
|
||||
return Filters\SharedableFilterType::class; // this allow us to use the "add_shared" option
|
||||
}
|
||||
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'theme_filter';
|
||||
}
|
||||
|
||||
public function setDefaultOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Theme::class,
|
||||
'csrf_protection' => false,
|
||||
'validation_groups' => ['filtering'], // avoid NotBlank() constraint-related message
|
||||
'method' => 'GET',
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager;
|
||||
|
||||
class BaseManager
|
||||
{
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRepository()
|
||||
{
|
||||
return $this->repository;
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Alias;
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use AppBundle\Manager\BaseManager;
|
||||
use AppBundle\Repository\LDraw\AliasRepository;
|
||||
|
||||
class AliasManager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* AliasManager constructor.
|
||||
*
|
||||
* @param AliasRepository $repository
|
||||
*/
|
||||
public function __construct(AliasRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Alias entity.
|
||||
*
|
||||
* @param $number
|
||||
* @param Model $model
|
||||
*
|
||||
* @return Alias
|
||||
*/
|
||||
public function create($number, $model)
|
||||
{
|
||||
if (($alias = $this->repository->findOneBy(['number' => $number, 'model' => $model])) == null) {
|
||||
$alias = new Alias();
|
||||
$alias->setModel($model);
|
||||
$alias->setNumber($number);
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Category;
|
||||
use AppBundle\Manager\BaseManager;
|
||||
use AppBundle\Repository\LDraw\CategoryRepository;
|
||||
|
||||
class CategoryManager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* CategoryManager constructor.
|
||||
*
|
||||
* @param CategoryRepository $repository
|
||||
*/
|
||||
public function __construct(CategoryRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function findAll()
|
||||
{
|
||||
return $this->repository->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Category entity with $name or retrieve one.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Category
|
||||
*/
|
||||
public function create($name)
|
||||
{
|
||||
if (($category = $this->repository->findByName($name)) == null) {
|
||||
$category = new Category();
|
||||
$category->setName($name);
|
||||
}
|
||||
|
||||
return $category;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Keyword;
|
||||
use AppBundle\Manager\BaseManager;
|
||||
use AppBundle\Repository\LDraw\KeywordRepository;
|
||||
|
||||
class KeywordManager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* KeywordManager constructor.
|
||||
*
|
||||
* @param KeywordRepository $repository
|
||||
*/
|
||||
public function __construct(KeywordRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Keyword entity with $name or retrieve one.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Keyword
|
||||
*/
|
||||
public function create($name)
|
||||
{
|
||||
if (($keyword = $this->repository->findByName($name)) == null) {
|
||||
$keyword = new Keyword();
|
||||
$keyword->setName($name);
|
||||
}
|
||||
|
||||
return $keyword;
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use AppBundle\Manager\BaseManager;
|
||||
use AppBundle\Repository\LDraw\ModelRepository;
|
||||
|
||||
class ModelManager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* ModelManager constructor.
|
||||
*
|
||||
* @param ModelRepository $repository
|
||||
*/
|
||||
public function __construct(ModelRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Model entity with $number or retrieve one.
|
||||
*
|
||||
* @param $number
|
||||
*
|
||||
* @return Model
|
||||
*/
|
||||
public function create($number)
|
||||
{
|
||||
if (($model = $this->repository->findOneBy(['number' => $number])) == null) {
|
||||
$model = new Model();
|
||||
$model->setNumber($number);
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function findByNumber($number)
|
||||
{
|
||||
return $this->repository->findOneByNumber($number);
|
||||
}
|
||||
|
||||
public function findByName($name)
|
||||
{
|
||||
return $this->repository->findOneBy(['name' => $name]);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Subpart;
|
||||
use AppBundle\Manager\BaseManager;
|
||||
use AppBundle\Repository\LDraw\SubpartRepository;
|
||||
|
||||
class SubpartManager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* SubpartManager constructor.
|
||||
*
|
||||
* @param SubpartRepository $repository
|
||||
*/
|
||||
public function __construct(SubpartRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Subpart relation entity or retrieve one by foreign keys.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Subpart
|
||||
*/
|
||||
public function create($parent, $child)
|
||||
{
|
||||
if (($subpart = $this->repository->findOneByKeys($parent, $child))) {
|
||||
$subpart->setCount($subpart->getCount() + 1);
|
||||
} else {
|
||||
$subpart = new Subpart();
|
||||
$subpart
|
||||
->setParent($parent)
|
||||
->setSubpart($child)
|
||||
->setCount(1);
|
||||
}
|
||||
|
||||
return $subpart;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Type;
|
||||
use AppBundle\Manager\BaseManager;
|
||||
use AppBundle\Repository\LDraw\TypeRepository;
|
||||
|
||||
class TypeManager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* TypeManager constructor.
|
||||
*
|
||||
* @param TypeRepository $typeRepository
|
||||
*/
|
||||
public function __construct(TypeRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Keyword entity with $name or retrieve one.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Type
|
||||
*/
|
||||
public function create($name)
|
||||
{
|
||||
if (($type = $this->repository->findByName($name)) == null) {
|
||||
$type = new Type();
|
||||
$type->setName($name);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Manager;
|
||||
|
||||
use AppBundle\Manager\LDraw\AliasManager;
|
||||
use AppBundle\Manager\LDraw\CategoryManager;
|
||||
use AppBundle\Manager\LDraw\KeywordManager;
|
||||
use AppBundle\Manager\LDraw\ModelManager;
|
||||
use AppBundle\Manager\LDraw\SubpartManager;
|
||||
use AppBundle\Manager\LDraw\TypeManager;
|
||||
|
||||
class LDrawManager
|
||||
{
|
||||
/** @var CategoryManager */
|
||||
private $categoryManager;
|
||||
|
||||
/** @var KeywordManager */
|
||||
private $keywordManager;
|
||||
|
||||
/** @var TypeManager */
|
||||
private $typeManager;
|
||||
|
||||
/** @var SubpartManager */
|
||||
private $subpartManager;
|
||||
|
||||
/** @var ModelManager */
|
||||
private $modelManager;
|
||||
|
||||
/** @var AliasManager */
|
||||
private $aliasManager;
|
||||
|
||||
/**
|
||||
* LDrawService constructor.
|
||||
*
|
||||
* @param CategoryManager $categoryManager
|
||||
* @param KeywordManager $keywordManager
|
||||
* @param TypeManager $typeManager
|
||||
* @param SubpartManager $subpartManager
|
||||
* @param ModelManager $modelManager
|
||||
* @param AliasManager $aliasManager
|
||||
*/
|
||||
public function __construct(CategoryManager $categoryManager, KeywordManager $keywordManager, TypeManager $typeManager, SubpartManager $subpartManager, ModelManager $modelManager, AliasManager $aliasManager)
|
||||
{
|
||||
$this->categoryManager = $categoryManager;
|
||||
$this->keywordManager = $keywordManager;
|
||||
$this->typeManager = $typeManager;
|
||||
$this->subpartManager = $subpartManager;
|
||||
$this->modelManager = $modelManager;
|
||||
$this->aliasManager = $aliasManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCategoryManager()
|
||||
{
|
||||
return $this->categoryManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getKeywordManager()
|
||||
{
|
||||
return $this->keywordManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypeManager
|
||||
*/
|
||||
public function getTypeManager()
|
||||
{
|
||||
return $this->typeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SubpartManager
|
||||
*/
|
||||
public function getSubpartManager()
|
||||
{
|
||||
return $this->subpartManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ModelManager
|
||||
*/
|
||||
public function getModelManager()
|
||||
{
|
||||
return $this->modelManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AliasManager
|
||||
*/
|
||||
public function getAliasManager()
|
||||
{
|
||||
return $this->aliasManager;
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ class Builder
|
||||
]);
|
||||
|
||||
$menu->addChild('Models', [
|
||||
'route' => 'ldraw_model_index',
|
||||
'route' => 'model_index',
|
||||
]);
|
||||
|
||||
$menu->addChild('Sets', [
|
||||
|
@ -2,8 +2,28 @@
|
||||
|
||||
namespace AppBundle\Repository\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Alias;
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use AppBundle\Repository\BaseRepository;
|
||||
|
||||
class AliasRepository extends BaseRepository
|
||||
{
|
||||
/**
|
||||
* Get existing entity or create new.
|
||||
*
|
||||
* @param $number
|
||||
* @param Model $model
|
||||
*
|
||||
* @return Alias
|
||||
*/
|
||||
public function getOrCreate($number, $model)
|
||||
{
|
||||
if (($alias = $this->findOneBy(['number' => $number, 'model' => $model])) == null) {
|
||||
$alias = new Alias();
|
||||
$alias->setModel($model);
|
||||
$alias->setNumber($number);
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
}
|
||||
|
31
src/AppBundle/Repository/LDraw/AuthorRepository.php
Normal file
31
src/AppBundle/Repository/LDraw/AuthorRepository.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Repository\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Author;
|
||||
use AppBundle\Repository\BaseRepository;
|
||||
|
||||
class AuthorRepository extends BaseRepository
|
||||
{
|
||||
public function findOneByName($name)
|
||||
{
|
||||
return $this->findOneBy(['name' => $name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing entity or create new.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Author
|
||||
*/
|
||||
public function getOrCreate($name)
|
||||
{
|
||||
if (($author = $this->findOneByName($name)) == null) {
|
||||
$author = new Author();
|
||||
$author->setName($name);
|
||||
}
|
||||
|
||||
return $author;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace AppBundle\Repository\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Category;
|
||||
use AppBundle\Repository\BaseRepository;
|
||||
|
||||
class CategoryRepository extends BaseRepository
|
||||
@ -10,4 +11,21 @@ class CategoryRepository extends BaseRepository
|
||||
{
|
||||
return $this->findOneBy(['name' => $name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing entity or create new.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Category
|
||||
*/
|
||||
public function getOrCreate($name)
|
||||
{
|
||||
if (($category = $this->findByName($name)) == null) {
|
||||
$category = new Category();
|
||||
$category->setName($name);
|
||||
}
|
||||
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace AppBundle\Repository\LDraw;
|
||||
|
||||
use AppBundle\Entity\LDraw\Keyword;
|
||||
use AppBundle\Repository\BaseRepository;
|
||||
|
||||
class KeywordRepository extends BaseRepository
|
||||
@ -10,4 +11,21 @@ class KeywordRepository extends BaseRepository
|
||||
{
|
||||
return $this->findOneBy(['name' => $name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Keyword entity with $name or retrieve one.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return Keyword
|
||||
*/
|
||||
public function getOrCreate($name)
|
||||
{
|
||||
if (($keyword = $this->findByName($name)) == null) {
|
||||
$keyword = new Keyword();
|
||||
$keyword->setName($name);
|
||||
}
|
||||
|
||||
return $keyword;
|
||||
}
|
||||
}
|
||||
|
@ -2,30 +2,33 @@
|
||||
|
||||
namespace AppBundle\Repository\LDraw;
|
||||
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use AppBundle\Entity\Rebrickable\Part;
|
||||
use AppBundle\Entity\LDraw\Alias;
|
||||
use AppBundle\Entity\LDraw\Type;
|
||||
use AppBundle\Entity\LDraw\Category;
|
||||
use AppBundle\Entity\LDraw\Model;
|
||||
use AppBundle\Entity\LDraw\Subpart;
|
||||
use AppBundle\Entity\Rebrickable\Inventory;
|
||||
use AppBundle\Entity\Rebrickable\Inventory_Part;
|
||||
use AppBundle\Entity\Rebrickable\Part;
|
||||
use AppBundle\Entity\Rebrickable\Set;
|
||||
use AppBundle\Repository\BaseRepository;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
|
||||
class ModelRepository extends BaseRepository
|
||||
{
|
||||
public function findAllByType($type)
|
||||
public function getFilteredQueryBuilder()
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder('model')
|
||||
->join(Type::class, 'type', Join::LEFT_JOIN, 'model.type = :type')
|
||||
->setParameter('type', $type);
|
||||
// ->where('model.name NOT LIKE :obsolete')
|
||||
// ->setParameter('obsolete','~%')
|
||||
;
|
||||
|
||||
return $queryBuilder->getQuery();
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
public function findAllByCategory($category)
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder('model')
|
||||
->join(Type::class, 'type', Join::LEFT_JOIN, 'model.category = :category')
|
||||
->join(Category::class, 'type', Join::LEFT_JOIN, 'model.category = :category')
|
||||
->setParameter('category', $category);
|
||||
|
||||
return $queryBuilder->getQuery();
|
||||
@ -49,6 +52,11 @@ class ModelRepository extends BaseRepository
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function findOneByName($name)
|
||||
{
|
||||
return $this->findOneBy(['name' => $name]);
|
||||
}
|
||||
|
||||
public function findAllBySetNumber($number)
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder('model');
|
||||
@ -64,4 +72,38 @@ class ModelRepository extends BaseRepository
|
||||
|
||||
return $queryBuilder->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function findAllRelatedModels($number)
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder('model');
|
||||
|
||||
$queryBuilder
|
||||
->select('related')
|
||||
->join(Subpart::class, 'subpart', JOIN::WITH, 'model.number = subpart.subpart')
|
||||
->join(Subpart::class, 'parent', JOIN::WITH, 'subpart.parent = parent.parent')
|
||||
->join(Model::class, 'related', JOIN::WITH, 'related.number = parent.subpart')
|
||||
->where('model.number = :number')
|
||||
->setParameter('number', $number)
|
||||
->andWhere('related.number != :number')
|
||||
->distinct(true);
|
||||
|
||||
return $queryBuilder->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Model entity with $number or retrieve one.
|
||||
*
|
||||
* @param $number
|
||||
*
|
||||
* @return Model
|
||||
*/
|
||||
public function getOrCreate($number)
|
||||
{
|
||||
if (($model = $this->findOneBy(['number' => $number])) == null) {
|
||||
$model = new Model();
|
||||
$model->setNumber($number);
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user