Merge branch 'form_add_ad'

# Conflicts:
#	www/app/config/config.yml
#	www/app/config/services.yml
#	www/composer.lock
#	www/vendor/composer/installed.json
#	www/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdStringWrapperNameEntity.php
#	www/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapper.php
#	www/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php
#	www/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/DataCollectorTranslatorPass.php
#	www/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/DataCollectorTranslatorPassTest.php
#	www/vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php
#	www/vendor/symfony/symfony/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php
#	www/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_frozen.php
#	www/vendor/symfony/symfony/src/Symfony/Component/Form/Tests/Extension/Core/Type/ExtendedChoiceTypeTest.php
#	www/vendor/symfony/symfony/src/Symfony/Component/Form/Tests/Fixtures/ChoiceTypeExtension.php
#	www/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Tests/Fixtures/123/Kernel123.php
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/currencies/es_BR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/currencies/pt_LU.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/ar_LY.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/ar_SA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/bn_IN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/de_AT.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/de_LU.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/en_IN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_AR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_BO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_CL.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_CO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_CR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_DO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_EC.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_GT.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_HN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_NI.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_PA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_PE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_PR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_PY.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_SV.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_US.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/es_VE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/fr_BE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/mo.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/ro_MD.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sh_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_Cyrl_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_Cyrl_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_Cyrl_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_Latn_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_Latn_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_Latn_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sr_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/languages/sw_KE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/ar_LY.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/ar_SA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/bn_IN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/de_AT.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/de_LU.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/en_IN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_AR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_BO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_CO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_CR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_DO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_EC.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_GT.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_HN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_NI.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_PA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_PE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_PY.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_US.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/es_VE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/fr_BE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/fr_CH.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/ko_KP.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/ro_MD.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/ru_UA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sr_Cyrl_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sr_Cyrl_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sr_Cyrl_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sr_Latn_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sr_Latn_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sr_Latn_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/sw_KE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/ar_LY.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/ar_SA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/bn_IN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/de_AT.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_419.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_AR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_BO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_CO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_CR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_DO.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_EC.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_GT.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_HN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_NI.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_PA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_PE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_PR.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_PY.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_SV.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_US.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/es_VE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/fr_BE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/ko_KP.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/mo.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/ro_MD.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/ru_UA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sh_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_Cyrl_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_Cyrl_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_Cyrl_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_Latn_BA.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_Latn_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_Latn_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_ME.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sr_XK.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/regions/sw_KE.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/scripts/en_IN.json
#	www/vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/scripts/es_419.json
This commit is contained in:
2017-03-28 14:16:42 +02:00
417 changed files with 43221 additions and 105 deletions
+1
View File
@@ -1,4 +1,5 @@
server {
client_max_body_size 500M;
server_name talentstube.dev;
root /home/www/talentstube.dev/www/web;
+6
View File
@@ -29,6 +29,12 @@ class AppKernel extends Kernel
// Doctrine JSON
new \Dunglas\DoctrineJsonOdm\Bundle\DunglasDoctrineJsonOdmBundle(),
new Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle(),
// Vimeo
new RequestLab\VimeoBundle\RequestLabVimeoBundle(),
//FFmpeg
new Dubture\FFmpegBundle\DubtureFFmpegBundle(),
];
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
+2 -2
View File
@@ -16,9 +16,9 @@
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
{% block javascripts %}
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
{% endblock %}
</body>
</html>
@@ -0,0 +1,13 @@
{% extends 'base.html.twig' %}
{% block content %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{% endblock %}
@@ -0,0 +1,33 @@
{% extends 'base.html.twig' %}
{% block content %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% include 'media/dropzone.html.twig'%}
{% endblock %}
{% block javascripts %}
<style>
#tt-dropzone{
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px;
}
</style>
<script type="text/javascript">
var urlDropzone = '{{ path("upload_media_answer", {"id": answer.getId()}) }}';
var urlDelete = '{{ path("delete_media_answer", {"id": answer.getId() }) }}'
var idObject = '{{ answer.getId() }}';
var typeObject = "answer";
{% if video %}
var videoExist = true;
var videoOriginal = "{{video.getOriginalUrl()}}";
var mockFile = { name: '{{video.getTitle()}}', size: '181818181', type: 'mp4', serverID: 0, accepted: true };
{% else %}
var videoExist = false;
{% endif %}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/dropzone.js"></script>
<script src="{{ asset('/js/dropzone.js') }}"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/dropzone.css">
{% endblock %}
@@ -0,0 +1,56 @@
{% extends 'base.html.twig' %}
{% block content %}
<div class="row">
<div class="col s12">
<ul id="tabs-swipe-demo" class="tabs">
<li class="tab col s3"><a class="active" href="#test-swipe-1">Ajouter une nouvelle vidéo</a></li>
<li class="tab col s3"><a href="#test-swipe-2">Utiliser une vidéo existante</a></li>
</ul>
</div>
<div id="test-swipe-1" class="col s12 blue">
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% include 'media/dropzone.html.twig' %}
</div>
<div id="test-swipe-2" class="col s12 red">
<div class="row">
<h3>Choisir une vidéo existante</h3>
{% for vid in videos %}
<div class="col s4">
<a class="addExistingVideo" href="#" data-title="{{ vid.getTitle() }}" data-id="{{ vid.getId() }}">
<span>{{ vid.getTitle() }}</span><br />
<img src="https://i.vimeocdn.com{{ vid.getCdnUrl()|replace({ "videos": "video"}) }}_295x166.webp" srcset="https://i.vimeocdn.com/{{ vid.getCdnUrl()|replace({ "videos": "video"}) }}_590x332.webp 2x" />
</a>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
<style>
#tt-dropzone{
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px;
}
</style>
<script type="text/javascript">
var urlDropzone = '{{ path("upload_media", {"id": ad.getId()}) }}';
var urlDelete = '{{ path("delete_media", {"id": ad.getId() }) }}'
var idObject = '{{ ad.getId() }}';
var typeObject = "ad";
{% if video %}
var videoExist = true;
var videoOriginal = "{{video.getOriginalUrl()}}";
var mockFile = { name: '{{video.getTitle()}}', size: '181818181', type: 'mp4', serverID: 0, accepted: true };
{% else %}
var videoExist = false;
{% endif %}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/dropzone.js"></script>
<script src="{{ asset('/js/dropzone.js') }}"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/dropzone.css">
{% endblock %}
@@ -0,0 +1,26 @@
{% extends 'base.html.twig' %}
{% block content %}
<div class="container">
{% for ad in list %}
<div class="row">
<div class="col s6">
<h3>{{ ad.title }}</h3>
<a href="{{ path('create_media', { 'id': ad.id }) }}">Ajout d'une vidéo</a>
<a href="{{ path('create_answer', { 'id': ad.id }) }}">Répondre à l'annonce</a>
{% if ad.getVideo() %}
<p>Vidéo existante : {{ ad.getVideo().getTitle() }}</p>
<p>Url Viméo : {{ ad.getVideo().getCdnUrl() }}<p>
{% endif %}
</div>
<div class="col s4">
{% if ad.getVideo() %}
<iframe src="https://player.vimeo.com{{ ad.getVideo().getCdnUrl()|replace({ "videos": "video"}) }}" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
@@ -0,0 +1,14 @@
{% block dropzone %}
<div class="row">
<div class="col s6">
<form action="UploadImages" class="dropzone" id="my-awesome-dropzone" enctype="multipart/form-data"></form>
</div>
<div class="col s6">
<div id="preview_video">
{% if video %}
<iframe src="https://player.vimeo.com{{ video.getCdnUrl()|replace({ "videos": "video"}) }}" width="200" height="150" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
{% endif %}
</div>
</div>
</div>
{% endblock %}
+13 -1
View File
@@ -8,6 +8,7 @@ imports:
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: fr
media_video_dir: '%kernel.root_dir%/../web/uploads/videos/'
framework:
#esi: ~
@@ -92,4 +93,15 @@ edeclic_prestashop_bridge:
prestashop:
cookie_key: 9YUQ5jPqT4Z4x5s9B25pb1yuGBtpaeBDxpWDgicPF3CuP8F2p9aK18ZS
presta_path: /home/projects/prestashop1/www
shop_id: 1
shop_id: 1 sender_name: jean-claude
request_lab_vimeo:
client_id: "83e90acc0793d3e5ea7e1df477e536611a36bdd0"
client_secret: "LdbzEX6DYTLou/0aART0B7zQoeGiKQEzDrP/IVNVMeAEcdzi4KEPBwsTORaGm2ZwN6ORgKO1B2TCW8PRyuFEN546SsmVxWDxTW3/lJmxqTkbaxFAIKVRonUS+Ujnd0Ji"
access_token: "8722974151bf40d523b0fd65aef970d6"
dubture_f_fmpeg:
ffmpeg_binary: /usr/bin/ffmpeg
ffprobe_binary: /usr/bin/ffprobe
binary_timeout: 300 # Use 0 for infinite
threads_count: 4
+4 -4
View File
@@ -1,7 +1,6 @@
# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/service_container.html
parameters:
# parameter_name: value
services:
app.form.registration:
@@ -16,6 +15,7 @@ services:
redirect.after.login:
class: AppBundle\Utils\Services\AfterLoginRedirection
arguments: ['@router']
media_manager:
class: AppBundle\Utils\Services\MediaManager
arguments: ["@doctrine.orm.entity_manager","@vimeo","@dubture_ffmpeg.ffprobe","%media_video_dir%"]
+6 -2
View File
@@ -38,7 +38,11 @@
"doctrine/mongodb-odm-bundle": "^3.0",
"doctrine/mongodb-odm": "^1.0",
"alcaeus/mongo-php-adapter": "^1.0",
"dunglas/doctrine-json-odm": "dev-master"
"dunglas/doctrine-json-odm": "dev-master",
"php-ffmpeg/php-ffmpeg": "^0.5",
"requestlab/vimeo-bundle": "^0.0.3",
"vimeo/vimeo-api": "^1.1",
"pulse00/ffmpeg-bundle": "^0.6.0"
},
"require-dev": {
"sensio/generator-bundle": "^3.0",
@@ -73,4 +77,4 @@
},
"branch-alias": null
}
}
}
+385 -5
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "3fb299c6fa430ac5c84896c4330e50b5",
"content-hash": "11e6fe97b1ec8f3ebf91e4e46429fc80",
"packages": [
{
"name": "alcaeus/mongo-php-adapter",
@@ -69,6 +69,63 @@
],
"time": "2017-01-29T08:35:26+00:00"
},
{
"name": "alchemy/binary-driver",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/BinaryDriver.git",
"reference": "80c6633890afb71d2417ae851d0ad167d8b00b95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/80c6633890afb71d2417ae851d0ad167d8b00b95",
"reference": "80c6633890afb71d2417ae851d0ad167d8b00b95",
"shasum": ""
},
"require": {
"evenement/evenement": "^2.0|^1.0",
"monolog/monolog": "^1.3",
"php": ">=5.5",
"psr/log": "^1.0",
"symfony/process": "^2.0|^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Alchemy": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
},
{
"name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com"
}
],
"description": "A set of tools to build binary drivers",
"keywords": [
"binary",
"driver"
],
"time": "2016-03-02T13:49:15+00:00"
},
{
"name": "doctrine/annotations",
"version": "v1.4.0",
@@ -1141,18 +1198,58 @@
],
"time": "2016-12-09T13:24:21+00:00"
},
{
"name": "evenement/evenement",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/igorw/evenement.git",
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Evenement": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch",
"homepage": "http://wiedler.ch/igor/"
}
],
"description": "Événement is a very simple event dispatching library for PHP 5.3",
"keywords": [
"event-dispatcher"
],
"time": "2012-05-30T15:01:08+00:00"
},
{
"name": "friendsofsymfony/user-bundle",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git",
"reference": "88b87249206fd867d5de8cee82e60885c0c8f749"
"reference": "4a6415b1254db6e8ea0886ead5c35888c02ccaf9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/88b87249206fd867d5de8cee82e60885c0c8f749",
"reference": "88b87249206fd867d5de8cee82e60885c0c8f749",
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/4a6415b1254db6e8ea0886ead5c35888c02ccaf9",
"reference": "4a6415b1254db6e8ea0886ead5c35888c02ccaf9",
"shasum": ""
},
"require": {
@@ -1216,7 +1313,7 @@
"keywords": [
"User management"
],
"time": "2017-03-19T13:49:51+00:00"
"time": "2017-03-09T15:14:58+00:00"
},
{
"name": "incenteev/composer-parameter-handler",
@@ -1455,6 +1552,46 @@
],
"time": "2017-03-13T07:08:03+00:00"
},
{
"name": "neutron/temporary-filesystem",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/romainneutron/Temporary-Filesystem.git",
"reference": "0a72a1c858b95fd469d87baa333f627978504ea8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/romainneutron/Temporary-Filesystem/zipball/0a72a1c858b95fd469d87baa333f627978504ea8",
"reference": "0a72a1c858b95fd469d87baa333f627978504ea8",
"shasum": ""
},
"require": {
"php": "^5.3.9 || ^7.0",
"symfony/filesystem": "^2.3 || ^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"type": "library",
"autoload": {
"psr-0": {
"Neutron": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com"
}
],
"description": "Symfony filesystem extension to handle temporary files",
"time": "2016-03-05T10:22:50+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.10",
@@ -1503,6 +1640,108 @@
],
"time": "2017-03-13T16:27:32+00:00"
},
{
"name": "php-ffmpeg/php-ffmpeg",
"version": "0.5.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-FFMpeg/PHP-FFMpeg.git",
"reference": "c8949fe3df89edd7692368cc110a51a27971f28a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-FFMpeg/PHP-FFMpeg/zipball/c8949fe3df89edd7692368cc110a51a27971f28a",
"reference": "c8949fe3df89edd7692368cc110a51a27971f28a",
"shasum": ""
},
"require": {
"alchemy/binary-driver": "~1.5",
"doctrine/cache": "~1.0",
"evenement/evenement": "~1.0",
"neutron/temporary-filesystem": "~2.1, >=2.1.1",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~3.7",
"sami/sami": "~1.0",
"silex/silex": "~1.0"
},
"suggest": {
"php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.5-dev"
}
},
"autoload": {
"psr-0": {
"FFMpeg": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
}
],
"description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"video",
"video processing"
],
"time": "2014-08-26T08:46:56+00:00"
},
{
"name": "phpexiftool/exiftool",
"version": "10.16",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/exiftool.git",
"reference": "c47639a6e9d8fd9746c8c24725e3c3e1e7eb0cbb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/exiftool/zipball/c47639a6e9d8fd9746c8c24725e3c3e1e7eb0cbb",
"reference": "c47639a6e9d8fd9746c8c24725e3c3e1e7eb0cbb",
"shasum": ""
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"Perl Licensing"
],
"authors": [
{
"name": "Phil Harvey",
"email": "phil@owl.phy.queensu.ca",
"homepage": "http://www.sno.phy.queensu.ca/~phil/exiftool/"
}
],
"description": "Exiftool is a library for reading, writing and editing meta information. This package is not PHP, but required for the main PHP driver : PHP Exiftool",
"keywords": [
"exiftool",
"metadata"
],
"time": "2016-05-09T09:08:26+00:00"
},
{
"name": "psr/cache",
"version": "1.0.1",
@@ -1596,6 +1835,106 @@
],
"time": "2016-10-10T12:19:37+00:00"
},
{
"name": "pulse00/ffmpeg-bundle",
"version": "0.6.0",
"source": {
"type": "git",
"url": "https://github.com/pulse00/ffmpeg-bundle.git",
"reference": "43014797e87e5d79322e59973e9925a88d64f9e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pulse00/ffmpeg-bundle/zipball/43014797e87e5d79322e59973e9925a88d64f9e9",
"reference": "43014797e87e5d79322e59973e9925a88d64f9e9",
"shasum": ""
},
"require": {
"php": "^5.3.9 || ^7.0",
"php-ffmpeg/php-ffmpeg": "^0.5 || ^0.6",
"symfony/dependency-injection": "^2.3 || ^3.0",
"symfony/framework-bundle": "^2.3 || ^3.0"
},
"require-dev": {
"matthiasnoback/symfony-dependency-injection-test": "~0.7",
"phpunit/phpunit": "^4.8"
},
"type": "symfony-bundle",
"autoload": {
"psr-4": {
"Dubture\\FFmpegBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Robert Gruendler",
"email": "r.gruendler@gmail.com"
}
],
"description": "Symfony bundle to provide PHP-FFmpeg as a Symfony service (https://github.com/alchemy-fr/PHP-FFmpeg)",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"multimedia",
"video",
"video processing"
],
"time": "2016-03-07T09:47:04+00:00"
},
{
"name": "requestlab/vimeo-bundle",
"version": "0.0.3",
"target-dir": "RequestLab/VimeoBundle",
"source": {
"type": "git",
"url": "https://github.com/RequestLab/VimeoBundle.git",
"reference": "ee20bfe8968fb0cfcbbb7584d2be07203001ff05"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/RequestLab/VimeoBundle/zipball/ee20bfe8968fb0cfcbbb7584d2be07203001ff05",
"reference": "ee20bfe8968fb0cfcbbb7584d2be07203001ff05",
"shasum": ""
},
"require": {
"symfony/framework-bundle": "3.*",
"vimeo/vimeo-api": "1.*"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"type": "symfony-bundle",
"autoload": {
"psr-0": {
"RequestLab\\VimeoBundle": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Yann Lecommandoux",
"email": "yann@requestlab.fr"
}
],
"keywords": [
"api",
"server",
"symfony",
"vimeo"
],
"time": "2016-11-28T08:54:50+00:00"
},
{
"name": "sensio/distribution-bundle",
"version": "v5.0.18",
@@ -2478,6 +2817,47 @@
"templating"
],
"time": "2017-02-27T00:16:20+00:00"
},
{
"name": "vimeo/vimeo-api",
"version": "1.2.6",
"source": {
"type": "git",
"url": "https://github.com/vimeo/vimeo.php.git",
"reference": "34a2b06801db3318ebb983821945293773691915"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vimeo/vimeo.php/zipball/34a2b06801db3318ebb983821945293773691915",
"reference": "34a2b06801db3318ebb983821945293773691915",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Vimeo\\": "src/Vimeo"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Vimeo",
"homepage": "http://vimeo.com"
}
],
"description": "Official PHP library for the Vimeo API.",
"homepage": "https://github.com/vimeo/vimeo.php",
"keywords": [
"video",
"vimeo"
],
"time": "2016-12-02T16:03:55+00:00"
}
],
"packages-dev": [
@@ -0,0 +1,56 @@
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Ad;
use AppBundle\Form\AdType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class AdController extends Controller
{
/**
* @Route("/annonce/create", name="create_ad")
*/
public function createAdAction(Request $request)
{
$ad = new Ad;
$form = $this->createForm(AdType::class, $ad);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$ad = $form->getData();
$ad->setCreator($this->getUser());
$ad->setReferenceTt(uniqid('ad_'));
$em->persist($ad);
$em->flush();
$em->clear();
return $this->redirectToRoute('list_ad');
}
return $this->render('default/createAd.html.twig', array(
'form' => $form->createView(),
));
}
/**
* @Route("/annonce", name="list_ad")
*/
public function listAdAction()
{
$em = $this->getDoctrine()->getManager();
$ads = $em->getRepository('AppBundle:Ad')->findBy(array('creator'=> $this->getUser()));
/*$vimeo = $this->get('vimeo');
$adArray = array();
foreach($ads as $ad){
$response = $vimeo->request($ad->getVideo()->getCdnUrl(),array(),'GET');
var_dump($response);
$adArray[]['status'] = $response['status'];
}*/
return $this->render('default/listAd.html.twig', array(
'list' => $ads,
));
}
}
@@ -0,0 +1,85 @@
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Answer;
use AppBundle\Form\AnswerType;
use AppBundle\Entity\Ad;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
class AnswerController extends Controller
{
/**
* @Route("/reponse/create/{id}", name="create_answer")
*/
public function createAnswerAction(Request $request, Ad $ad)
{
$em = $this->getDoctrine()->getManager();
$existAnswer = $em->getRepository('AppBundle:Answer')->findOneBy(array(
'user' => $this->getUser(),
'ad' => $ad
));
if($existAnswer) {
$answer = $existAnswer;
} else {
$answer = new Answer;
$answer->setUser($this->getUser());
$answer->setAd($ad);
$answer->setStatus('DRAFT');
$em->persist($answer);
$em->flush();
$em->clear();
}
$video = $answer->getVideo();
$form = $this->createForm(AnswerType::class, $answer);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->redirectToRoute('list_ad');
}
return $this->render('default/createAnswer.html.twig', array(
'form' => $form->createView(),
'answer' => $answer,
'video' => $video
));
}
/**
* @Route("/media/deleteAnswer/{id}", name="delete_media_answer")
*/
public function removeFileAnswerAction(Request $request, Answer $answer)
{
$mediaManager = $this->get('media_manager');
$message = $mediaManager->remove($answer);
return new JsonResponse($message);
}
/**
* @Route("/media/uploadAnswer/{id}", name="upload_media_answer")
*/
public function uploadAnswerAction(Request $request, Answer $answer)
{
$message = array( 'success' => 200,
'filename' => null,
'originalFilename' => null
);
foreach($request->files as $uploadedFile) {
$mediaManager = $this->get('media_manager');
$message = $mediaManager->upload($answer, $uploadedFile, $this->getUser());
}
return new JsonResponse($message);
}
}
@@ -3,8 +3,15 @@
namespace AppBundle\Controller;
use AppBundle\Entity\Company;
use AppBundle\Entity\Ad;
use AppBundle\Entity\Media;
use AppBundle\Utils\Exif;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class DefaultController extends Controller
@@ -72,5 +79,5 @@ class DefaultController extends Controller
return $this->render('default/index.html.twig', [
]);
}
}
}
@@ -0,0 +1,96 @@
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Ad;
use AppBundle\Entity\Media;
use AppBundle\Utils\Exif;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
class MediaController extends Controller
{
/**
* @Route("/media/create/{id}", name="create_media")
*/
public function createMediaAction(Request $request,Ad $ad)
{
if ($this->container->has('profiler')) {
$this->container->get('profiler')->disable();
}
if($ad){
$video = $ad->getVideo();
}
// Get Avalaible videos
$em = $this->getDoctrine()->getManager();
$videos = $em->getRepository('AppBundle:Media')->findBy(array('creator'=> $this->getUser()));
$form = $this->createFormBuilder($video)
->add('title', TextType::class)
->add('save', SubmitType::class, array('label' => 'Create Média'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$media = $form->getData();
$em->persist($media);
$em->flush();
return $this->redirectToRoute('list_ad');
}
return $this->render('default/createMedia.html.twig', array(
'form' => $form->createView(),
'ad' => $ad,
'video' => $video,
'videos' => $videos
));
}
/**
* @Route("/media/upload/{id}", name="upload_media")
*/
public function uploadAction(Request $request, Ad $ad)
{
$message = array( 'success' => 200,
'filename' => null,
'originalFilename' => null
);
foreach($request->files as $uploadedFile) {
$mediaManager = $this->get('media_manager');
$message = $mediaManager->upload($ad, $uploadedFile, $this->getUser());
}
return new JsonResponse($message);
}
/**
* @Route("/media/delete/{id}", name="delete_media")
*/
public function removeFileAction(Request $request, Ad $ad)
{
$mediaManager = $this->get('media_manager');
$message = $mediaManager->remove($ad);
return new JsonResponse($message);
}
/**
* @Route("/media/link/{id}", name="link_media")
*/
public function mediaLinkAction(Request $request, Ad $ad)
{
$em = $this->getDoctrine()->getManager();
$video = $em->getRepository('AppBundle:Media')->find($request->request->get('idVideo'));
$ad->setVideo($video);
$em->persist($ad);
$em->flush();
return new JsonResponse(array('success' => "true"));
}
}
+52 -14
View File
@@ -38,7 +38,7 @@ class Ad
*
* @ORM\Column(name="reference_tt", type="string", length=255)
*/
private $reference_tt;
private $referenceTt;
/**
* @var string
@@ -57,42 +57,70 @@ class Ad
/**
* @var \DateTime
*
* @ORM\Column(name="p_time", type="datetime", nullable=true)
* @ORM\Column(name="published_at", type="datetime", nullable=true)
*/
private $pTime;
private $publishedAt;
/**
* @var \DateTime
*
* @ORM\Column(name="e_time", type="datetime", nullable=true)
* @ORM\Column(name="unpublished_at", type="datetime", nullable=true)
*/
private $eTime;
private $unpublishedAt;
/**
* @var int
* @var boolean
*
* @ORM\Column(name="status", type="smallint", nullable=true, options={"comment":"Etat de visibilite"})
* @ORM\Column(name="status", type="string", nullable=true, options={"comment":"Etat de visibilite"})
*/
private $status;
/**
* @var array
* @var boolean
*
* @ORM\Column(name="public_tag", type="json_array", nullable=true)
* @ORM\Column(name="is_verified", type="boolean", nullable=true, options={"comment":"Etat de vérification"})
*/
private $public_tag;
private $isVerified;
/**
* @var boolean
*
* @ORM\Column(name="is_online", type="boolean", nullable=true, options={"comment":"En ligne"})
*/
private $isOnline;
/**
* @var boolean
*
* @ORM\Column(name="is_answerable", type="boolean", nullable=true, options={"comment":"Peux t'on répondre'"})
*/
private $isAnswerable;
/**
* @var integer
*
* @ORM\Column(name="defcon", type="smallint", nullable=true, options={"comment":"Etat d'alerte de modération"})
*/
private $defcon;
/**
* @var array
*
* @ORM\Column(name="private_tag", type="json_array", nullable=true)
* @ORM\Column(name="public_tag", type="json_document", nullable=true)
*/
private $private_tag;
private $publicTag;
/**
* @var array
*
* @ORM\Column(name="extra", type="json_array", nullable=true)
* @ORM\Column(name="private_tag", type="json_document", nullable=true)
*/
private $privateTag;
/**
* @var array
*
* @ORM\Column(name="extra", type="json_document", nullable=true)
*/
private $extra;
@@ -106,6 +134,11 @@ class Ad
*/
private $video;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Company", inversedBy="ads")
*/
private $company;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="ads")
*/
@@ -116,6 +149,11 @@ class Ad
*/
private $answers;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Note", cascade={"persist"})
*/
private $draftNotes;
public function __construct()
{
$this->answers = new \Doctrine\Common\Collections\ArrayCollection();
@@ -138,7 +176,7 @@ class Ad
* @param string $reference
*
* @return Ad
*/
*/
public function setReference($reference)
{
$this->reference = $reference;
+26 -2
View File
@@ -36,7 +36,7 @@ class Answer
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Ad", inversedBy="answers")
*/
protected $ad;
private $ad;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="answers", cascade={"persist"})
@@ -46,7 +46,7 @@ class Answer
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Media", cascade={"persist"})
*/
private $media;
private $video;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Note", cascade={"persist"})
@@ -232,4 +232,28 @@ class Answer
{
return $this->notes;
}
/**
* Set video.
*
* @param \AppBundle\Entity\Media|null $video
*
* @return Answer
*/
public function setVideo(\AppBundle\Entity\Media $video = null)
{
$this->video = $video;
return $this;
}
/**
* Get video.
*
* @return \AppBundle\Entity\Media|null
*/
public function getVideo()
{
return $this->video;
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ class Answer
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Media", cascade={"persist"})
*/
private $media;
private $video;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Note", cascade={"persist"})
+1 -1
View File
@@ -44,7 +44,7 @@ class Bookmark
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="bookmarks")
*/
protected $creator;
private $creator;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\User", mappedBy="sharedBookmarks" ,cascade={"persist"})
+1 -1
View File
@@ -36,7 +36,7 @@ class BookmarkSearch
/**
* @ORM\oneToOne(targetEntity="AppBundle\Entity\Bookmark", cascade={"persist"})
*/
protected $bookmark;
private $bookmark;
/**
* @var bool
+2 -2
View File
@@ -41,12 +41,12 @@ class BookmarkUser
/**
* @ORM\oneToOne(targetEntity="AppBundle\Entity\Bookmark", cascade={"persist"})
*/
protected $bookmark;
private $bookmark;
/**
* @ORM\oneToOne(targetEntity="AppBundle\Entity\User", cascade={"persist"})
*/
protected $user;
private $user;
/**
+25 -6
View File
@@ -29,9 +29,16 @@ class Company
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
* @ORM\Column(name="brand_name", type="string", length=255, options={"comment":"Nom commercial"})
*/
private $name;
private $brandName;
/**
* @var string
*
* @ORM\Column(name="business_name", type="string", length=255, options={"comment":"Raison sociale"})
*/
private $businessName;
/**
* @var text
@@ -41,7 +48,7 @@ class Company
private $description;
/**
* @ORM\Column(name="address", type="json_document", length=255, nullable=true)
* @ORM\Column(name="address", type="json_document", nullable=true)
*/
private $addresses;
@@ -50,14 +57,14 @@ class Company
*
* @ORM\Column(name="logo", type="string", nullable=true)
*/
protected $logo;
private $logo;
/**
* @var string
*
* @ORM\Column(name="website", type="string", nullable=true)
*/
protected $website;
private $website;
/**
* @var string
@@ -66,6 +73,18 @@ class Company
*/
private $alias;
/**
* @var array
*
* @ORM\Column(name="public_tag", type="json_document", nullable=true)
*/
private $publicTag;
/**
* @ORM\oneToMany(targetEntity="AppBundle\Entity\Ad",mappedBy="company", cascade={"persist"})
*/
private $ads;
/**
* @var array
*
@@ -81,7 +100,7 @@ class Company
/**
* @ORM\oneToMany(targetEntity="AppBundle\Entity\User", mappedBy="company", cascade={"persist"})
*/
protected $users;
private $users;
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Media", cascade={"persist"})
+11 -6
View File
@@ -38,14 +38,14 @@ class Media
*
* @ORM\Column(name="original_url", type="string", length=255)
*/
private $original_url;
private $originalUrl;
/**
* @var string
*
* @ORM\Column(name="cdn_url", type="string", length=255)
*/
private $cdn_url;
private $cdnUrl;
/**
* @var string
@@ -71,17 +71,22 @@ class Media
/**
* @var bool
*
* @ORM\Column(name="is_active", type="boolean", nullable=true)
* @ORM\Column(name="is_visible", type="boolean", nullable=true)
*/
private $isActive;
private $isVisible;
/**
* @var string
*
* @ORM\Column(name="status", type="string", length=255)
*/
private $status;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="medias")
*/
private $creator;
/**
* Get id.
*
+1 -1
View File
@@ -36,7 +36,7 @@ class Note
/**
* @ORM\oneToOne(targetEntity="AppBundle\Entity\User", cascade={"persist"})
*/
protected $author;
private $author;
/**
* Get id.
+18 -25
View File
@@ -24,65 +24,50 @@ class User extends BaseUser
*
* @ORM\Column(name="firstname", type="string", length=255, nullable=true)
*/
protected $firstname;
private $firstname;
/**
* @var string
*
* @ORM\Column(name="lastname", type="string", length=255, nullable=true)
*/
protected $lastname;
private $lastname;
/**
* @var \DateTime
*
* @ORM\Column(name="birthday", type="datetime", length=255, nullable=true)
*/
protected $birthday;
private $birthday;
/**
* @var string
*
* @ORM\Column(name="profile_photo", type="string", length=255, nullable=true)
* @ORM\Column(name="photo", type="string", length=255, nullable=true)
*/
protected $profilePhoto;
private $photo;
/**
* @var string
*
* @ORM\Column(name="gender", type="string", length=255, nullable=true)
*/
protected $gender;
/**
* @var array
*
* @ORM\Column(name="private_tag", type="json_array", nullable=true)
*/
private $private_tag;
/**
* @var string
*
* @ORM\Column(name="extra", type="json_array", nullable=true)
*/
protected $extra;
private $gender;
/**
* @ORM\oneToMany(targetEntity="AppBundle\Entity\Ad",mappedBy="creator", cascade={"persist"})
*/
protected $ads;
private $ads;
/**
* @ORM\oneToMany(targetEntity="AppBundle\Entity\Media",mappedBy="creator", cascade={"persist"})
*/
protected $medias;
private $medias;
/**
* @ORM\oneToMany(targetEntity="AppBundle\Entity\Bookmark",mappedBy="creator", cascade={"persist"})
*/
protected $bookmarks;
private $bookmarks;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Company", inversedBy="users")
@@ -97,7 +82,15 @@ class User extends BaseUser
/**
* @ORM\oneToMany(targetEntity="AppBundle\Entity\Answer",mappedBy="user", cascade={"persist"})
*/
protected $answers;
private $answers;
/**
* @var string
*
* @ORM\Column(name="status", type="string", nullable=true, options={"comment":"Etat de visibilite"})
*/
private $status;
public function __construct()
+21
View File
@@ -0,0 +1,21 @@
<?php
// src/AppBundle/Form/TaskType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class AdType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reference', TextType::class)
->add('title', TextType::class)
->add('description', TextType::class)
->add('save', SubmitType::class, array('label' => 'Je créé mon annonce'));
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class AnswerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('status', TextType::class)
->add('save', SubmitType::class, array('label' => 'Je répond à l\'annonce'));
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace AppBundle\Utils;
class Exif
{
public static function getMetadata($file = null)
{
if($file){
$toolpath = exec('which exiftool');
$resultJson = self::getCliOutput(
sprintf(
'%1$s -json -struct -a -charset %3$s %2$s',
$toolpath,
escapeshellarg($file),
'UTF-8'
)
);
return $resultJson;
} else {
return "{}";
}
}
private function getCliOutput($command)
{
$descriptorspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'a')
);
$process = proc_open($command, $descriptorspec, $pipes);
if (!is_resource($process)) {
throw new RuntimeException(
'Could not open a resource to the exiftool binary'
);
}
$result = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
return $result;
}
}
@@ -0,0 +1,80 @@
<?php
namespace AppBundle\Utils\Services;
use AppBundle\Entity\Media;
use AppBundle\Utils\Exif;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
class MediaManager
{
protected $em;
protected $vimeo;
protected $ffprobe;
protected $mediaVideoDir;
public function __construct(\Doctrine\ORM\EntityManager $em, $vimeo, $ffprobe, $mediaVideoDir)
{
$this->em = $em;
$this->vimeo = $vimeo;
$this->ffprobe = $ffprobe;
$this->mediaVideoDir = $mediaVideoDir;
}
public function remove($entity)
{
$video = $entity->getVideo();
if (unlink($this->mediaVideoDir.$video->getOriginalUrl())){
$entity->setVideo(null);
$this->em->persist($entity);
$this->em->remove($video);
$this->em->flush();
return array('success' => "true");
} else {
return array('success' => "false");
}
}
public function upload($entity, $uploadedFile, $creator)
{
$media = new Media;
$fileName = md5(uniqid()).'.'.$uploadedFile->guessExtension();
$extension = $uploadedFile->guessExtension();
$file = $uploadedFile->move($this->mediaVideoDir, $fileName);
//GET FILE INFO
$filePath = $this->mediaVideoDir.$fileName;
$duration = $this->ffprobe->format($filePath)->get('duration');
$metadata = array();
$metadata['duration'] = $duration;
//PUSH VIDEO TO Vimeo
$uriVimeo = "/videos/208509565";
/*$response = $this->vimeo->request('/me/videos', array('type' => 'pull', 'link' => 'http://jeanneau.e-declic.tv/video/Prestige_chinaboatshow2012.mp4'), 'POST');
if($response['status'] == 200){
$uriVimeo = $response['body']['uri'];
$nameVimeo = $response['body']['name'];
$linkVimeo = $response['body']['link'];
}*/
//SAVE MEDIA
$media->setCreator($creator);
$media->setTitle($fileName);
$media->setOriginalUrl($fileName);
$media->setCdnUrl($uriVimeo);
$media->setMetadata(Exif::getMetadata($filePath));
$media->setFormat($extension);
$media->setType("video");
$this->em->persist($media);
$entity->setVideo($media);
$this->em->persist($entity);
$this->em->flush();
$this->em->clear();
$message = array( 'success' => 200,
'filename' => $fileName,
'originalFilename' => $uploadedFile->getClientOriginalName(),
'uriVimeo' => str_replace('videos','video',$uriVimeo)
);
return $message;
}
}
@@ -7,60 +7,60 @@ use Doctrine\ORM\Mapping as ORM;
trait TimestampableTrait
{
/**
* @var \DateTime $ctime
* @var \DateTime $cTime
*
* @ORM\Column(name="ctime", type="datetime")
* @ORM\Column(name="c_time", type="datetime")
*/
private $ctime;
private $cTime;
/**
* @var \DateTime $utime
* @var \DateTime $uTime
*
* @ORM\Column(name="utime", type="datetime")
* @ORM\Column(name="u_time", type="datetime")
*/
private $utime;
private $uTime;
/**
* Get ctime
* Get cTime
*
* @return \DateTime
*/
public function getCtime()
public function getCTime()
{
return $this->ctime;
return $this->cTime;
}
/**
* Set ctime
* Set cTime
*
* @param \DateTime $ctime
* @param \DateTime $cTime
*/
public function setCtime($ctime)
public function setCTime($cTime)
{
$this->ctime = $ctime;
$this->cTime = $cTime;
return $this;
}
/**
* Get utime
* Get uTime
*
* @return \DateTime
*/
public function getUtime()
public function getUTime()
{
return $this->utime;
return $this->uTime;
}
/**
* Set utime
* Set uTime
*
* @param \DateTime $utime
* @param \DateTime $uTime
*/
public function setUtime($utime)
public function setUTime($uTime)
{
$this->utime = $utime;
$this->uTime = $uTime;
return $this;
}
@@ -76,7 +76,7 @@ trait TimestampableTrait
*/
public function UpdateDate()
{
$this->setUtime(new \DateTime());
$this->setUTime(new \DateTime());
}
/**
@@ -85,6 +85,6 @@ trait TimestampableTrait
*/
public function CDate()
{
$this->setCtime(new \DateTime());
$this->setCTime(new \DateTime());
}
}
@@ -25,7 +25,7 @@ class EntityHistorySubscriber implements EventSubscriber
return array(
'postPersist',
'postUpdate',
'postRemove',
//'postRemove',
'preRemove',
);
}
@@ -0,0 +1,2 @@
/vendor/
composer.lock
+16
View File
@@ -0,0 +1,16 @@
language: php
sudo: false
matrix:
fast_finish: true
before_script:
- composer self-update
- composer install --prefer-source
php:
- 5.5
- 5.6
- 7.0
- hhvm
+64
View File
@@ -0,0 +1,64 @@
CHANGELOG
---------
* 1.6.0 (2015-03-02)
* BC Break: bump minimum PHP versions
* Allow use of evenement v2.0 (thanks @patkar for the P/R)
* 1.5.0 (2013-06-21)
* BC Break : ConfigurationInterface::get does not throw exceptions anymore
in case the key does not exist. Second argument is a default value to return
in case the key does not exist.
* 1.4.1 (2013-05-23)
* Add third parameter to BinaryInterface::command method to pass a listener or
an array of listener that will be registered just the time of the command.
* 1.4.0 (2013-05-11)
* Extract process run management to ProcessRunner.
* Add support for process listeners.
* Provides bundled DebugListener.
* Add BinaryInterface::command method.
* BC break : ProcessRunnerInterface::run now takes an SplObjectStorage containing
listeners as second argument.
* BC break : BinaryInterface no longer implements LoggerAwareInterface
as it is now supported by ProcessRunner.
* 1.3.4 (2013-04-26)
* Add BinaryDriver::run method.
* 1.3.3 (2013-04-26)
* Add BinaryDriver::createProcessMock method.
* 1.3.2 (2013-04-26)
* Add BinaryDriverTestCase for testing BinaryDriver implementations.
* 1.3.1 (2013-04-24)
* Add timeouts handling
* 1.3.0 (2013-04-24)
* Add BinaryInterface and AbstractBinary
* 1.2.1 (2013-04-24)
* Add ConfigurationAwareInterface
* Add ProcessBuilderAwareInterface
* 1.2.0 (2013-04-24)
* Add BinaryDriver\Configuration
* 1.1.0 (2013-04-24)
* Add support for timeouts via `setTimeout` method
* 1.0.0 (2013-04-23)
* First stable version.
+21
View File
@@ -0,0 +1,21 @@
BinaryDriver is released with MIT License :
Copyright (c) 2013 Alchemy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
+190
View File
@@ -0,0 +1,190 @@
# Binary Driver
Binary-Driver is a set of PHP tools to build binary drivers.
[![Build Status](https://travis-ci.org/alchemy-fr/BinaryDriver.png?branch=master)](https://travis-ci.org/alchemy-fr/BinaryDriver)
## Why ?
You may wonder *Why building a library while I can use `exec` or
[symfony/process](https://github.com/symfony/Process) ?*.
Here is a simple answer :
- If you use `exec`, `passthru`, `system`, `proc_open` or any low level process
handling in PHP, you should have a look to [symfony/process](https://github.com/symfony/Process)
component that will provide an OO portable, testable and secure interface to
deal with this. It seems easy at first approach, but if you look at this
component [unit tests](https://github.com/symfony/Process/tree/master/Tests),
you will see that handling process in a simple interface can easily become a
nightmare.
- If you already use symfony/process, and want to build binary drivers, you
will always have the same common set of methods and objects to configure, log,
debug, and generate processes.
This library is a base to implement any binary driver with this common set of
needs.
## AbstractBinary
`AbstractBinary` provides an abstract class to build a binary driver. It implements
`BinaryInterface`.
Implementation example :
```php
use Alchemy\BinaryDriver\AbstractBinary;
class LsDriver extends AbstractBinary
{
public function getName()
{
return 'ls driver';
}
}
$parser = new LsParser();
$driver = Driver::load('ls');
// will return the output of `ls -a -l`
$parser->parse($driver->command(array('-a', '-l')));
```
### Binary detection troubleshooting
If you are using Nginx with PHP-fpm, executable detection may not work because of an empty `$_ENV['path']`.
To avoid having an empty `PATH` environment variable, add the following line to your `fastcgi_params`
config file (replace `/your/current/path/` with the output of `printenv PATH`) :
```
fastcgi_param PATH /your/current/path
```
## Logging
You can log events with a `Psr\Log\LoggerInterface` by passing it in the load
method as second argument :
```php
$logger = new Monolog\Logger('driver');
$driver = Driver::load('ls', $logger);
```
## Listeners
You can add custom listeners on processes.
Listeners are built on top of [Evenement](https://github.com/igorw/evenement)
and must implement `Alchemy\BinaryDriver\ListenerInterface`.
```php
use Symfony\Component\Process\Process;
class DebugListener extends EventEmitter implements ListenerInterface
{
public function handle($type, $data)
{
foreach (explode(PHP_EOL, $data) as $line) {
$this->emit($type === Process::ERR ? 'error' : 'out', array($line));
}
}
public function forwardedEvents()
{
// forward 'error' events to the BinaryInterface
return array('error');
}
}
$listener = new DebugListener();
$driver = CustomImplementation::load('php');
// adds listener
$driver->listen($listener);
$driver->on('error', function ($line) {
echo '[ERROR] ' . $line . PHP_EOL;
});
// removes listener
$driver->unlisten($listener);
```
### Bundled listeners
The debug listener is a simple listener to catch `stderr` and `stdout` outputs ;
read the implementation for customization.
```php
use Alchemy\BinaryDriver\Listeners\DebugListener;
$driver = CustomImplementation::load('php');
$driver->listen(new DebugListener());
$driver->on('debug', function ($line) {
echo $line;
});
```
## ProcessBuilderFactory
ProcessBuilderFactory ease spawning processes by generating Symfony [Process]
(http://symfony.com/doc/master/components/process.html) objects.
```php
use Alchemy\BinaryDriver\ProcessBuilderFactory;
$factory = new ProcessBuilderFactory('/usr/bin/php');
// return a Symfony\Component\Process\Process
$process = $factory->create('-v');
// echoes '/usr/bin/php' '-v'
echo $process->getCommandLine();
$process = $factory->create(array('-r', 'echo "Hello !";'));
// echoes '/usr/bin/php' '-r' 'echo "Hello !";'
echo $process->getCommandLine();
```
## Configuration
A simple configuration object, providing an `ArrayAccess` and `IteratorAggregate`
interface.
```php
use Alchemy\BinaryDriver\Configuration;
$conf = new Configuration(array('timeout' => 0));
echo $conf->get('timeout');
if ($conf->has('param')) {
$conf->remove('param');
}
$conf->set('timeout', 20);
$conf->all();
```
Same example using the `ArrayAccess` interface :
```php
use Alchemy\BinaryDriver\Configuration;
$conf = new Configuration(array('timeout' => 0));
echo $conf['timeout'];
if (isset($conf['param'])) {
unset($conf['param']);
}
$conf['timeout'] = 20;
```
## License
This project is released under the MIT license.
+38
View File
@@ -0,0 +1,38 @@
{
"name": "alchemy/binary-driver",
"type": "library",
"description": "A set of tools to build binary drivers",
"keywords": ["binary", "driver"],
"license": "MIT",
"authors": [
{
"name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com"
},
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
}
],
"require": {
"php" : ">=5.5",
"evenement/evenement" : "^2.0|^1.0",
"monolog/monolog" : "^1.3",
"psr/log" : "^1.0",
"symfony/process" : "^2.0|^3.0"
},
"require-dev": {
"phpunit/phpunit" : "^4.0|^5.0"
},
"autoload": {
"psr-0": {
"Alchemy": "src"
}
}
}
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true"
verbose="false"
bootstrap="tests/bootstrap.php"
>
<php>
<ini name="display_errors" value="on"/>
</php>
<testsuites>
<testsuite>
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory>vendor</directory>
<directory>tests</directory>
</blacklist>
</filter>
</phpunit>
@@ -0,0 +1,220 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\Listeners;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Evenement\EventEmitter;
use Monolog\Logger;
use Monolog\Handler\NullHandler;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
abstract class AbstractBinary extends EventEmitter implements BinaryInterface
{
/** @var ConfigurationInterface */
protected $configuration;
/** @var ProcessBuilderFactoryInterface */
protected $factory;
/** @var ProcessRunner */
private $processRunner;
/** @var Listeners */
private $listenersManager;
public function __construct(ProcessBuilderFactoryInterface $factory, LoggerInterface $logger, ConfigurationInterface $configuration)
{
$this->factory = $factory;
$this->configuration = $configuration;
$this->processRunner = new ProcessRunner($logger, $this->getName());
$this->listenersManager = new Listeners();
$this->applyProcessConfiguration();
}
/**
* {@inheritdoc}
*/
public function listen(ListenerInterface $listener)
{
$this->listenersManager->register($listener, $this);
return $this;
}
/**
* {@inheritdoc}
*/
public function unlisten(ListenerInterface $listener)
{
$this->listenersManager->unregister($listener, $this);
return $this;
}
/**
* {@inheritdoc}
*/
public function getConfiguration()
{
return $this->configuration;
}
/**
* {@inheritdoc}
*
* @return BinaryInterface
*/
public function setConfiguration(ConfigurationInterface $configuration)
{
$this->configuration = $configuration;
$this->applyProcessConfiguration();
return $this;
}
/**
* {@inheritdoc}
*/
public function getProcessBuilderFactory()
{
return $this->factory;
}
/**
* {@inheritdoc}
*
* @return BinaryInterface
*/
public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory)
{
$this->factory = $factory;
$this->applyProcessConfiguration();
return $this;
}
/**
* {@inheritdoc}
*/
public function getProcessRunner()
{
return $this->processRunner;
}
/**
* {@inheritdoc}
*/
public function setProcessRunner(ProcessRunnerInterface $runner)
{
$this->processRunner = $runner;
return $this;
}
/**
* {@inheritdoc}
*/
public function command($command, $bypassErrors = false, $listeners = null)
{
if (!is_array($command)) {
$command = array($command);
}
return $this->run($this->factory->create($command), $bypassErrors, $listeners);
}
/**
* {@inheritdoc}
*/
public static function load($binaries, LoggerInterface $logger = null, $configuration = array())
{
$finder = new ExecutableFinder();
$binary = null;
$binaries = is_array($binaries) ? $binaries : array($binaries);
foreach ($binaries as $candidate) {
if (file_exists($candidate) && is_executable($candidate)) {
$binary = $candidate;
break;
}
if (null !== $binary = $finder->find($candidate)) {
break;
}
}
if (null === $binary) {
throw new ExecutableNotFoundException(sprintf(
'Executable not found, proposed : %s', implode(', ', $binaries)
));
}
if (null === $logger) {
$logger = new Logger(__NAMESPACE__ . ' logger');
$logger->pushHandler(new NullHandler());
}
$configuration = $configuration instanceof ConfigurationInterface ? $configuration : new Configuration($configuration);
return new static(new ProcessBuilderFactory($binary), $logger, $configuration);
}
/**
* Returns the name of the driver
*
* @return string
*/
abstract public function getName();
/**
* Executes a process, logs events
*
* @param Process $process
* @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions
* @param ListenerInterface|array $listeners A listener or an array of listener to register for this unique run
*
* @return string The Process output
*
* @throws ExecutionFailureException in case of process failure.
*/
protected function run(Process $process, $bypassErrors = false, $listeners = null)
{
if (null !== $listeners) {
if (!is_array($listeners)) {
$listeners = array($listeners);
}
$listenersManager = clone $this->listenersManager;
foreach ($listeners as $listener) {
$listenersManager->register($listener, $this);
}
} else {
$listenersManager = $this->listenersManager;
}
return $this->processRunner->run($process, $listenersManager->storage, $bypassErrors);
}
private function applyProcessConfiguration()
{
if ($this->configuration->has('timeout')) {
$this->factory->setTimeout($this->configuration->get('timeout'));
}
return $this;
}
}
@@ -0,0 +1,76 @@
<?php
namespace Alchemy\BinaryDriver;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
/**
* Convenient PHPUnit methods for testing BinaryDriverInterface implementations.
*/
class BinaryDriverTestCase extends \PHPUnit_Framework_TestCase
{
/**
* @return ProcessBuilderFactoryInterface
*/
public function createProcessBuilderFactoryMock()
{
return $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface');
}
/**
* @param integer $runs The number of runs expected
* @param Boolean $success True if the process expects to be successfull
* @param string $commandLine The commandline executed
* @param string $output The process output
* @param string $error The process error output
*
* @return Process
*/
public function createProcessMock($runs = 1, $success = true, $commandLine = null, $output = null, $error = null, $callback = false)
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$builder = $process->expects($this->exactly($runs))
->method('run');
if (true === $callback) {
$builder->with($this->isInstanceOf('Closure'));
}
$process->expects($this->any())
->method('isSuccessful')
->will($this->returnValue($success));
foreach (array(
'getOutput' => $output,
'getErrorOutput' => $error,
'getCommandLine' => $commandLine,
) as $command => $value) {
$process
->expects($this->any())
->method($command)
->will($this->returnValue($value));
}
return $process;
}
/**
* @return LoggerInterface
*/
public function createLoggerMock()
{
return $this->getMock('Psr\Log\LoggerInterface');
}
/**
* @return ConfigurationInterface
*/
public function createConfigurationMock()
{
return $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface');
}
}
@@ -0,0 +1,67 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Psr\Log\LoggerInterface;
use Evenement\EventEmitterInterface;
interface BinaryInterface extends ConfigurationAwareInterface, ProcessBuilderFactoryAwareInterface, ProcessRunnerAwareInterface, EventEmitterInterface
{
/**
* Adds a listener to the binary driver
*
* @param ListenerInterface $listener
*
* @return BinaryInterface
*/
public function listen(ListenerInterface $listener);
/**
* Removes a listener from the binary driver
*
* @param ListenerInterface $listener
*
* @return BinaryInterface
*/
public function unlisten(ListenerInterface $listener);
/**
* Runs a command against the driver.
*
* Calling this method on a `ls` driver with the command `-a` would run `ls -a`.
*
* @param array|string $command A command or an array of command
* @param Boolean $bypassErrors If set to true, an erronous process will not throw an exception
* @param ListenerInterface|array $listeners A listener or an array of listeners to register for this unique run
*
* @return string The command output
*
* @throws ExecutionFailureException in case of process failure.
*/
public function command($command, $bypassErrors = false, $listeners = null);
/**
* Loads a binary
*
* @param string|array $binaries A binary name or an array of binary names
* @param null|LoggerInterface $logger A Logger
* @param array|ConfigurationInterface $configuration The configuration
*
* @throws ExecutableNotFoundException In case none of the binaries were found
*
* @return BinaryInterface
*/
public static function load($binaries, LoggerInterface $logger = null, $configuration = array());
}
@@ -0,0 +1,107 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
class Configuration implements ConfigurationInterface
{
private $data;
public function __construct(array $data = array())
{
$this->data = $data;
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->data);
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
return isset($this->data[$key]) ? $this->data[$key] : $default;
}
/**
* {@inheritdoc}
*/
public function set($key, $value)
{
$this->data[$key] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function has($key)
{
return array_key_exists($key, $this->data);
}
/**
* {@inheritdoc}
*/
public function remove($key)
{
$value = $this->get($key);
unset($this->data[$key]);
return $value;
}
/**
* {@inheritdoc}
*/
public function all()
{
return $this->data;
}
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
return $this->has($offset);
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
$this->remove($offset);
}
}
@@ -0,0 +1,29 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
interface ConfigurationAwareInterface
{
/**
* Returns the configuration
*
* @return ConfigurationInterface
*/
public function getConfiguration();
/**
* Set the configuration
*
* @param ConfigurationInterface $configuration
*/
public function setConfiguration(ConfigurationInterface $configuration);
}
@@ -0,0 +1,58 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
interface ConfigurationInterface extends \ArrayAccess, \IteratorAggregate
{
/**
* Returns the value given a key from configuration
*
* @param string $key
* @param mixed $default The default value in case the key does not exist
*
* @return mixed
*/
public function get($key, $default = null);
/**
* Set a value to configuration
*
* @param string $key The key
* @param mixed $value The value corresponding to the key
*/
public function set($key, $value);
/**
* Tells if Configuration contains `$key`
*
* @param string $key
*
* @return Boolean
*/
public function has($key);
/**
* Removes a value given a key
*
* @param string $key
*
* @return mixed The previous value
*/
public function remove($key);
/**
* Returns all values set in the configuration
*
* @return array
*/
public function all();
}
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver\Exception;
interface ExceptionInterface
{
}
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver\Exception;
class ExecutableNotFoundException extends \RuntimeException implements ExceptionInterface
{
}
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver\Exception;
class ExecutionFailureException extends \RuntimeException implements ExceptionInterface
{
}
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
@@ -0,0 +1,58 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver\Listeners;
use Evenement\EventEmitter;
use Symfony\Component\Process\Process;
class DebugListener extends EventEmitter implements ListenerInterface
{
private $prefixOut;
private $prefixErr;
private $eventOut;
private $eventErr;
public function __construct($prefixOut = '[OUT] ', $prefixErr = '[ERROR] ', $eventOut = 'debug', $eventErr = 'debug')
{
$this->prefixOut = $prefixOut;
$this->prefixErr = $prefixErr;
$this->eventOut = $eventOut;
$this->eventErr = $eventErr;
}
/**
* {@inheritdoc}
*/
public function handle($type, $data)
{
if (Process::ERR === $type) {
$this->emitLines($this->eventErr, $this->prefixErr, $data);
} elseif (Process::OUT === $type) {
$this->emitLines($this->eventOut, $this->prefixOut, $data);
}
}
/**
* {@inheritdoc}
*/
public function forwardedEvents()
{
return array_unique(array($this->eventErr, $this->eventOut));
}
private function emitLines($event, $prefix, $lines)
{
foreach (explode("\n", $lines) as $line) {
$this->emit($event, array($prefix . $line));
}
}
}
@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver\Listeners;
use Evenement\EventEmitterInterface;
interface ListenerInterface extends EventEmitterInterface
{
/**
* Handle the output of a ProcessRunner
*
* @param string $type The data type, one of Process::ERR, Process::OUT constants
* @param string $data The output
*/
public function handle($type, $data);
/**
* An array of events that should be forwarded to BinaryInterface
*
* @return array
*/
public function forwardedEvents();
}
@@ -0,0 +1,88 @@
<?php
namespace Alchemy\BinaryDriver\Listeners;
use SplObjectStorage;
use Evenement\EventEmitter;
class Listeners extends EventEmitter
{
/** @var SplObjectStorage */
public $storage;
public function __construct()
{
$this->storage = new SplObjectStorage();
}
public function __clone()
{
$storage = $this->storage;
$this->storage = new SplObjectStorage();
$this->storage->addAll($storage);
}
/**
* Registers a listener, pass the listener events to the target.
*
* @param ListenerInterface $listener
* @param null|EventEmitter $target
*
* @return ListenersInterface
*/
public function register(ListenerInterface $listener, EventEmitter $target = null)
{
$EElisteners = array();
if (null !== $target) {
$EElisteners = $this->forwardEvents($listener, $target, $listener->forwardedEvents());
}
$this->storage->attach($listener, $EElisteners);
return $this;
}
/**
* Unregisters a listener, removes the listener events from the target.
*
* @param ListenerInterface $listener
*
* @return ListenersInterface
*
* @throws InvalidArgumentException In case the listener is not registered
*/
public function unregister(ListenerInterface $listener)
{
if (!isset($this->storage[$listener])) {
throw new InvalidArgumentException('Listener is not registered.');
}
foreach ($this->storage[$listener] as $event => $EElistener) {
$listener->removeListener($event, $EElistener);
}
$this->storage->detach($listener);
return $this;
}
private function forwardEvents($source, $target, array $events)
{
$EElisteners = array();
foreach ($events as $event) {
$listener = $this->createListener($event, $target);
$source->on($event, $EElisteners[$event] = $listener);
}
return $EElisteners;
}
private function createListener($event, $target)
{
return function () use ($event, $target) {
$target->emit($event, func_get_args());
};
}
}
@@ -0,0 +1,177 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use Symfony\Component\Process\ProcessBuilder;
class ProcessBuilderFactory implements ProcessBuilderFactoryInterface
{
/**
* The binary path
*
* @var String
*/
protected $binary;
/**
* The timeout for the generated processes
*
* @var integer|float
*/
private $timeout;
/**
* An internal ProcessBuilder.
*
* Note that this one is used only if Symfony ProcessBuilder has method
* setPrefix (2.3)
*
* @var ProcessBuilder
*/
private $builder;
/**
* Tells whether Symfony LTS ProcessBuilder should be emulated or not.
*
* This symfony version provided a brand new ::setPrefix method.
*
* @var Boolean
*/
public static $emulateSfLTS;
/**
* Constructor
*
* @param String $binary The path to the binary
*
* @throws InvalidArgumentException In case binary path is invalid
*/
public function __construct($binary)
{
$this->detectEmulation();
if (!self::$emulateSfLTS) {
$this->builder = new ProcessBuilder();
}
$this->useBinary($binary);
}
/**
* Covenient method for unit testing
*
* @return type
*/
public function getBuilder()
{
return $this->builder;
}
/**
* Covenient method for unit testing
*
* @param ProcessBuilder $builder
* @return ProcessBuilderFactory
*/
public function setBuilder(ProcessBuilder $builder)
{
$this->builder = $builder;
return $this;
}
/**
* @inheritdoc
*/
public function getBinary()
{
return $this->binary;
}
/**
* @inheritdoc
*/
public function useBinary($binary)
{
if (!is_executable($binary)) {
throw new InvalidArgumentException(sprintf('`%s` is not an executable binary', $binary));
}
$this->binary = $binary;
if (!static::$emulateSfLTS) {
$this->builder->setPrefix($binary);
}
return $this;
}
/**
* @inheritdoc
*/
public function setTimeout($timeout)
{
$this->timeout = $timeout;
if (!static::$emulateSfLTS) {
$this->builder->setTimeout($this->timeout);
}
return $this;
}
/**
* @inheritdoc
*/
public function getTimeout()
{
return $this->timeout;
}
/**
* @inheritdoc
*/
public function create($arguments = array())
{
if (null === $this->binary) {
throw new InvalidArgumentException('No binary set');
}
if (!is_array($arguments)) {
$arguments = array($arguments);
}
if (static::$emulateSfLTS) {
array_unshift($arguments, $this->binary);
return ProcessBuilder::create($arguments)
->setTimeout($this->timeout)
->getProcess();
} else {
return $this->builder
->setArguments($arguments)
->getProcess();
}
}
private function detectEmulation()
{
if (null !== static::$emulateSfLTS) {
return $this;
}
static::$emulateSfLTS = !method_exists('Symfony\Component\Process\ProcessBuilder', 'setPrefix');
return $this;
}
}
@@ -0,0 +1,29 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
interface ProcessBuilderFactoryAwareInterface
{
/**
* Returns the current process builder factory
*
* @return ProcessBuilderFactoryInterface
*/
public function getProcessBuilderFactory();
/**
* Set a process builder factory
*
* @param ProcessBuilderFactoryInterface $factory
*/
public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory);
}
@@ -0,0 +1,65 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use Symfony\Component\Process\Process;
interface ProcessBuilderFactoryInterface
{
/**
* Returns a new instance of Symfony Process
*
* @param string|array $arguments An argument or an array of arguments
*
* @return Process
*
* @throws InvalidArgumentException
*/
public function create($arguments = array());
/**
* Returns the path to the binary that is used
*
* @return String
*/
public function getBinary();
/**
* Sets the path to the binary
*
* @param String $binary A path to a binary
*
* @return ProcessBuilderFactoryInterface
*
* @throws InvalidArgumentException In case binary is not executable
*/
public function useBinary($binary);
/**
* Set the default timeout to apply on created processes.
*
* @param integer|float $timeout
*
* @return ProcessBuilderFactoryInterface
*
* @throws InvalidArgumentException In case the timeout is not valid
*/
public function setTimeout($timeout);
/**
* Returns the current timeout applied to the created processes.
*
* @return integer|float
*/
public function getTimeout();
}
@@ -0,0 +1,104 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Psr\Log\LoggerInterface;
use SplObjectStorage;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;
class ProcessRunner implements ProcessRunnerInterface
{
/** @var LoggerInterface */
private $logger;
/** @var string */
private $name;
public function __construct(LoggerInterface $logger, $name)
{
$this->logger = $logger;
$this->name = $name;
}
/**
* {@inheritdoc}
*
* @return ProcessRunner
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
return $this;
}
/**
* @return LoggerInterface
*/
public function getLogger()
{
return $this->logger;
}
/**
* {@inheritdoc}
*/
public function run(Process $process, SplObjectStorage $listeners, $bypassErrors)
{
$this->logger->info(sprintf(
'%s running command %s', $this->name, $process->getCommandLine()
));
try {
$process->run($this->buildCallback($listeners));
} catch (RuntimeException $e) {
if (!$bypassErrors) {
$this->doExecutionFailure($process->getCommandLine(), $e);
}
}
if (!$bypassErrors && !$process->isSuccessful()) {
$this->doExecutionFailure($process->getCommandLine());
} elseif (!$process->isSuccessful()) {
$this->logger->error(sprintf(
'%s failed to execute command %s', $this->name, $process->getCommandLine()
));
return;
} else {
$this->logger->info(sprintf('%s executed command successfully', $this->name));
return $process->getOutput();
}
}
private function buildCallback(SplObjectStorage $listeners)
{
return function ($type, $data) use ($listeners) {
foreach ($listeners as $listener) {
$listener->handle($type, $data);
}
};
}
private function doExecutionFailure($command, \Exception $e = null)
{
$this->logger->error(sprintf(
'%s failed to execute command %s', $this->name, $command
));
throw new ExecutionFailureException(sprintf(
'%s failed to execute command %s', $this->name, $command
), $e ? $e->getCode() : null, $e ?: null);
}
}
@@ -0,0 +1,29 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
interface ProcessRunnerAwareInterface
{
/**
* Returns the current process runner
*
* @return ProcessRunnerInterface
*/
public function getProcessRunner();
/**
* Sets a process runner
*
* @param ProcessRunnerInterface $runner
*/
public function setProcessRunner(ProcessRunnerInterface $runner);
}
@@ -0,0 +1,33 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Psr\Log\LoggerAwareInterface;
use SplObjectStorage;
use Symfony\Component\Process\Process;
interface ProcessRunnerInterface extends LoggerAwareInterface
{
/**
* Executes a process, logs events
*
* @param Process $process
* @param SplObjectStorage $listeners Some listeners
* @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions
*
* @return string The Process output
*
* @throws ExecutionFailureException in case of process failure.
*/
public function run(Process $process, SplObjectStorage $listeners, $bypassErrors);
}
@@ -0,0 +1,300 @@
<?php
namespace Alchemy\Tests\BinaryDriver;
use Alchemy\BinaryDriver\AbstractBinary;
use Alchemy\BinaryDriver\BinaryDriverTestCase;
use Alchemy\BinaryDriver\Configuration;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Symfony\Component\Process\ExecutableFinder;
class AbstractBinaryTest extends BinaryDriverTestCase
{
protected function getPhpBinary()
{
$finder = new ExecutableFinder();
$php = $finder->find('php');
if (null === $php) {
$this->markTestSkipped('Unable to find a php binary');
}
return $php;
}
public function testSimpleLoadWithBinaryPath()
{
$php = $this->getPhpBinary();
$imp = Implementation::load($php);
$this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp);
$this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary());
}
public function testMultipleLoadWithBinaryPath()
{
$php = $this->getPhpBinary();
$imp = Implementation::load(array('/zz/path/to/unexisting/command', $php));
$this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp);
$this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary());
}
public function testSimpleLoadWithBinaryName()
{
$php = $this->getPhpBinary();
$imp = Implementation::load('php');
$this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp);
$this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary());
}
public function testMultipleLoadWithBinaryName()
{
$php = $this->getPhpBinary();
$imp = Implementation::load(array('bachibouzouk', 'php'));
$this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp);
$this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary());
}
public function testLoadWithMultiplePathExpectingAFailure()
{
$this->setExpectedException(ExecutableNotFoundException::class);
Implementation::load(array('bachibouzouk', 'moribon'));
}
public function testLoadWithUniquePathExpectingAFailure()
{
$this->setExpectedException(ExecutableNotFoundException::class);
Implementation::load('bachibouzouk');
}
public function testLoadWithCustomLogger()
{
$logger = $this->getMock('Psr\Log\LoggerInterface');
$imp = Implementation::load('php', $logger);
$this->assertEquals($logger, $imp->getProcessRunner()->getLogger());
}
public function testLoadWithCustomConfigurationAsArray()
{
$conf = array('timeout' => 200);
$imp = Implementation::load('php', null, $conf);
$this->assertEquals($conf, $imp->getConfiguration()->all());
}
public function testLoadWithCustomConfigurationAsObject()
{
$conf = $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface');
$imp = Implementation::load('php', null, $conf);
$this->assertEquals($conf, $imp->getConfiguration());
}
public function testProcessBuilderFactoryGetterAndSetters()
{
$imp = Implementation::load('php');
$factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface');
$imp->setProcessBuilderFactory($factory);
$this->assertEquals($factory, $imp->getProcessBuilderFactory());
}
public function testConfigurationGetterAndSetters()
{
$imp = Implementation::load('php');
$conf = $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface');
$imp->setConfiguration($conf);
$this->assertEquals($conf, $imp->getConfiguration());
}
public function testTimeoutIsSetOnConstruction()
{
$imp = Implementation::load('php', null, array('timeout' => 42));
$this->assertEquals(42, $imp->getProcessBuilderFactory()->getTimeout());
}
public function testTimeoutIsSetOnConfigurationSetting()
{
$imp = Implementation::load('php', null);
$imp->setConfiguration(new Configuration(array('timeout' => 42)));
$this->assertEquals(42, $imp->getProcessBuilderFactory()->getTimeout());
}
public function testTimeoutIsSetOnProcessBuilderSetting()
{
$imp = Implementation::load('php', null, array('timeout' => 42));
$factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface');
$factory->expects($this->once())
->method('setTimeout')
->with(42);
$imp->setProcessBuilderFactory($factory);
}
public function testListenRegistersAListener()
{
$imp = Implementation::load('php');
$listeners = $this->getMockBuilder('Alchemy\BinaryDriver\Listeners\Listeners')
->disableOriginalConstructor()
->getMock();
$listener = $this->getMock('Alchemy\BinaryDriver\Listeners\ListenerInterface');
$listeners->expects($this->once())
->method('register')
->with($this->equalTo($listener), $this->equalTo($imp));
$reflexion = new \ReflectionClass('Alchemy\BinaryDriver\AbstractBinary');
$prop = $reflexion->getProperty('listenersManager');
$prop->setAccessible(true);
$prop->setValue($imp, $listeners);
$imp->listen($listener);
}
/**
* @dataProvider provideCommandParameters
*/
public function testCommandRunsAProcess($parameters, $bypassErrors, $expectedParameters, $output)
{
$imp = Implementation::load('php');
$factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface');
$processRunner = $this->getMock('Alchemy\BinaryDriver\ProcessRunnerInterface');
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$processRunner->expects($this->once())
->method('run')
->with($this->equalTo($process), $this->isInstanceOf('SplObjectStorage'), $this->equalTo($bypassErrors))
->will($this->returnValue($output));
$factory->expects($this->once())
->method('create')
->with($expectedParameters)
->will($this->returnValue($process));
$imp->setProcessBuilderFactory($factory);
$imp->setProcessRunner($processRunner);
$this->assertEquals($output, $imp->command($parameters, $bypassErrors));
}
/**
* @dataProvider provideCommandWithListenersParameters
*/
public function testCommandWithTemporaryListeners($parameters, $bypassErrors, $expectedParameters, $output, $count, $listeners)
{
$imp = Implementation::load('php');
$factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface');
$processRunner = $this->getMock('Alchemy\BinaryDriver\ProcessRunnerInterface');
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$firstStorage = $secondStorage = null;
$processRunner->expects($this->exactly(2))
->method('run')
->with($this->equalTo($process), $this->isInstanceOf('SplObjectStorage'), $this->equalTo($bypassErrors))
->will($this->returnCallback(function ($process, $storage, $errors) use ($output, &$firstStorage, &$secondStorage) {
if (null === $firstStorage) {
$firstStorage = $storage;
} else {
$secondStorage = $storage;
}
return $output;
}));
$factory->expects($this->exactly(2))
->method('create')
->with($expectedParameters)
->will($this->returnValue($process));
$imp->setProcessBuilderFactory($factory);
$imp->setProcessRunner($processRunner);
$this->assertEquals($output, $imp->command($parameters, $bypassErrors, $listeners));
$this->assertCount($count, $firstStorage);
$this->assertEquals($output, $imp->command($parameters, $bypassErrors));
$this->assertCount(0, $secondStorage);
}
public function provideCommandWithListenersParameters()
{
return array(
array('-a', false, array('-a'), 'loubda', 2, array($this->getMockListener(), $this->getMockListener())),
array('-a', false, array('-a'), 'loubda', 1, array($this->getMockListener())),
array('-a', false, array('-a'), 'loubda', 1, $this->getMockListener()),
array('-a', false, array('-a'), 'loubda', 0, array()),
);
}
public function provideCommandParameters()
{
return array(
array('-a', false, array('-a'), 'loubda'),
array('-a', true, array('-a'), 'loubda'),
array('-a -b', false, array('-a -b'), 'loubda'),
array(array('-a'), false, array('-a'), 'loubda'),
array(array('-a'), true, array('-a'), 'loubda'),
array(array('-a', '-b'), false, array('-a', '-b'), 'loubda'),
);
}
public function testUnlistenUnregistersAListener()
{
$imp = Implementation::load('php');
$listeners = $this->getMockBuilder('Alchemy\BinaryDriver\Listeners\Listeners')
->disableOriginalConstructor()
->getMock();
$listener = $this->getMock('Alchemy\BinaryDriver\Listeners\ListenerInterface');
$listeners->expects($this->once())
->method('unregister')
->with($this->equalTo($listener), $this->equalTo($imp));
$reflexion = new \ReflectionClass('Alchemy\BinaryDriver\AbstractBinary');
$prop = $reflexion->getProperty('listenersManager');
$prop->setAccessible(true);
$prop->setValue($imp, $listeners);
$imp->unlisten($listener);
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject
*/
private function getMockListener()
{
$listener = $this->getMock(ListenerInterface::class);
$listener->expects($this->any())
->method('forwardedEvents')
->willReturn(array());
return $listener;
}
}
class Implementation extends AbstractBinary
{
public function getName()
{
return 'Implementation';
}
}
@@ -0,0 +1,97 @@
<?php
namespace Alchemy\Tests\BinaryDriver;
use Symfony\Component\Process\ExecutableFinder;
use Alchemy\BinaryDriver\ProcessBuilderFactory;
abstract class AbstractProcessBuilderFactoryTest extends \PHPUnit_Framework_TestCase
{
public static $phpBinary;
private $original;
/**
* @return ProcessBuilderFactory
*/
abstract protected function getProcessBuilderFactory($binary);
public function setUp()
{
ProcessBuilderFactory::$emulateSfLTS = null;
if (null === static::$phpBinary) {
$this->markTestSkipped('Unable to detect php binary, skipping');
}
}
public static function setUpBeforeClass()
{
$finder = new ExecutableFinder();
static::$phpBinary = $finder->find('php');
}
public function testThatBinaryIsSetOnConstruction()
{
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$this->assertEquals(static::$phpBinary, $factory->getBinary());
}
public function testGetSetBinary()
{
$finder = new ExecutableFinder();
$phpUnit = $finder->find('phpunit');
if (null === $phpUnit) {
$this->markTestSkipped('Unable to detect phpunit binary, skipping');
}
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$factory->useBinary($phpUnit);
$this->assertEquals($phpUnit, $factory->getBinary());
}
/**
* @expectedException Alchemy\BinaryDriver\Exception\InvalidArgumentException
*/
public function testUseNonExistantBinary()
{
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$factory->useBinary('itissureitdoesnotexist');
}
public function testCreateShouldReturnAProcess()
{
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$process = $factory->create();
$this->assertInstanceOf('Symfony\Component\Process\Process', $process);
$this->assertEquals("'".static::$phpBinary."'", $process->getCommandLine());
}
public function testCreateWithStringArgument()
{
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$process = $factory->create('-v');
$this->assertInstanceOf('Symfony\Component\Process\Process', $process);
$this->assertEquals("'".static::$phpBinary."' '-v'", $process->getCommandLine());
}
public function testCreateWithArrayArgument()
{
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$process = $factory->create(array('-r', 'echo "Hello !";'));
$this->assertInstanceOf('Symfony\Component\Process\Process', $process);
$this->assertEquals("'".static::$phpBinary."' '-r' 'echo \"Hello !\";'", $process->getCommandLine());
}
public function testCreateWithTimeout()
{
$factory = $this->getProcessBuilderFactory(static::$phpBinary);
$factory->setTimeout(200);
$process = $factory->create(array('-i'));
$this->assertInstanceOf('Symfony\Component\Process\Process', $process);
$this->assertEquals(200, $process->getTimeout());
}
}
@@ -0,0 +1,78 @@
<?php
namespace Alchemy\Tests\BinaryDriver;
use Alchemy\BinaryDriver\Configuration;
class ConfigurationTest extends \PHPUnit_Framework_TestCase
{
public function testArrayAccessImplementation()
{
$configuration = new Configuration(array('key' => 'value'));
$this->assertTrue(isset($configuration['key']));
$this->assertEquals('value', $configuration['key']);
$this->assertFalse(isset($configuration['key2']));
unset($configuration['key']);
$this->assertFalse(isset($configuration['key']));
$configuration['key2'] = 'value2';
$this->assertTrue(isset($configuration['key2']));
$this->assertEquals('value2', $configuration['key2']);
}
public function testGetOnNonExistentKeyShouldReturnDefaultValue()
{
$conf = new Configuration();
$this->assertEquals('booba', $conf->get('hooba', 'booba'));
$this->assertEquals(null, $conf->get('hooba'));
}
public function testSetHasGetRemove()
{
$configuration = new Configuration(array('key' => 'value'));
$this->assertTrue($configuration->has('key'));
$this->assertEquals('value', $configuration->get('key'));
$this->assertFalse($configuration->has('key2'));
$configuration->remove('key');
$this->assertFalse($configuration->has('key'));
$configuration->set('key2', 'value2');
$this->assertTrue($configuration->has('key2'));
$this->assertEquals('value2', $configuration->get('key2'));
}
public function testIterator()
{
$data = array(
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
);
$captured = array();
$conf = new Configuration($data);
foreach ($conf as $key => $value) {
$captured[$key] = $value;
}
$this->assertEquals($data, $captured);
}
public function testAll()
{
$data = array(
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
);
$conf = new Configuration($data);
$this->assertEquals($data, $conf->all());
}
}
@@ -0,0 +1,66 @@
<?php
namespace Alchemy\Tests\BinaryDriver;
use Symfony\Component\Process\ProcessBuilder;
use Alchemy\BinaryDriver\ProcessBuilderFactory;
use Symfony\Component\Process\Process;
class LTSProcessBuilderFactoryTest extends AbstractProcessBuilderFactoryTest
{
protected function getProcessBuilderFactory($binary)
{
$factory = new ProcessBuilderFactory($binary);
$factory->setBuilder(new LTSProcessBuilder());
ProcessBuilderFactory::$emulateSfLTS = false;
$factory->useBinary($binary);
return $factory;
}
}
class LTSProcessBuilder extends ProcessBuilder
{
private $arguments;
private $prefix;
private $timeout;
public function __construct(array $arguments = array())
{
$this->arguments = $arguments;
parent::__construct($arguments);
}
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
return $this;
}
public function setPrefix($prefix)
{
$this->prefix = $prefix;
return $this;
}
public function setTimeout($timeout)
{
$this->timeout = $timeout;
return $this;
}
public function getProcess()
{
if (!$this->prefix && !count($this->arguments)) {
throw new LogicException('You must add() command arguments before calling getProcess().');
}
$args = $this->prefix ? array_merge(array($this->prefix), $this->arguments) : $this->arguments;
$script = implode(' ', array_map('escapeshellarg', $args));
return new Process($script, null, null, null, $this->timeout);
}
}
@@ -0,0 +1,33 @@
<?php
namespace Alchemy\Tests\BinaryDriver\Listeners;
use Alchemy\BinaryDriver\Listeners\DebugListener;
use Symfony\Component\Process\Process;
class DebugListenerTest extends \PHPUnit_Framework_TestCase
{
public function testHandle()
{
$listener = new DebugListener();
$lines = array();
$listener->on('debug', function ($line) use (&$lines) {
$lines[] = $line;
});
$listener->handle(Process::ERR, "first line\nsecond line");
$listener->handle(Process::OUT, "cool output");
$listener->handle('unknown', "lalala");
$listener->handle(Process::OUT, "another output\n");
$expected = array(
'[ERROR] first line',
'[ERROR] second line',
'[OUT] cool output',
'[OUT] another output',
'[OUT] ',
);
$this->assertEquals($expected, $lines);
}
}
@@ -0,0 +1,92 @@
<?php
namespace Alchemy\Tests\BinaryDriver\Listeners;
use Alchemy\BinaryDriver\Listeners\Listeners;
use Evenement\EventEmitter;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
class ListenersTest extends \PHPUnit_Framework_TestCase
{
public function testRegister()
{
$listener = new MockListener();
$listeners = new Listeners();
$listeners->register($listener);
$n = 0;
$listener->on('received', function ($type, $data) use (&$n, &$capturedType, &$capturedData) {
$n++;
$capturedData = $data;
$capturedType = $type;
});
$type = 'type';
$data = 'data';
$listener->handle($type, $data);
$listener->handle($type, $data);
$listeners->unregister($listener);
$listener->handle($type, $data);
$this->assertEquals(3, $n);
$this->assertEquals($type, $capturedType);
$this->assertEquals($data, $capturedData);
}
public function testRegisterAndForwardThenUnregister()
{
$listener = new MockListener();
$target = new EventEmitter();
$n = 0;
$target->on('received', function ($type, $data) use (&$n, &$capturedType, &$capturedData) {
$n++;
$capturedData = $data;
$capturedType = $type;
});
$m = 0;
$listener->on('received', function ($type, $data) use (&$m, &$capturedType2, &$capturedData2) {
$m++;
$capturedData2 = $data;
$capturedType2 = $type;
});
$listeners = new Listeners();
$listeners->register($listener, $target);
$type = 'type';
$data = 'data';
$listener->handle($type, $data);
$listener->handle($type, $data);
$listeners->unregister($listener, $target);
$listener->handle($type, $data);
$this->assertEquals(2, $n);
$this->assertEquals(3, $m);
$this->assertEquals($type, $capturedType);
$this->assertEquals($data, $capturedData);
$this->assertEquals($type, $capturedType2);
$this->assertEquals($data, $capturedData2);
}
}
class MockListener extends EventEmitter implements ListenerInterface
{
public function handle($type, $data)
{
$this->emit('received', array($type, $data));
}
public function forwardedEvents()
{
return array('received');
}
}
@@ -0,0 +1,15 @@
<?php
namespace Alchemy\Tests\BinaryDriver;
use Alchemy\BinaryDriver\ProcessBuilderFactory;
class NONLTSProcessBuilderFactoryTest extends AbstractProcessBuilderFactoryTest
{
protected function getProcessBuilderFactory($binary)
{
ProcessBuilderFactory::$emulateSfLTS = true;
return new ProcessBuilderFactory($binary);
}
}
@@ -0,0 +1,208 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Tests\BinaryDriver;
use Alchemy\BinaryDriver\ProcessRunner;
use Alchemy\BinaryDriver\BinaryDriverTestCase;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Evenement\EventEmitter;
use Symfony\Component\Process\Exception\RuntimeException as ProcessRuntimeException;
class ProcessRunnerTest extends BinaryDriverTestCase
{
public function getProcessRunner($logger)
{
return new ProcessRunner($logger, 'test-runner');
}
public function testRunSuccessFullProcess()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$process = $this->createProcessMock(1, true, '--helloworld--', "Kikoo Romain", null, true);
$logger
->expects($this->never())
->method('error');
$logger
->expects($this->exactly(2))
->method('info');
$this->assertEquals('Kikoo Romain', $runner->run($process, new \SplObjectStorage(), false));
}
public function testRunSuccessFullProcessBypassingErrors()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$process = $this->createProcessMock(1, true, '--helloworld--', "Kikoo Romain", null, true);
$logger
->expects($this->never())
->method('error');
$logger
->expects($this->exactly(2))
->method('info');
$this->assertEquals('Kikoo Romain', $runner->run($process, new \SplObjectStorage(), true));
}
public function testRunFailingProcess()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$process = $this->createProcessMock(1, false, '--helloworld--', null, null, true);
$logger
->expects($this->once())
->method('error');
$logger
->expects($this->once())
->method('info');
try {
$runner->run($process, new \SplObjectStorage(), false);
$this->fail('An exception should have been raised');
} catch (ExecutionFailureException $e) {
}
}
public function testRunFailingProcessWithException()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$exception = new ProcessRuntimeException('Process Failed');
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$process->expects($this->once())
->method('run')
->will($this->throwException($exception));
$logger
->expects($this->once())
->method('error');
$logger
->expects($this->once())
->method('info');
try {
$runner->run($process, new \SplObjectStorage(), false);
$this->fail('An exception should have been raised');
} catch (ExecutionFailureException $e) {
$this->assertEquals($exception, $e->getPrevious());
}
}
public function testRunfailingProcessBypassingErrors()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$process = $this->createProcessMock(1, false, '--helloworld--', 'Hello output', null, true);
$logger
->expects($this->once())
->method('error');
$logger
->expects($this->once())
->method('info');
$this->assertNull($runner->run($process, new \SplObjectStorage(), true));
}
public function testRunFailingProcessWithExceptionBypassingErrors()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$exception = new ProcessRuntimeException('Process Failed');
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$process->expects($this->once())
->method('run')
->will($this->throwException($exception));
$logger
->expects($this->once())
->method('error');
$logger
->expects($this->once())
->method('info');
$this->assertNull($runner->run($process, new \SplObjectStorage(), true));
}
public function testRunSuccessFullProcessWithHandlers()
{
$logger = $this->createLoggerMock();
$runner = $this->getProcessRunner($logger);
$capturedCallback = null;
$process = $this->createProcessMock(1, true, '--helloworld--', "Kikoo Romain", null, true);
$process->expects($this->once())
->method('run')
->with($this->isInstanceOf('Closure'))
->will($this->returnCallback(function ($callback) use (&$capturedCallback) {
$capturedCallback = $callback;
}));
$logger
->expects($this->never())
->method('error');
$logger
->expects($this->exactly(2))
->method('info');
$listener = new TestListener();
$storage = new \SplObjectStorage();
$storage->attach($listener);
$capturedType = $capturedData = null;
$listener->on('received', function ($type, $data) use (&$capturedType, &$capturedData) {
$capturedData = $data;
$capturedType = $type;
});
$this->assertEquals('Kikoo Romain', $runner->run($process, $storage, false));
$type = 'err';
$data = 'data';
$capturedCallback($type, $data);
$this->assertEquals($data, $capturedData);
$this->assertEquals($type, $capturedType);
}
}
class TestListener extends EventEmitter implements ListenerInterface
{
public function handle($type, $data)
{
return $this->emit('received', array($type, $data));
}
public function forwardedEvents()
{
return array();
}
}
+4
View File
@@ -0,0 +1,4 @@
<?php
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->add('Alchemy\Tests', __DIR__);
+7 -3
View File
@@ -374,9 +374,13 @@ class ClassLoader
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
foreach ($this->prefixDirsPsr4[$search] as $dir) {
$length = $this->prefixLengthsPsr4[$first][$search];
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+5
View File
@@ -8,7 +8,11 @@ $baseDir = dirname($vendorDir);
return array(
'Twig_' => array($vendorDir . '/twig/twig/lib'),
'SensioLabs\\Security' => array($vendorDir . '/sensiolabs/security-checker'),
'RequestLab\\VimeoBundle' => array($vendorDir . '/requestlab/vimeo-bundle'),
'Neutron' => array($vendorDir . '/neutron/temporary-filesystem/src'),
'Mongo' => array($vendorDir . '/alcaeus/mongo-php-adapter/lib/Mongo'),
'FFMpeg' => array($vendorDir . '/php-ffmpeg/php-ffmpeg/src'),
'Evenement' => array($vendorDir . '/evenement/evenement/src'),
'Doctrine\\ODM\\MongoDB' => array($vendorDir . '/doctrine/mongodb-odm/lib'),
'Doctrine\\MongoDB' => array($vendorDir . '/doctrine/mongodb/lib'),
'Doctrine\\DBAL\\' => array($vendorDir . '/doctrine/dbal/lib'),
@@ -17,4 +21,5 @@ return array(
'Doctrine\\Common\\Collections\\' => array($vendorDir . '/doctrine/collections/lib'),
'Alom' => array($vendorDir . '/alom/graphviz/src'),
'Alex\\DoctrineExtraBundle' => array($vendorDir . '/alexandresalome/doctrine-extra-bundle'),
'Alchemy' => array($vendorDir . '/alchemy/binary-driver/src'),
);
+2
View File
@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Vimeo\\' => array($vendorDir . '/vimeo/vimeo-api/src/Vimeo'),
'Tests\\' => array($baseDir . '/tests'),
'Symfony\\Polyfill\\Util\\' => array($vendorDir . '/symfony/polyfill-util'),
'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'),
@@ -31,6 +32,7 @@ return array(
'Incenteev\\ParameterHandler\\' => array($vendorDir . '/incenteev/composer-parameter-handler'),
'FOS\\UserBundle\\' => array($vendorDir . '/friendsofsymfony/user-bundle'),
'Dunglas\\DoctrineJsonOdm\\' => array($vendorDir . '/dunglas/doctrine-json-odm/src'),
'Dubture\\FFmpegBundle\\' => array($vendorDir . '/pulse00/ffmpeg-bundle'),
'Doctrine\\ORM\\' => array($vendorDir . '/doctrine/orm/lib/Doctrine/ORM'),
'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib/Doctrine/Common/Cache'),
+45
View File
@@ -20,6 +20,10 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
);
public static $prefixLengthsPsr4 = array (
'V' =>
array (
'Vimeo\\' => 6,
),
'T' =>
array (
'Tests\\' => 6,
@@ -65,6 +69,7 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
'D' =>
array (
'Dunglas\\DoctrineJsonOdm\\' => 24,
'Dubture\\FFmpegBundle\\' => 21,
'Doctrine\\ORM\\' => 13,
'Doctrine\\Instantiator\\' => 22,
'Doctrine\\Common\\Cache\\' => 22,
@@ -81,6 +86,10 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
);
public static $prefixDirsPsr4 = array (
'Vimeo\\' =>
array (
0 => __DIR__ . '/..' . '/vimeo/vimeo-api/src/Vimeo',
),
'Tests\\' =>
array (
0 => __DIR__ . '/../..' . '/tests',
@@ -181,6 +190,10 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
array (
0 => __DIR__ . '/..' . '/dunglas/doctrine-json-odm/src',
),
'Dubture\\FFmpegBundle\\' =>
array (
0 => __DIR__ . '/..' . '/pulse00/ffmpeg-bundle',
),
'Doctrine\\ORM\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/orm/lib/Doctrine/ORM',
@@ -238,6 +251,20 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
0 => __DIR__ . '/..' . '/sensiolabs/security-checker',
),
),
'R' =>
array (
'RequestLab\\VimeoBundle' =>
array (
0 => __DIR__ . '/..' . '/requestlab/vimeo-bundle',
),
),
'N' =>
array (
'Neutron' =>
array (
0 => __DIR__ . '/..' . '/neutron/temporary-filesystem/src',
),
),
'M' =>
array (
'Mongo' =>
@@ -245,6 +272,20 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
0 => __DIR__ . '/..' . '/alcaeus/mongo-php-adapter/lib/Mongo',
),
),
'F' =>
array (
'FFMpeg' =>
array (
0 => __DIR__ . '/..' . '/php-ffmpeg/php-ffmpeg/src',
),
),
'E' =>
array (
'Evenement' =>
array (
0 => __DIR__ . '/..' . '/evenement/evenement/src',
),
),
'D' =>
array (
'Doctrine\\ODM\\MongoDB' =>
@@ -282,6 +323,10 @@ class ComposerStaticInit1b32d02bd8fea2d524bf79b36ada5830
array (
0 => __DIR__ . '/..' . '/alexandresalome/doctrine-extra-bundle',
),
'Alchemy' =>
array (
0 => __DIR__ . '/..' . '/alchemy/binary-driver/src',
),
),
);
+400 -4
View File
@@ -1737,12 +1737,12 @@
"source": {
"type": "git",
"url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git",
"reference": "88b87249206fd867d5de8cee82e60885c0c8f749"
"reference": "4a6415b1254db6e8ea0886ead5c35888c02ccaf9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/88b87249206fd867d5de8cee82e60885c0c8f749",
"reference": "88b87249206fd867d5de8cee82e60885c0c8f749",
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/4a6415b1254db6e8ea0886ead5c35888c02ccaf9",
"reference": "4a6415b1254db6e8ea0886ead5c35888c02ccaf9",
"shasum": ""
},
"require": {
@@ -1769,7 +1769,7 @@
"symfony/validator": "^2.7 || ^3.0",
"symfony/yaml": "^2.7 || ^3.0"
},
"time": "2017-03-19T13:49:51+00:00",
"time": "2017-03-09T15:14:58+00:00",
"type": "symfony-bundle",
"extra": {
"branch-alias": {
@@ -2307,6 +2307,107 @@
"controllers"
]
},
{
"name": "neutron/temporary-filesystem",
"version": "2.2.0",
"version_normalized": "2.2.0.0",
"source": {
"type": "git",
"url": "https://github.com/romainneutron/Temporary-Filesystem.git",
"reference": "0a72a1c858b95fd469d87baa333f627978504ea8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/romainneutron/Temporary-Filesystem/zipball/0a72a1c858b95fd469d87baa333f627978504ea8",
"reference": "0a72a1c858b95fd469d87baa333f627978504ea8",
"shasum": ""
},
"require": {
"php": "^5.3.9 || ^7.0",
"symfony/filesystem": "^2.3 || ^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"time": "2016-03-05T10:22:50+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Neutron": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com"
}
],
"description": "Symfony filesystem extension to handle temporary files"
},
{
"name": "alchemy/binary-driver",
"version": "1.6.0",
"version_normalized": "1.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/BinaryDriver.git",
"reference": "80c6633890afb71d2417ae851d0ad167d8b00b95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/80c6633890afb71d2417ae851d0ad167d8b00b95",
"reference": "80c6633890afb71d2417ae851d0ad167d8b00b95",
"shasum": ""
},
"require": {
"evenement/evenement": "^2.0|^1.0",
"monolog/monolog": "^1.3",
"php": ">=5.5",
"psr/log": "^1.0",
"symfony/process": "^2.0|^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0"
},
"time": "2016-03-02T13:49:15+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Alchemy": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
},
{
"name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com"
}
],
"description": "A set of tools to build binary drivers",
"keywords": [
"binary",
"driver"
]
},
{
"name": "paragonie/random_compat",
"version": "v2.0.10",
@@ -2748,5 +2849,300 @@
}
],
"description": "A security checker for your composer.lock"
},
{
"name": "evenement/evenement",
"version": "v1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/igorw/evenement.git",
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2012-05-30T15:01:08+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Evenement": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch",
"homepage": "http://wiedler.ch/igor/"
}
],
"description": "Événement is a very simple event dispatching library for PHP 5.3",
"keywords": [
"event-dispatcher"
]
},
{
"name": "php-ffmpeg/php-ffmpeg",
"version": "0.5.1",
"version_normalized": "0.5.1.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-FFMpeg/PHP-FFMpeg.git",
"reference": "c8949fe3df89edd7692368cc110a51a27971f28a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-FFMpeg/PHP-FFMpeg/zipball/c8949fe3df89edd7692368cc110a51a27971f28a",
"reference": "c8949fe3df89edd7692368cc110a51a27971f28a",
"shasum": ""
},
"require": {
"alchemy/binary-driver": "~1.5",
"doctrine/cache": "~1.0",
"evenement/evenement": "~1.0",
"neutron/temporary-filesystem": "~2.1, >=2.1.1",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~3.7",
"sami/sami": "~1.0",
"silex/silex": "~1.0"
},
"suggest": {
"php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg"
},
"time": "2014-08-26T08:46:56+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.5-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"FFMpeg": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
}
],
"description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"video",
"video processing"
]
},
{
"name": "vimeo/vimeo-api",
"version": "1.2.6",
"version_normalized": "1.2.6.0",
"source": {
"type": "git",
"url": "https://github.com/vimeo/vimeo.php.git",
"reference": "34a2b06801db3318ebb983821945293773691915"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vimeo/vimeo.php/zipball/34a2b06801db3318ebb983821945293773691915",
"reference": "34a2b06801db3318ebb983821945293773691915",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2016-12-02T16:03:55+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Vimeo\\": "src/Vimeo"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Vimeo",
"homepage": "http://vimeo.com"
}
],
"description": "Official PHP library for the Vimeo API.",
"homepage": "https://github.com/vimeo/vimeo.php",
"keywords": [
"video",
"vimeo"
]
},
{
"name": "requestlab/vimeo-bundle",
"version": "0.0.3",
"version_normalized": "0.0.3.0",
"target-dir": "RequestLab/VimeoBundle",
"source": {
"type": "git",
"url": "https://github.com/RequestLab/VimeoBundle.git",
"reference": "ee20bfe8968fb0cfcbbb7584d2be07203001ff05"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/RequestLab/VimeoBundle/zipball/ee20bfe8968fb0cfcbbb7584d2be07203001ff05",
"reference": "ee20bfe8968fb0cfcbbb7584d2be07203001ff05",
"shasum": ""
},
"require": {
"symfony/framework-bundle": "3.*",
"vimeo/vimeo-api": "1.*"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"time": "2016-11-28T08:54:50+00:00",
"type": "symfony-bundle",
"installation-source": "dist",
"autoload": {
"psr-0": {
"RequestLab\\VimeoBundle": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Yann Lecommandoux",
"email": "yann@requestlab.fr"
}
],
"keywords": [
"api",
"server",
"symfony",
"vimeo"
]
},
{
"name": "pulse00/ffmpeg-bundle",
"version": "0.6.0",
"version_normalized": "0.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/pulse00/ffmpeg-bundle.git",
"reference": "43014797e87e5d79322e59973e9925a88d64f9e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pulse00/ffmpeg-bundle/zipball/43014797e87e5d79322e59973e9925a88d64f9e9",
"reference": "43014797e87e5d79322e59973e9925a88d64f9e9",
"shasum": ""
},
"require": {
"php": "^5.3.9 || ^7.0",
"php-ffmpeg/php-ffmpeg": "^0.5 || ^0.6",
"symfony/dependency-injection": "^2.3 || ^3.0",
"symfony/framework-bundle": "^2.3 || ^3.0"
},
"require-dev": {
"matthiasnoback/symfony-dependency-injection-test": "~0.7",
"phpunit/phpunit": "^4.8"
},
"time": "2016-03-07T09:47:04+00:00",
"type": "symfony-bundle",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Dubture\\FFmpegBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Robert Gruendler",
"email": "r.gruendler@gmail.com"
}
],
"description": "Symfony bundle to provide PHP-FFmpeg as a Symfony service (https://github.com/alchemy-fr/PHP-FFmpeg)",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"multimedia",
"video",
"video processing"
]
},
{
"name": "phpexiftool/exiftool",
"version": "10.16",
"version_normalized": "10.16.0.0",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/exiftool.git",
"reference": "c47639a6e9d8fd9746c8c24725e3c3e1e7eb0cbb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/exiftool/zipball/c47639a6e9d8fd9746c8c24725e3c3e1e7eb0cbb",
"reference": "c47639a6e9d8fd9746c8c24725e3c3e1e7eb0cbb",
"shasum": ""
},
"time": "2016-05-09T09:08:26+00:00",
"type": "library",
"installation-source": "dist",
"notification-url": "https://packagist.org/downloads/",
"license": [
"Perl Licensing"
],
"authors": [
{
"name": "Phil Harvey",
"email": "phil@owl.phy.queensu.ca",
"homepage": "http://www.sno.phy.queensu.ca/~phil/exiftool/"
}
],
"description": "Exiftool is a library for reading, writing and editing meta information. This package is not PHP, but required for the main PHP driver : PHP Exiftool",
"keywords": [
"exiftool",
"metadata"
]
}
]
@@ -0,0 +1,2 @@
composer.lock
vendor
+11
View File
@@ -0,0 +1,11 @@
language: php
php:
- 5.3
- 5.4
before_script:
- wget http://getcomposer.org/composer.phar
- php composer.phar install
script: phpunit --coverage-text
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2011 Igor Wiedler
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+74
View File
@@ -0,0 +1,74 @@
# Événement
Événement is a very simple event dispatching library for PHP 5.3.
It has the same design goals as [Silex](http://silex-project.org) and
[Pimple](http://pimple-project.org), to empower the user while staying concise
and simple.
It is very strongly inspired by the EventEmitter API found in
[node.js](http://nodejs.org). It includes an implementation of
[EventEmitter2](https://github.com/hij1nx/EventEmitter2), that extends
the original EventEmitter.
[![Build Status](https://secure.travis-ci.org/igorw/evenement.png)](http://travis-ci.org/igorw/evenement)
## Fetch
The recommended way to install Événement is [through composer](http://getcomposer.org).
Just create a composer.json file for your project:
```JSON
{
"require": {
"evenement/evenement": "dev-master"
}
}
```
And run these two commands to install it:
$ curl -s http://getcomposer.org/installer | php
$ php composer.phar install
Now you can add the autoloader, and you will have access to the library:
```php
<?php
require 'vendor/autoload.php';
```
## Usage
### Creating an Emitter
```php
<?php
$emitter = new Evenement\EventEmitter();
```
### Adding Listeners
```php
<?php
$emitter->on('user.create', function (User $user) use ($logger) {
$logger->log(sprintf("User '%s' was created.", $user->getLogin()));
});
```
### Emitting Events
```php
<?php
$emitter->emit('user.create', array($user));
```
Tests
-----
$ phpunit
License
-------
MIT, see LICENSE.
+20
View File
@@ -0,0 +1,20 @@
{
"name": "evenement/evenement",
"description": "Événement is a very simple event dispatching library for PHP 5.3",
"keywords": ["event-dispatcher"],
"license": "MIT",
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-0": {
"Evenement": "src"
}
}
}
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="Evenement Test Suite">
<directory>./tests/Evenement/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
</filter>
</phpunit>
@@ -0,0 +1,73 @@
<?php
/*
* This file is part of Evenement.
*
* (c) Igor Wiedler <igor@wiedler.ch>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Evenement;
class EventEmitter implements EventEmitterInterface
{
protected $listeners = array();
public function on($event, $listener)
{
if (!is_callable($listener)) {
throw new \InvalidArgumentException('The provided listener was not a valid callable.');
}
if (!isset($this->listeners[$event])) {
$this->listeners[$event] = array();
}
$this->listeners[$event][] = $listener;
}
public function once($event, $listener)
{
$that = $this;
$onceListener = function () use ($that, &$onceListener, $event, $listener) {
$that->removeListener($event, $onceListener);
call_user_func_array($listener, func_get_args());
};
$this->on($event, $onceListener);
}
public function removeListener($event, $listener)
{
if (isset($this->listeners[$event])) {
if (false !== $index = array_search($listener, $this->listeners[$event], true)) {
unset($this->listeners[$event][$index]);
}
}
}
public function removeAllListeners($event = null)
{
if ($event !== null) {
unset($this->listeners[$event]);
} else {
$this->listeners = array();
}
}
public function listeners($event)
{
return isset($this->listeners[$event]) ? $this->listeners[$event] : array();
}
public function emit($event, array $arguments = array())
{
foreach ($this->listeners($event) as $listener) {
call_user_func_array($listener, $arguments);
}
}
}
@@ -0,0 +1,114 @@
<?php
/*
* This file is part of Evenement.
*
* (c) Igor Wiedler <igor@wiedler.ch>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Evenement;
class EventEmitter2 extends EventEmitter
{
protected $options;
protected $anyListeners = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'delimiter' => '.',
), $options);
}
public function onAny($listener)
{
$this->anyListeners[] = $listener;
}
public function offAny($listener)
{
if (false !== $index = array_search($listener, $this->anyListeners, true)) {
unset($this->anyListeners[$index]);
}
}
public function many($event, $timesToListen, $listener)
{
$that = $this;
$timesListened = 0;
if ($timesToListen == 0) {
return;
}
if ($timesToListen < 0) {
throw new \OutOfRangeException('You cannot listen less than zero times.');
}
$manyListener = function () use ($that, &$timesListened, &$manyListener, $event, $timesToListen, $listener) {
if (++$timesListened == $timesToListen) {
$that->removeListener($event, $manyListener);
}
call_user_func_array($listener, func_get_args());
};
$this->on($event, $manyListener);
}
public function emit($event, array $arguments = array())
{
foreach ($this->anyListeners as $listener) {
call_user_func_array($listener, $arguments);
}
parent::emit($event, $arguments);
}
public function listeners($event)
{
$matchedListeners = array();
foreach ($this->listeners as $name => $listeners) {
foreach ($listeners as $listener) {
if ($this->matchEventName($event, $name)) {
$matchedListeners[] = $listener;
}
}
}
return $matchedListeners;
}
protected function matchEventName($matchPattern, $eventName)
{
$patternParts = explode($this->options['delimiter'], $matchPattern);
$nameParts = explode($this->options['delimiter'], $eventName);
if (count($patternParts) != count($nameParts)) {
return false;
}
$size = min(count($patternParts), count($nameParts));
for ($i = 0; $i < $size; $i++) {
$patternPart = $patternParts[$i];
$namePart = $nameParts[$i];
if ('*' === $patternPart || '*' === $namePart) {
continue;
}
if ($namePart === $patternPart) {
continue;
}
return false;
}
return true;
}
}
@@ -0,0 +1,22 @@
<?php
/*
* This file is part of Evenement.
*
* (c) Igor Wiedler <igor@wiedler.ch>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Evenement;
interface EventEmitterInterface
{
public function on($event, $listener);
public function once($event, $listener);
public function removeListener($event, $listener);
public function removeAllListeners($event = null);
public function listeners($event);
public function emit($event, array $arguments = array());
}
@@ -0,0 +1,160 @@
<?php
/*
* This file is part of Evenement.
*
* Copyright (c) 2011 Igor Wiedler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Evenement\Tests;
use Evenement\EventEmitter2;
class EventEmitter2Test extends \PHPUnit_Framework_TestCase
{
private $emitter;
public function setUp()
{
$this->emitter = new EventEmitter2();
}
// matching tests from
// test/wildcardEvents/addListener.js
public function testWildcardMatching7()
{
$listenerCalled = 0;
$listener = function () use (&$listenerCalled) {
$listenerCalled++;
};
$this->emitter->on('*.test', $listener);
$this->emitter->on('*.*', $listener);
$this->emitter->on('*', $listener);
$this->emitter->emit('other.emit');
$this->emitter->emit('foo.test');
$this->assertSame(3, $listenerCalled);
}
public function testWildcardMatching8()
{
$listenerCalled = 0;
$listener = function () use (&$listenerCalled) {
$listenerCalled++;
};
$this->emitter->on('foo.test', $listener);
$this->emitter->on('*.*', $listener);
$this->emitter->on('*', $listener);
$this->emitter->emit('*.*');
$this->emitter->emit('foo.test');
$this->emitter->emit('*');
$this->assertSame(5, $listenerCalled);
}
public function testOnAny()
{
$this->emitter->onAny(function () {});
}
public function testOnAnyWithEmit()
{
$listenerCalled = 0;
$this->emitter->onAny(function () use (&$listenerCalled) {
$listenerCalled++;
});
$this->assertSame(0, $listenerCalled);
$this->emitter->emit('foo');
$this->assertSame(1, $listenerCalled);
$this->emitter->emit('bar');
$this->assertSame(2, $listenerCalled);
}
public function testoffAnyWithEmit()
{
$listenerCalled = 0;
$listener = function () use (&$listenerCalled) {
$listenerCalled++;
};
$this->emitter->onAny($listener);
$this->emitter->offAny($listener);
$this->assertSame(0, $listenerCalled);
$this->emitter->emit('foo');
$this->assertSame(0, $listenerCalled);
}
/**
* @dataProvider provideMany
*/
public function testMany($amount)
{
$listenerCalled = 0;
$this->emitter->many('foo', $amount, function () use (&$listenerCalled) {
$listenerCalled++;
});
for ($i = 0; $i < $amount; $i++) {
$this->assertSame($i, $listenerCalled);
$this->emitter->emit('foo');
}
$this->emitter->emit('foo');
$this->assertSame($amount, $listenerCalled);
}
public function provideMany()
{
return array(
array(0),
array(1),
array(2),
array(3),
array(4),
array(400),
);
}
/**
* @expectedException OutOfRangeException
*/
public function testManyWithLessThanZeroTtl()
{
$this->emitter->many('foo', -1, function () {});
$this->emitter->emit('foo');
}
}
@@ -0,0 +1,236 @@
<?php
/*
* This file is part of Evenement.
*
* Copyright (c) 2011 Igor Wiedler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Evenement\Tests;
use Evenement\EventEmitter;
class EventEmitterTest extends \PHPUnit_Framework_TestCase
{
private $emitter;
public function setUp()
{
$this->emitter = new EventEmitter();
}
public function testAddListenerWithLambda()
{
$this->emitter->on('foo', function () {});
}
public function testAddListenerWithMethod()
{
$listener = new Listener();
$this->emitter->on('foo', array($listener, 'onFoo'));
}
public function testAddListenerWithStaticMethod()
{
$this->emitter->on('bar', array('Evenement\Tests\Listener', 'onBar'));
}
/**
* @expectedException InvalidArgumentException
*/
public function testAddListenerWithInvalidListener()
{
$this->emitter->on('foo', 'not a callable');
}
public function testOnce()
{
$listenerCalled = 0;
$this->emitter->once('foo', function () use (&$listenerCalled) {
$listenerCalled++;
});
$this->assertSame(0, $listenerCalled);
$this->emitter->emit('foo');
$this->assertSame(1, $listenerCalled);
$this->emitter->emit('foo');
$this->assertSame(1, $listenerCalled);
}
public function testEmitWithoutArguments()
{
$listenerCalled = false;
$this->emitter->on('foo', function () use (&$listenerCalled) {
$listenerCalled = true;
});
$this->assertSame(false, $listenerCalled);
$this->emitter->emit('foo');
$this->assertSame(true, $listenerCalled);
}
public function testEmitWithOneArgument()
{
$test = $this;
$listenerCalled = false;
$this->emitter->on('foo', function ($value) use (&$listenerCalled, $test) {
$listenerCalled = true;
$test->assertSame('bar', $value);
});
$this->assertSame(false, $listenerCalled);
$this->emitter->emit('foo', array('bar'));
$this->assertSame(true, $listenerCalled);
}
public function testEmitWithTwoArguments()
{
$test = $this;
$listenerCalled = false;
$this->emitter->on('foo', function ($arg1, $arg2) use (&$listenerCalled, $test) {
$listenerCalled = true;
$test->assertSame('bar', $arg1);
$test->assertSame('baz', $arg2);
});
$this->assertSame(false, $listenerCalled);
$this->emitter->emit('foo', array('bar', 'baz'));
$this->assertSame(true, $listenerCalled);
}
public function testEmitWithNoListeners()
{
$this->emitter->emit('foo');
$this->emitter->emit('foo', array('bar'));
$this->emitter->emit('foo', array('bar', 'baz'));
}
public function testEmitWithTwoListeners()
{
$listenersCalled = 0;
$this->emitter->on('foo', function () use (&$listenersCalled) {
$listenersCalled++;
});
$this->emitter->on('foo', function () use (&$listenersCalled) {
$listenersCalled++;
});
$this->assertSame(0, $listenersCalled);
$this->emitter->emit('foo');
$this->assertSame(2, $listenersCalled);
}
public function testRemoveListenerMatching()
{
$listenersCalled = 0;
$listener = function () use (&$listenersCalled) {
$listenersCalled++;
};
$this->emitter->on('foo', $listener);
$this->emitter->removeListener('foo', $listener);
$this->assertSame(0, $listenersCalled);
$this->emitter->emit('foo');
$this->assertSame(0, $listenersCalled);
}
public function testRemoveListenerNotMatching()
{
$listenersCalled = 0;
$listener = function () use (&$listenersCalled) {
$listenersCalled++;
};
$this->emitter->on('foo', $listener);
$this->emitter->removeListener('bar', $listener);
$this->assertSame(0, $listenersCalled);
$this->emitter->emit('foo');
$this->assertSame(1, $listenersCalled);
}
public function testRemoveAllListenersMatching()
{
$listenersCalled = 0;
$this->emitter->on('foo', function () use (&$listenersCalled) {
$listenersCalled++;
});
$this->emitter->removeAllListeners('foo');
$this->assertSame(0, $listenersCalled);
$this->emitter->emit('foo');
$this->assertSame(0, $listenersCalled);
}
public function testRemoveAllListenersNotMatching()
{
$listenersCalled = 0;
$this->emitter->on('foo', function () use (&$listenersCalled) {
$listenersCalled++;
});
$this->emitter->removeAllListeners('bar');
$this->assertSame(0, $listenersCalled);
$this->emitter->emit('foo');
$this->assertSame(1, $listenersCalled);
}
public function testRemoveAllListenersWithoutArguments()
{
$listenersCalled = 0;
$this->emitter->on('foo', function () use (&$listenersCalled) {
$listenersCalled++;
});
$this->emitter->on('bar', function () use (&$listenersCalled) {
$listenersCalled++;
});
$this->emitter->removeAllListeners();
$this->assertSame(0, $listenersCalled);
$this->emitter->emit('foo');
$this->emitter->emit('bar');
$this->assertSame(0, $listenersCalled);
}
}
@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Evenement.
*
* Copyright (c) 2011 Igor Wiedler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Evenement\Tests;
class Listener
{
public function onFoo()
{
}
public static function onBar()
{
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* This file is part of Evenement.
*
* Copyright (c) 2011 Igor Wiedler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->add('Evenement\Tests', __DIR__);
@@ -0,0 +1,3 @@
vendor
composer.phar
composer.lock
+43
View File
@@ -0,0 +1,43 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
sudo: false
cache:
directories:
- $HOME/.composer
env:
- SYMFONY_VERSION=2.8.*
matrix:
include:
- php: 5.6
env: SYMFONY_VERSION=2.3.*
- php: 5.6
env: SYMFONY_VERSION=2.7.*
- php: 7.0
env: SYMFONY_VERSION=2.8.*@dev
- php: 7.0
env: SYMFONY_VERSION=3.0.*
- php: 7.0
env: SYMFONY_VERSION=3.0.*@dev
- php: 5.3
env: COMPOSER_FLAGS="--prefer-lowest"
before_install:
- composer self-update
- if [ "COMPOSER_FLAGS" == "--prefer-lowest" ]; then composer require "roave/security-advisories" dev-master --no-update; fi;
- if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi;
install: composer update --prefer-source $COMPOSER_FLAGS
script:
- vendor/bin/phpunit
+27
View File
@@ -0,0 +1,27 @@
CHANGELOG
=========
* 2.1.1 (2013-10-10)
* Add a factory for the Manager
* 2.1.0 (2013-08-06)
* Use custom IOException instead of Symfony one.
* Add a TemporaryFilesystemInterface.
* Add optional directory prefix to createTemporaryDirectory.
* Add temporary files manager.
* 2.0.1 (2013-04-09)
* Add TemporaryFilesystem::createTemporaryFile method
* 2.0.0 (2013-04-08)
* Switch from inheritance to composition design
* Add TemporaryFilesystem::create method
* Add TemporaryFilesystem::createTemporaryDirectory method
* 1.0.0 (2012-11-02)
* First tagged release
+21
View File
@@ -0,0 +1,21 @@
TemporaryFilesystem is released with MIT License :
Copyright (c) 2012 Alchemy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
+72
View File
@@ -0,0 +1,72 @@
# TemporaryFilesystem
TemporaryFilesystem propose an API for temprary filesystem based on [Symfony
Filesystem Component](https://github.com/symfony/filesystem).
[![Build Status](https://travis-ci.org/romainneutron/Temporary-Filesystem.png?branch=master)](https://travis-ci.org/romainneutron/Temporary-Filesystem)
## Usage
```php
use Neutron\TemporaryFilesystem\TemporaryFilesystem;
$fs = TemporaryFilesystem::create();
```
## API Examples :
### CreateTemporaryDirectory
CreateTemporaryDirectory creates a temporary directory with an optional mode :
```php
$tempDir = $fs->createTemporaryDirectory($mode = 0755);
```
### CreateTemporaryFile
CreateTemporaryFile creates an empty files in the temporary folder:
```php
$fs->createTemporaryFile();
// return an empty temporary files with a "thumb-"
// prefix, '.dcm' as suffix and 'jpg' as extension
$fs->createTemporaryFile('thumb-', '.dcm', 'jpg');
```
### CreateTemporaryFiles
CreateTemporaryFiles creates a set of empty files in the temporary folder:
```php
// return an array of 5 path to temporary files
$fs->createTemporaryFiles(5);
// return an array of 5 path to empty temporary files with a "thumb-"
// prefix, '.dcm' as suffix and 'jpg' as extension
$fs->createTemporaryFiles(20, 'thumb-', '.dcm', 'jpg');
```
This method is useful when dealing with libraries which encode images
depending on the filename extension.
### CreateEmptyFile
CreateEmptyFile creates an empty file in the specified folder:
```php
// return a path to an empty file inside the current working directory
$fs->createEmptyFile(getcwd());
// return a path to an empty file in the "/home/romain" directory. The file
// has "original." as prefix, ".raw" as suffix and "CR2" as extension.
$fs->createEmptyFile("/home/romain", 'original.', '.raw', 'CR2');
```
This method is particularly useful when dealing with concurrent process
writing in the same directory.
# License
Released under the MIT license
+23
View File
@@ -0,0 +1,23 @@
{
"name": "neutron/temporary-filesystem",
"description": "Symfony filesystem extension to handle temporary files",
"license": "MIT",
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com"
}
],
"require": {
"php": "^5.3.9 || ^7.0",
"symfony/filesystem": "^2.3 || ^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"autoload": {
"psr-0": {
"Neutron": "src"
}
}
}
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true"
verbose="false"
bootstrap="tests/bootstrap.php"
>
<logging>
<log type="coverage-html" target="tests/phpunit_report/report" charset="UTF-8"
yui="true" highlight="false"
lowUpperBound="35" highLowerBound="70"/>
</logging>
<php>
<ini name="display_errors" value="on"/>
</php>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<testsuites>
<testsuite name="TemporaryFilesystem tests Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory>vendor</directory>
<directory>tests</directory>
</blacklist>
</filter>
</phpunit>
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of TemporaryFilesystem.
*
* (c) Romain Neutron <imprec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Neutron\TemporaryFilesystem;
class IOException extends \RuntimeException
{
}
@@ -0,0 +1,156 @@
<?php
/*
* This file is part of TemporaryFilesystem.
*
* (c) Romain Neutron <imprec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Neutron\TemporaryFilesystem;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOException as SfIOException;
class Manager implements TemporaryFilesystemInterface
{
/** @var Filesystem */
private $fs;
/** @var TemporaryFilesystem */
private $tmpFs;
/** @var array */
private $files = array();
const DEFAULT_SCOPE = '_tmp_fs_';
public function __construct(TemporaryFilesystemInterface $tmpFs, Filesystem $fs)
{
$this->fs = $fs;
$this->tmpFs = $tmpFs;
register_shutdown_function(array($this, 'clean'), null, false);
}
/**
* {@inheritdoc}
*/
public function createEmptyFile($basePath, $prefix = self::DEFAULT_SCOPE, $suffix = null, $extension = null, $maxTry = 65536)
{
$file = $this->tmpFs->createEmptyFile($basePath, $prefix, $suffix, $extension, $maxTry);
$this->add($file, $prefix);
return $file;
}
/**
* {@inheritdoc}
*/
public function createTemporaryDirectory($mode = 0777, $maxTry = 65536, $prefix = self::DEFAULT_SCOPE)
{
$dir = $this->tmpFs->createTemporaryDirectory($mode, $maxTry, $prefix);
$this->add($dir, $prefix);
return $dir;
}
/**
* {@inheritdoc}
*/
public function createTemporaryFile($prefix = self::DEFAULT_SCOPE, $suffix = null, $extension = null, $maxTry = 65536)
{
$file = $this->tmpFs->createTemporaryFile($prefix, $suffix, $extension, $maxTry);
$this->add($file, $prefix);
return $file;
}
/**
* {@inheritdoc}
*/
public function createTemporaryFiles($quantity = 1, $prefix = self::DEFAULT_SCOPE, $suffix = null, $extension = null, $maxTry = 65536)
{
$files = $this->tmpFs->createTemporaryFiles($quantity, $prefix, $suffix, $extension, $maxTry);
$this->add($files, $prefix);
return $files;
}
/**
* Adds file to be handled by the manager.
*
* @param string|array $files
* @param string $scope
*
* @return Manager
*/
public function add($files, $scope = self::DEFAULT_SCOPE)
{
if (!is_array($files)) {
$files = array($files);
}
if ('' === trim($scope)) {
$scope = self::DEFAULT_SCOPE;
}
if (!isset($this->files[$scope])) {
$this->files[$scope] = array();
}
$this->files[$scope] = array_merge($this->files[$scope], $files);
return $this;
}
/**
* Removes all managed files in a scope. If no scope provided, all scopes
* are cleared.
*
* @param string $scope
*
* @return Manager
*
* @throws IOException
*/
public function clean($scope = null, $throwException = true)
{
if (null !== $scope) {
$this->cleanScope($scope, $throwException);
} else {
foreach ($this->files as $scope => $files) {
$this->cleanScope($scope, $throwException);
}
}
return $this;
}
/**
* Factory for the Manager
*
* @return Manager
*/
public static function create()
{
$fs = new Filesystem();
return new static(new TemporaryFilesystem($fs), $fs);
}
private function cleanScope($scope, $throwException)
{
if (!isset($this->files[$scope])) {
return;
}
try {
$this->fs->remove($this->files[$scope]);
unset($this->files[$scope]);
} catch (SfIOException $e) {
unset($this->files[$scope]);
if ($throwException) {
throw new IOException('Unable to remove all the files', $e->getCode(), $e);
}
}
}
}
@@ -0,0 +1,130 @@
<?php
/*
* This file is part of TemporaryFilesystem.
*
* (c) Romain Neutron <imprec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Neutron\TemporaryFilesystem;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOException as SfIOException;
class TemporaryFilesystem implements TemporaryFilesystemInterface
{
/** @var Filesystem */
private $filesystem;
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}
/**
* {@inheritdoc}
*/
public function createTemporaryDirectory($mode = 0777, $maxTry = 65536, $prefix = null)
{
$basePath = sys_get_temp_dir();
while ($maxTry > 0) {
$dir = $basePath . DIRECTORY_SEPARATOR
. $prefix . base_convert(mt_rand(0x19A100, 0x39AA3FF), 10, 36);
if (false === file_exists($dir)) {
try {
$this->filesystem->mkdir($dir, $mode);
} catch (SfIOException $e) {
throw new IOException('Unable to make directory', $e->getCode(), $e);
}
return $dir;
}
$maxTry --;
}
throw new IOException('Unable to generate a temporary directory');
}
/**
* {@inheritdoc}
*/
public function createTemporaryFiles($quantity = 1, $prefix = null, $suffix = null, $extension = null, $maxTry = 65536)
{
if ($quantity < 1) {
throw new \InvalidArgumentException('Invalid temporary files quantity');
}
$files = array();
while ($quantity > 0) {
$files[] = $this->createEmptyFile(sys_get_temp_dir(), $prefix, $suffix, $extension, $maxTry);
$quantity --;
}
return $files;
}
/**
* {@inheritdoc}
*/
public function createTemporaryFile($prefix = null, $suffix = null, $extension = null, $maxTry = 65536)
{
$files = $this->createTemporaryFiles(1, $prefix, $suffix, $extension, $maxTry);
return array_pop($files);
}
/**
* {@inheritdoc}
*/
public function createEmptyFile($basePath, $prefix = null, $suffix = null, $extension = null, $maxTry = 65536)
{
if (false === is_dir($basePath) || false === is_writeable($basePath)) {
throw new IOException(sprintf('`%s` should be a writeable directory', $basePath));
}
if ($suffix === null && $extension === null) {
if (false === $file = @tempnam($basePath, $prefix)) {
throw new IOException('Unable to generate a temporary filename');
}
return $file;
}
while ($maxTry > 0) {
$file = $basePath . DIRECTORY_SEPARATOR
. $prefix . base_convert(mt_rand(0x19A100, 0x39AA3FF), 10, 36) . $suffix
. ( $extension ? '.' . $extension : '');
if (false === file_exists($file)) {
try {
$this->filesystem->touch($file);
} catch (SfIOException $e) {
throw new IOException('Unable to touch file', $e->getCode(), $e);
}
return $file;
}
$maxTry --;
}
throw new IOException('Unable to generate a temporary filename');
}
/**
* Creates a TemporaryFilesystem
*
* @return TemporaryFilesystem
*/
public static function create()
{
return new static(new Filesystem());
}
}
@@ -0,0 +1,86 @@
<?php
/*
* This file is part of TemporaryFilesystem.
*
* (c) Romain Neutron <imprec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Neutron\TemporaryFilesystem;
use Symfony\Component\Filesystem\Exception\IOException;
interface TemporaryFilesystemInterface
{
/**
* Creates a temporary directory.
*
* @param octal $mode The directory mode
* @param integer $maxTry The maximum number of trials
* @param string $prefix The directory prefix
*
* @return string The name of the created directory
*
* @throws IOException In case the directory could not be created
*/
public function createTemporaryDirectory($mode = 0777, $maxTry = 65536, $prefix = null);
/**
* Creates an array of temporary files.
*
* Temporary files are created inside the system temporary folder. You must
* removed them manually at the end of use.
*
* @param integer $quantity The quantity of temporary files requested
* @param string $prefix The prefix of the files
* @param string $suffix The suffix of the files
* @param string $extension The extension of the files
* @param integer $maxTry The maximum number of trials to create one temporary file
*
* @return array An array of filenames
*
* @throws \InvalidArgumentException In case you provide a wrong argument
* @throws IOException In case of failure
*/
public function createTemporaryFiles($quantity = 1, $prefix = null, $suffix = null, $extension = null, $maxTry = 65536);
/**
* Creates a temporary file.
*
* Temporary files are created inside the system temporary folder. You must
* removed them manually at the end of use.
*
* @param string $prefix The prefix of the files
* @param string $suffix The suffix of the files
* @param string $extension The extension of the files
* @param integer $maxTry The maximum number of trials to create one temporary file
*
* @return array An array of filenames
*
* @throws \InvalidArgumentException In case you provide a wrong argument
* @throws IOException In case of failure
*/
public function createTemporaryFile($prefix = null, $suffix = null, $extension = null, $maxTry = 65536);
/**
* Create an empty file in the specified directory.
*
* The new file is created in the requested directory and will fit the
* the given parameters. Please note that the filename contains some
* random caracters.
*
* @param string $basePath The directory where to create the file
* @param string $prefix The prefix of the file
* @param string $suffix The suffix of the file
* @param string $extension The extension of the file
* @param integer $maxTry The maximum number of trials to create the file
*
* @return string The path of the created file
*
* @throws IOException in case of failure
*/
public function createEmptyFile($basePath, $prefix = null, $suffix = null, $extension = null, $maxTry = 65536);
}
@@ -0,0 +1,301 @@
<?php
namespace Neutron\TemporaryFilesystem\Tests;
use Neutron\TemporaryFilesystem\Manager;
class ManagerTest extends \PHPUnit_Framework_TestCase
{
public function testCreateEmptyFileAndCleanScope()
{
$basePath = 'basePath';
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/empty/file'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createEmptyFile')
->with($basePath, $prefix, $suffix, $extension, $maxTry)
->will($this->returnValue('/path/to/empty/file'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/empty/file', $manager->createEmptyFile($basePath, $prefix, $suffix, $extension, $maxTry));
$manager->clean($prefix);
}
public function testCreateEmptyFileAndCleanOtherScope()
{
$basePath = 'basePath';
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->never())
->method('remove');
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createEmptyFile')
->with($basePath, $prefix, $suffix, $extension, $maxTry)
->will($this->returnValue('/path/to/empty/file'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/empty/file', $manager->createEmptyFile($basePath, $prefix, $suffix, $extension, $maxTry));
$manager->clean('other prefix');
}
public function testCreateEmptyFileAndCleanScopes()
{
$basePath = 'basePath';
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/empty/file'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createEmptyFile')
->with($basePath, $prefix, $suffix, $extension, $maxTry)
->will($this->returnValue('/path/to/empty/file'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/empty/file', $manager->createEmptyFile($basePath, $prefix, $suffix, $extension, $maxTry));
$manager->clean();
}
public function testCreateTemporaryDirectoryAndCleanScope()
{
$mode = 'mode';
$prefix = 'prefix';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/dir'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryDirectory')
->with($mode, $maxTry, $prefix)
->will($this->returnValue('/path/to/dir'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/dir', $manager->createTemporaryDirectory($mode, $maxTry, $prefix));
$manager->clean($prefix);
}
public function testCreateTemporaryDirectoryAndCleanOtherScope()
{
$mode = 'mode';
$prefix = 'prefix';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->never())
->method('remove');
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryDirectory')
->with($mode, $maxTry, $prefix)
->will($this->returnValue('/path/to/dir'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/dir', $manager->createTemporaryDirectory($mode, $maxTry, $prefix));
$manager->clean('other prefix');
}
public function testCreateTemporaryDirectoryAndCleanScopes()
{
$mode = 'mode';
$prefix = 'prefix';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/dir'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryDirectory')
->with($mode, $maxTry, $prefix)
->will($this->returnValue('/path/to/dir'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/dir', $manager->createTemporaryDirectory($mode, $maxTry, $prefix));
$manager->clean();
}
public function testCreateTemporaryFileAndCleanScope()
{
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/file'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryFile')
->with($prefix, $suffix, $extension, $maxTry)
->will($this->returnValue('/path/to/file'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/file', $manager->createTemporaryFile($prefix, $suffix, $extension, $maxTry));
$manager->clean($prefix);
}
public function testCreateTemporaryFileAndCleanOtherScope()
{
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->never())
->method('remove');
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryFile')
->with($prefix, $suffix, $extension, $maxTry)
->will($this->returnValue('/path/to/file'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/file', $manager->createTemporaryFile($prefix, $suffix, $extension, $maxTry));
$manager->clean('other prefix');
}
public function testCreateTemporaryFileAndCleanScopes()
{
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/file'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryFile')
->with($prefix, $suffix, $extension, $maxTry)
->will($this->returnValue('/path/to/file'));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals('/path/to/file', $manager->createTemporaryFile($prefix, $suffix, $extension, $maxTry));
$manager->clean();
}
public function testCreateTemporaryFilesAndCleanScope()
{
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$quantity = 123;
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/file'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryFiles')
->with($quantity, $prefix, $suffix, $extension, $maxTry)
->will($this->returnValue(array('/path/to/file')));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals(array('/path/to/file'), $manager->createTemporaryFiles($quantity, $prefix, $suffix, $extension, $maxTry));
$manager->clean($prefix);
}
public function testCreateTemporaryFilesAndCleanOtherScope()
{
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$quantity = 123;
$fs = $this->createFsMock();
$fs->expects($this->never())
->method('remove');
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryFiles')
->with($quantity, $prefix, $suffix, $extension, $maxTry)
->will($this->returnValue(array('/path/to/file')));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals(array('/path/to/file'), $manager->createTemporaryFiles($quantity, $prefix, $suffix, $extension, $maxTry));
$manager->clean('other prefix');
}
public function testCreateTemporaryFilesAndCleanScopes()
{
$prefix = 'prefix';
$suffix = 'suffix';
$extension = 'extension';
$maxTry = 'maxtry';
$quantity = 123;
$fs = $this->createFsMock();
$fs->expects($this->once())
->method('remove')
->with(array('/path/to/file'));
$tmpFs = $this->createTmpFsMock();
$tmpFs->expects($this->once())
->method('createTemporaryFiles')
->with($quantity, $prefix, $suffix, $extension, $maxTry)
->will($this->returnValue(array('/path/to/file')));
$manager = new Manager($tmpFs, $fs);
$this->assertEquals(array('/path/to/file'), $manager->createTemporaryFiles($quantity, $prefix, $suffix, $extension, $maxTry));
$manager->clean();
}
public function testCreate()
{
$this->assertInstanceOf('Neutron\TemporaryFilesystem\Manager', Manager::create());
}
private function createTmpFsMock()
{
return $this->getMock('Neutron\TemporaryFilesystem\TemporaryFilesystemInterface');
}
private function createFsMock()
{
return $this
->getMockBuilder('Symfony\Component\Filesystem\Filesystem')
->disableOriginalConstructor()
->getMock();
}
}
@@ -0,0 +1,206 @@
<?php
namespace Neutron\TemporaryFilesystem\Tests;
use Neutron\TemporaryFilesystem\TemporaryFilesystem;
use Symfony\Component\Filesystem\Filesystem;
class TemporaryFilesystemTest extends \PHPUnit_Framework_TestCase
{
/**
* @var string $workspace
*/
private $workspace = null;
/**
* @var TemporaryFilesystem
*/
private $filesystem;
public function setUp()
{
parent::setUp();
$this->workspace = sys_get_temp_dir().DIRECTORY_SEPARATOR.time().rand(0, 1000);
mkdir($this->workspace, 0777, true);
$this->workspace = realpath($this->workspace);
$this->filesystem = TemporaryFilesystem::create();
}
public function tearDown()
{
$this->clean($this->workspace);
}
public function testCreate()
{
$this->assertInstanceOf('Neutron\TemporaryFilesystem\TemporaryFilesystem', TemporaryFilesystem::create());
}
public function testConctruct()
{
$this->assertInstanceOf('Neutron\TemporaryFilesystem\TemporaryFilesystem', new TemporaryFilesystem(new Filesystem()));
}
/**
* @param string $file
*/
private function clean($file)
{
if (is_dir($file) && !is_link($file)) {
$dir = new \FilesystemIterator($file);
foreach ($dir as $childFile) {
$this->clean($childFile);
}
rmdir($file);
} else {
unlink($file);
}
}
/**
* @dataProvider provideFilesToCreate
*/
public function testCreateEmptyFile($prefix, $suffix, $extension, $maxTry, $pattern)
{
$createDir = $this->workspace . DIRECTORY_SEPARATOR . 'book-dir';
mkdir($createDir);
$file = $this->filesystem->createEmptyFile($createDir, $prefix, $suffix, $extension, $maxTry);
$this->assertTrue(file_exists($file));
$this->assertEquals($createDir, dirname($file));
$this->assertEquals(0, filesize($file));
$this->assertRegExp($pattern, basename($file));
unlink($file);
}
public function testCreateTemporaryDir()
{
$dir = $this->filesystem->createTemporaryDirectory();
$this->assertTrue(file_exists($dir));
$this->assertTrue(is_dir($dir));
rmdir($dir);
}
public function testCreateTemporaryDirWithPrefix()
{
$dir = $this->filesystem->createTemporaryDirectory(0777, 200, 'neutron');
$this->assertTrue(file_exists($dir));
$this->assertTrue(is_dir($dir));
$this->assertContains('neutron', $dir);
rmdir($dir);
}
public function provideFilesToCreate()
{
return array(
array(null, null, null, 10, '/\w{5}/'),
array('romain', null, null, 10, '/romain\w{5}/'),
array(null, 'neutron', null, 10, '/\w{5}neutron/'),
array(null, null, 'io', 10, '/\w{5}\.io/'),
array('romain', null, 'io', 10, '/romain\w{5}\.io/'),
array(null, 'neutron', 'io', 10, '/\w{5}neutron\.io/'),
array('romain', 'neutron', 'io', 10, '/romain\w{5}neutron\.io/'),
);
}
/**
* @expectedException Neutron\TemporaryFilesystem\IOException
*/
public function testCreateEmptyFileInvalidDir()
{
$createDir = $this->workspace . DIRECTORY_SEPARATOR . 'invalid-book-dir';
$this->filesystem->createEmptyFile($createDir);
}
/**
* @expectedException Neutron\TemporaryFilesystem\IOException
*/
public function testCreateEmptyFileInvalidDirSecondMethod()
{
$createDir = $this->workspace . DIRECTORY_SEPARATOR . 'invalid-book-dir';
$this->filesystem->createEmptyFile($createDir, 'romain', 'neutron');
}
/**
* @expectedException Neutron\TemporaryFilesystem\IOException
*/
public function testCreateEmptyFileFails()
{
$createDir = $this->workspace . DIRECTORY_SEPARATOR . 'book-dir';
mkdir($createDir);
$this->filesystem->createEmptyFile($createDir, 'romain', 'neutron', null, 0);
}
/**
* @expectedException Neutron\TemporaryFilesystem\IOException
*/
public function testCreateEmptyFileOnFile()
{
$createDir = $this->workspace . DIRECTORY_SEPARATOR . 'book-dir';
touch($createDir);
$this->filesystem->createEmptyFile($createDir, null, null, null);
}
/**
* @expectedException Neutron\TemporaryFilesystem\IOException
*/
public function testCreateEmptyFileOnFileSecondMethod()
{
$createDir = $this->workspace . DIRECTORY_SEPARATOR . 'book-dir';
touch($createDir);
$this->filesystem->createEmptyFile($createDir, 'romain', 'neutron', 'io');
}
/**
* @dataProvider provideFilesToCreate
*/
public function testTemporaryFiles($prefix, $suffix, $extension, $maxTry, $pattern)
{
$files = $this->filesystem->createTemporaryFiles(3, $prefix, $suffix, $extension, $maxTry);
$this->assertEquals(3, count($files));
foreach ($files as $file) {
$this->assertTrue(file_exists($file));
$this->assertEquals(realpath(sys_get_temp_dir()), realpath(dirname($file)));
$this->assertEquals(0, filesize($file));
$this->assertRegExp($pattern, basename($file));
}
}
/**
* @dataProvider provideFilesToCreate
*/
public function testTemporaryFile($prefix, $suffix, $extension, $maxTry, $pattern)
{
$file = $this->filesystem->createTemporaryFile($prefix, $suffix, $extension, $maxTry);
$this->assertInternalType('string', $file);
$this->assertTrue(file_exists($file));
$this->assertEquals(realpath(sys_get_temp_dir()), realpath(dirname($file)));
$this->assertEquals(0, filesize($file));
$this->assertRegExp($pattern, basename($file));
}
/**
* @expectedException Neutron\TemporaryFilesystem\IOException
*/
public function testTemporaryFilesFails()
{
$this->filesystem->createTemporaryFiles(3, 'prefix', 'suffix', null, 0);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testTemporaryFilesInvalidQuantity()
{
$this->filesystem->createTemporaryFiles(0);
}
}
@@ -0,0 +1,4 @@
<?php
$loader = require __DIR__ . '/../vendor/autoload.php';
$loader->add('Neutron\TemporaryFilesystem\Tests', __DIR__ . '/../tests');

Some files were not shown because too many files have changed in this diff Show More