Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
afi
Pellicule
Commits
5e6fbfe6
Commit
5e6fbfe6
authored
Jun 10, 2020
by
Henri-Damien LAURENT
Browse files
refactoring
parent
ba7e79a4
Pipeline
#10305
passed with stage
in 41 seconds
Changes
12
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
270 additions
and
427 deletions
+270
-427
.gitlab-ci.yml
.gitlab-ci.yml
+2
-1
src/Controllers/Media.php
src/Controllers/Media.php
+32
-23
src/FileSystem.php
src/FileSystem.php
+16
-15
src/Models/Media.php
src/Models/Media.php
+45
-20
src/Providers/Electre.php
src/Providers/Electre.php
+3
-4
tests/BrowserMockBuilder.php
tests/BrowserMockBuilder.php
+0
-76
tests/FileSystemTest.php
tests/FileSystemTest.php
+24
-39
tests/MediaTest.php
tests/MediaTest.php
+112
-201
tests/OrbTest.php
tests/OrbTest.php
+0
-45
tests/TestCase.php
tests/TestCase.php
+35
-2
tests/bootstrap.php
tests/bootstrap.php
+1
-1
tests/decitre_test.json
tests/decitre_test.json
+0
-0
No files found.
.gitlab-ci.yml
View file @
5e6fbfe6
...
...
@@ -4,7 +4,8 @@ test:php7_latest:
-
apt update -yqq && apt install git zip -yqq
-
git submodule init
-
git submodule update
-
./vendor/bin/phpunit -c tests/phpunit.xml
-
php --version
-
./vendor/bin/phpunit -c tests/phpunit.xml --testdox
except
:
-
tags
tags
:
...
...
src/Controllers/Media.php
View file @
5e6fbfe6
<?php
namespace
Pellicule\Controllers
;
use
Slim\Routing\RouteContext
;
use
Slim\Psr7\Request
;
use
Slim\Psr7\Response
;
use
Fig\Http\Message\StatusCodeInterface
;
use
Pellicule\Models\Record
;
use
Pellicule\Providers\Provider
;
...
...
@@ -11,8 +9,15 @@ use Pellicule\Providers\FetchRecordResult;
class
Media
{
protected
$_request
,
$_args
=
[];
public
function
__invoke
(
$request
,
$response
,
$args
)
{
$fetch_result
=
$this
->
_fetchRecord
(
$request
,
$args
);
$this
->
_request
=
$request
;
$this
->
_args
=
$this
->
_processArgs
(
$args
);
$fetch_result
=
$this
->
_fetchRecord
();
if
(
$fetch_result
->
hasError
())
{
$response
->
getBody
()
->
write
(
json_encode
([
'error'
=>
$fetch_result
->
getErrorCode
()]));
...
...
@@ -23,52 +28,56 @@ class Media {
$record
=
$fetch_result
->
getRecord
();
$record
->
save
();
$response
->
getBody
()
->
write
(
$record
->
asJSON
());
return
$response
->
withHeader
(
'Content-Type'
,
'application/json'
);
}
protected
function
_fetchRecord
(
$request
,
$args
)
{
$findargs
=
$this
->
_processParams
(
$args
);
if
(
$record
=
Record
::
findFirstBy
(
$findargs
))
protected
function
_fetchRecord
()
{
if
(
!
$this
->
_args
)
return
(
new
FetchRecordResult
())
->
beError
(
StatusCodeInterface
::
STATUS_BAD_REQUEST
,
'no valid params provided'
);
if
(
$record
=
Record
::
findFirstBy
(
$this
->
_args
))
return
(
new
FetchRecordResult
())
->
beSuccess
(
$record
);
if
(
!
$request
->
hasHeader
(
'Authorization'
))
if
(
!
$
this
->
_
request
->
hasHeader
(
'Authorization'
))
return
(
new
FetchRecordResult
())
->
beError
(
StatusCodeInterface
::
STATUS_NOT_FOUND
,
'record not found'
);
return
$this
->
_fetchRecordFromProviders
(
$request
,
$findargs
);
return
$this
->
_fetchRecordFromProviders
();
}
protected
function
_fetchRecordFromProviders
(
$request
,
$args
){
$credentials
=
array_filter
(
$this
->
_parseAuthorizationHeader
(
$request
))
;
if
(
!
$cre
dent
ials
)
return
(
new
FetchRecordResult
())
->
beError
(
StatusCodeInterface
::
STATUS_PROXY_AUTHENTICATION_REQUIRED
,
'no_valid_authentication_information_provided'
);
protected
function
_fetchRecordFromProviders
()
{
if
(
!
$credentials
=
array_filter
(
$this
->
_parseAuthorizationHeader
(
)
))
return
(
new
FetchRecordResult
())
->
beError
(
StatusCo
de
I
nt
erface
::
STATUS_PROXY_AUTHENTICATION_REQUIRED
,
'no_valid_authentication_information_provided'
);
$provider
=
Provider
::
newProvider
(
$credentials
[
0
]);
return
$provider
->
fetchRecord
(
$this
->
_
processParams
(
$
args
)
)
;
return
$provider
->
fetchRecord
(
$this
->
_args
);
}
protected
function
_parseAuthorizationHeader
(
$request
){
return
(
new
\
Storm\
Model\
Collection
(
$request
->
getHeader
(
'Authorization'
)))
protected
function
_parseAuthorizationHeader
()
{
return
(
new
\
Storm\Collection
(
$
this
->
_
request
->
getHeader
(
'Authorization'
)))
->
select
(
function
(
$header
)
{
return
(
$header
&&
(
strpos
(
'Pellicule '
,
$header
)
==
0
));
return
(
$header
&&
'Pellicule '
==
substr
(
$header
,
0
,
1
0
));
})
->
collect
([
$this
,
'decodeAuthorizationHeader'
])
->
getArrayCopy
();
->
collect
([
$this
,
'decodeAuthorizationHeader'
])
->
getArrayCopy
();
}
public
function
decodeAuthorizationHeader
(
$string
){
public
function
decodeAuthorizationHeader
(
$string
)
{
return
json_decode
(
base64_decode
(
str_replace
(
'Pellicule '
,
''
,
$string
)),
true
);
}
protected
function
_processParams
(
$args
){
protected
function
_processArgs
(
$args
)
{
if
(
!
$args
)
return
;
return
[]
;
if
(
isset
(
$args
[
'isbn'
]))
return
[
'isbn'
=>
$args
[
'isbn'
]];
...
...
src/FileSystem.php
View file @
5e6fbfe6
...
...
@@ -14,28 +14,29 @@ class FileSystem {
}
public
function
download
(
$media
)
{
$directory
=
static
::
$_base_path
.
$media
->
getLocation
();
if
(
false
===
\
file_exists
(
$directory
))
\
mkdir
(
$directory
,
0755
,
true
);
public
function
fileExists
(
$path
)
{
return
\
file_exists
(
static
::
$_base_path
.
$path
);
}
if
(
!
$url_to_fetch
=
$media
->
getUrl
())
public
function
download
(
$url
,
$path
)
{
if
(
!
$url
||
!
$path
)
return
;
$client
=
$this
->
newHttpClient
();
$directory
=
pathinfo
(
static
::
$_base_path
.
$path
,
PATHINFO_DIRNAME
);
if
(
false
===
\
file_exists
(
$directory
))
\
mkdir
(
$directory
,
0755
,
true
);
if
(
false
===
(
$local_file
=
fopen
(
$directory
.
'/'
.
$media
->
getLocalFileName
()
,
'w'
)))
return
;
// can throw exception on invalid url
$request
=
(
new
RequestFactory
())
->
createRequest
(
'GET'
,
$url
)
;
if
(
false
===
(
$local_file
=
fopen
(
static
::
$_base_path
.
$path
,
'w'
)))
return
;
$
request
=
(
new
RequestFactory
())
->
createRequest
(
'GET'
,
$url_to_fetch
);
if
(
$request
)
$client
->
sendRequest
(
$request
,
[
'curl'
=>
[
'CURLOPT_FILE'
,
$local_file
]]
);
$
this
->
newHttpClient
()
->
sendRequest
(
$request
,
[
'curl'
=>
[
'CURLOPT_FILE'
,
$local_file
]]);
fclose
(
$local_file
);
// $media->resizeTo('thumbnail');
// $directory = static::$_base_path . $media->getLocation();
//
}
}
src/Models/Media.php
View file @
5e6fbfe6
...
...
@@ -5,16 +5,19 @@ use \Storm\Model\ModelAbstract;
class
Media
extends
ModelAbstract
{
protected
static
$_file_system
;
const
SIZE_FULL
=
'fullsize'
,
TYPE_COVER
=
'cover'
,
TYPE_BACKCOVER
=
'back_cover'
;
protected
$_size
;
protected
static
$_file_system
;
protected
$_table_name
=
'media'
,
$_belongs_to
=
[
'record'
=>
[
'model'
=>
Record
::
class
]
];
/** @category testing */
public
static
function
setFileSystem
(
$filesystem
)
{
static
::
$_file_system
=
$filesystem
;
}
...
...
@@ -34,39 +37,61 @@ class Media extends ModelAbstract {
public
function
afterSave
()
{
$this
->
getFileSystem
()
->
download
(
$this
);
if
(
!
$this
->
fileExists
())
$this
->
getFileSystem
()
->
download
(
$this
->
getUrl
(),
$this
->
getFilePath
());
}
public
function
fileExists
()
{
return
$this
->
isNew
()
?
false
:
$this
->
getFileSystem
()
->
fileExists
(
$this
->
getFilePath
());
}
public
function
getSize
(){
return
(
isset
(
$this
->
_size
))
?
$this
->
_size
:
'fullsize'
;
public
function
validate
()
{
$this
->
checkAttribute
(
'type'
,
in_array
(
$this
->
getType
(),
[
static
::
TYPE_COVER
,
static
::
TYPE_BACKCOVER
]),
'unknown type'
);
}
public
function
setSize
(
$string
){
$this
->
_size
=
$string
;
return
$this
;
public
function
getSize
()
{
return
static
::
SIZE_FULL
;
}
public
function
splitId
(){
return
array_slice
(
str_split
(
sprintf
(
"%04d"
,
$this
->
getId
()))
,
0
,
4
);
public
function
getFilePath
()
{
return
$this
->
getLocation
()
.
$this
->
getLocalFileName
();
}
public
function
getLocation
(){
return
'/'
.
implode
(
'/'
,
array_merge
([
$this
->
getSize
(),
$this
->
getType
()],
$this
->
splitId
()))
.
'/'
;
public
function
splitId
()
{
return
array_slice
(
str_split
(
sprintf
(
'%04d'
,
$this
->
getId
())),
0
,
4
);
}
public
function
getLocalFileName
(){
return
$this
->
getId
()
.
'.'
.
$this
->
getExtension
();
protected
function
getLocation
()
{
return
$this
->
isNew
()
?
''
:
'/'
.
implode
(
'/'
,
array_merge
([
$this
->
getSize
(),
$this
->
getType
()],
$this
->
splitId
()))
.
'/'
;
}
public
function
getExtension
(){
return
pathinfo
(
$this
->
getUrl
()
,
PATHINFO_EXTENSION
);
protected
function
getLocalFileName
()
{
return
$this
->
isNew
()
?
''
:
$this
->
getId
()
.
'.'
.
$this
->
getExtension
();
}
protected
function
getExtension
()
{
return
$this
->
hasUrl
()
?
pathinfo
(
$this
->
getUrl
(),
PATHINFO_EXTENSION
)
:
''
;
}
}
src/Providers/Electre.php
View file @
5e6fbfe6
...
...
@@ -38,11 +38,11 @@ class Electre extends Provider {
public
function
fetchRecord
(
$search_request
)
{
try
{
try
{
$response
=
$this
->
_getToken
(
$this
->
_client_id
,
$this
->
_client_secret
);
}
catch
(
\
Exception
$exception
)
{
return
(
new
FetchRecordResult
())
->
beError
(
StatusCodeInterface
::
STATUS_GATEWAY_TIMEOUT
,
,
'no_answer_from_gateway'
);
}
...
...
@@ -74,7 +74,6 @@ class Electre extends Provider {
'no_answer_from_gateway'
);
}
if
(
$response
->
getStatusCode
()
!=
StatusCodeInterface
::
STATUS_OK
)
return
(
new
FetchRecordResult
())
->
beError
(
StatusCodeInterface
::
STATUS_NOT_FOUND
,
'ean_not_found'
);
...
...
@@ -100,7 +99,7 @@ class Electre extends Provider {
return
(
new
\
Pellicule\Models\Media
())
->
setProvider
(
$this
->
providerName
())
->
setUrl
(
$link
->
href
)
->
setType
(
((
$link
->
rel
==
'coverCopy'
)
->
setType
(
((
$link
->
rel
==
'coverCopy'
)
?
'back_cover'
:
$link
->
rel
));
});
...
...
tests/BrowserMockBuilder.php
deleted
100644 → 0
View file @
ba7e79a4
<?php
namespace
Pellicule\Tests
;
class
BrowserMockBuilder
{
protected
$_mock
;
public
function
__construct
()
{
$stack
=
debug_backtrace
(
DEBUG_BACKTRACE_IGNORE_ARGS
,
2
);
$this
->
_mock
=
\
Storm\Test\ObjectWrapper
::
mock
(
'from '
.
$stack
[
0
][
'file'
]
.
':'
.
$stack
[
0
][
'line'
]);
}
public
function
expectHttpQuery
(
$request
,
$response
)
{
$request
=
array_merge
([
'type'
=>
'get'
,
'url'
=>
''
,
'headers'
=>
[],
'body'
=>
[]],
$request
);
$with_params
=
[];
$with_params
[]
=
$request
[
'url'
];
$sith_params
[]
=
$request
[
'headers'
];
if
(
$request
[
'type'
]
==
'post'
)
$with_params
[]
=
http_build_query
(
$request
[
'body'
]);
$this
->
_mock
->
whenCalled
(
$request
[
'type'
])
->
with
(
$with_params
)
->
answers
(
$this
->
_forgePSR7Response
(
$response
));
return
$this
;
}
public
function
expectPost
(
$post
,
$response
)
{
$post
=
array_merge
([
'url'
=>
''
,
'headers'
=>
[],
'body'
=>
[]],
$post
);
$this
->
_mock
->
whenCalled
(
'post'
)
->
with
(
$post
[
'url'
],
$post
[
'headers'
],
http_build_query
(
$post
[
'body'
]))
->
answers
(
$this
->
_forgePSR7Response
(
$response
));
return
$this
;
}
public
function
expectGet
(
$get
,
$response
)
{
$get
=
array_merge
([
'url'
=>
''
,
'headers'
=>
[]],
$get
);
$this
->
_mock
->
whenCalled
(
'get'
)
->
with
(
$get
[
'url'
],
$get
[
'headers'
])
->
answers
(
$this
->
_forgePSR7Response
(
$response
));
return
$this
;
}
public
function
getMock
()
{
return
$this
->
_mock
;
}
protected
function
_forgePSR7Response
(
$response
)
{
$response
=
array_merge
([
'status'
=>
200
,
'headers'
=>
null
,
'content'
=>
''
],
$response
);
return
new
\
Slim\Psr7\Response
(
$response
[
'status'
],
$response
[
'headers'
],
(
new
\
Slim\Psr7\Factory\StreamFactory
())
->
createStream
(
$response
[
'content'
]));
}
}
tests/FileSystemTest.php
View file @
5e6fbfe6
...
...
@@ -7,46 +7,38 @@ use Pellicule\Models\Record;
use
Pellicule\Models\Media
;
use
Pellicule\Providers\Electre
;
use
Pellicule\Providers\Orb
;
use
Pellicule\FileSystem
;
use
\
org\bovigo\vfs\vfsStream
;
class
FileSystemTest
extends
TestCase
{
protected
$_root
;
public
function
setUp
(){
$this
->
_root
=
vfsStream
::
setup
(
'myDir'
);
FileSystem
::
setBasePath
(
vfsStream
::
url
(
'myDir'
));
$mock_browser
=
(
new
BrowserMockBuilder
())
->
expectGet
([
'url'
=>
'http://image.org/city.jpg'
,
],
[
'content'
=>
file_get_contents
(
realpath
(
dirname
(
__FILE__
))
.
'/'
.
'imagefullsize.jpg'
)])
->
getMock
()
->
beStrict
();
$app
=
AppFactory
::
create
();
Record
::
newInstance
([
'id'
=>
1
,
'isbn'
=>
'2259228194'
,
'ean'
=>
'9782259228190'
,
'ark'
=>
'https://catalogue.bnf.fr/ark:/12148/cb445155569'
])
->
assertSave
();
Media
::
newInstance
([
'id'
=>
135
,
'record_id'
=>
1
,
'type'
=>
'cover'
,
'url'
=>
'http://image.org/city.jpg'
,
'provider'
=>
'Me'
,
'created_at'
=>
'2020-01-13 08:00:00'
,
'updated_at'
=>
'2020-01-16 08:00:00'
])
->
assertSave
();
parent
::
setUp
();
Media
::
setFileSystem
(
null
);
$this
->
_http_client
->
whenCalled
(
'get'
)
->
answers
(
$this
->
_forgePSR7Response
([
'content'
=>
file_get_contents
(
realpath
(
dirname
(
__FILE__
))
.
'/'
.
'imagefullsize.jpg'
)]));
$this
->
fixture
(
Record
::
class
,
[
'id'
=>
1
,
'isbn'
=>
'2259228194'
,
'ean'
=>
'9782259228190'
,
'ark'
=>
'https://catalogue.bnf.fr/ark:/12148/cb445155569'
]);
$this
->
fixture
(
Media
::
class
,
[
'id'
=>
135
,
'record_id'
=>
1
,
'type'
=>
'cover'
,
'url'
=>
'http://image.org/city.jpg'
,
'provider'
=>
'Me'
,
'created_at'
=>
'2020-01-13 08:00:00'
,
'updated_at'
=>
'2020-01-16 08:00:00'
]);
}
/** @test */
public
function
fullsizeCoverDirectoryShouldBeCreated
()
{
$this
->
assertTrue
(
$this
->
_root
->
hasChild
(
'fullsize/cover/0/1'
));
...
...
@@ -57,11 +49,4 @@ class FileSystemTest extends TestCase {
public
function
fullsizeCoverFileShouldBeCreated
()
{
$this
->
assertTrue
(
$this
->
_root
->
hasChild
(
'fullsize/cover/0/1/3/5/135.jpg'
));
}
//TBD
/** @test */
// public function thumbnailCoverDirectoryShouldBeCreated() {
// $this->assertTrue($this->_root->hasChild('thumbnail/cover/0/1/3/5/135.jpg'));
//}
}
tests/MediaTest.php
View file @
5e6fbfe6
This diff is collapsed.
Click to expand it.
tests/OrbTest.php
deleted
100644 → 0
View file @
ba7e79a4
<?php
namespace
Pellicule\Tests
;
use
Pellicule\AppFactory
;
use
Pellicule\Models\Record
;
use
Pellicule\Models\Media
;
use
Pellicule\Providers\Orb
;
class
OrbGetTest
extends
TestCase
{
public
function
setUp
(){
parent
::
setUp
();
$mock_browser
=
(
new
BrowserMockBuilder
())
->
expectGet
([
'url'
=>
'https://api.base-orb.fr/v1/products?sort=ean_asc&eans=9782212144383'
,
'headers'
=>
[
'Authorization'
=>
'Basic '
.
base64_encode
(
'test:s3cr3t'
),
'Accept-Encoding'
=>
'deflate, gzip'
]
],
[
'content'
=>
file_get_contents
(
realpath
(
dirname
(
__FILE__
))
.
'/'
.
'decitre_test.json'
)])
->
getMock
()
->
beStrict
();
Orb
::
setDefaultHttpClient
(
$mock_browser
);
$ident_request
=
[
'username'
=>
'test'
,
'secret'
=>
's3cr3t'
];
$search_request
=
[
'ean'
=>
'9782212144383'
];
((
new
Orb
(
$ident_request
))
->
fetchRecord
(
$search_request
))
->
getRecord
()
->
save
();
}
/** @test */
public
function
databaseShouldContainsOneRecord
()
{
$this
->
assertEquals
(
1
,
Record
::
count
());
}
/** @test */
public
function
databaseShouldContainsOneMedia
()
{
$this
->
assertEquals
(
1
,
Media
::
count
());
}
}
\ No newline at end of file
tests/TestCase.php
View file @
5e6fbfe6
...
...
@@ -3,21 +3,53 @@ namespace Pellicule\Tests;
use
\
Pellicule\AppFactory
;
use
\
Pellicule\Models\Media
;
use
\
Pellicule\FileSystem
;
use
\
Pellicule\Providers\Provider
;
use
\
Slim\Psr7\Request
;
use
\
Slim\Psr7\Headers
;
use
\
Slim\Psr7\Factory\UriFactory
;
use
\
Slim\Psr7\Factory\StreamFactory
;
use
\
Storm\Test\THelpers
;
use
\
Storm\Model\ModelAbstract
;
use
\
org\bovigo\vfs\vfsStream
;
abstract
class
TestCase
extends
\
PHPUnit\Framework\TestCase
{
use
THelpers
;
protected
$_root
,
$_http_client
;
public
function
setUp
()
{
parent
::
setUp
();
ModelAbstract
::
unsetLoaders
();
Media
::
setFileSystem
(
$this
->
mock
());
$this
->
_root
=
vfsStream
::
setup
(
'myDir'
);
FileSystem
::
setBasePath
(
vfsStream
::
url
(
'myDir'
));
$this
->
_http_client
=
$this
->
mock
();
Provider
::
setDefaultHttpClient
(
$this
->
_http_client
);
}
public
function
tearDown
()
{
Provider
::
setDefaultHttpClient
(
null
);
FileSystem
::
setDefaultHttpClient
(
null
);
Media
::
setFileSystem
(
null
);
ModelAbstract
::
unsetLoaders
();
parent
::
tearDown
();
}
protected
function
_forgePSR7Response
(
$response
)
{
$response
=
array_merge
([
'status'
=>
200
,
'headers'
=>
null
,
'content'
=>
''
],
$response
);
return
new
\
Slim\Psr7\Response
(
$response
[
'status'
],
$response
[
'headers'
],
(
new
\
Slim\Psr7\Factory\StreamFactory
())
->
createStream
(
$response
[
'content'
]));
}
...
...
@@ -43,7 +75,8 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase {
return
$response
->
getBody
()
->
getContents
();
}
public
function
httpHeader
(
$url
,
$headers
=
[]){
public
function
httpStatusCode
(
$url
,
$headers
=
[]){
$response
=
$this
->
dispatch
(
$url
,
$headers
);
return
$response
->
getStatusCode
();
}
...
...
tests/bootstrap.php
View file @
5e6fbfe6
...
...
@@ -2,6 +2,6 @@
error_reporting
(
E_ALL
^
E_DEPRECATED
);
ini_set
(
'display_startup_errors'
,
1
);
ini_set
(
'display_errors'
,
1
);
ini_set
(
'xdebug.remote_port'
,
'93
0
1'
);
ini_set
(
'xdebug.remote_port'
,
'931
2
'
);
ini_set
(
'xdebug.remote_host'
,
'10.13.78.15'
);
require
__DIR__
.
'/../vendor/autoload.php'
;
tests/decitre_test.json
deleted
100644 → 0
View file @
ba7e79a4
File deleted
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment