Add smiles converter as service

This commit is contained in:
Saul Johnson
2017-08-06 19:42:46 +01:00
parent b6cf123bfe
commit cc7af9d541
6 changed files with 235 additions and 29 deletions
+6
View File
@@ -66,3 +66,9 @@ phpunit.phar
# Compiled code
/web/js/
/web/css/
# Caches
/db/*.dat
# Keep files
!.gitkeep
+7 -1
View File
@@ -14,6 +14,12 @@
"twig/twig": "^1.24",
"mustangostang/spyc": "^0.5.1",
"intervention/image": "^2.4",
"guzzlehttp/guzzle": "^6.3"
"guzzlehttp/guzzle": "^6.3",
"lambdacasserole/condense": "^1.1"
},
"autoload": {
"psr-4": {
"Avogadrio\\": "src/"
}
}
}
Generated
+148 -1
View File
@@ -4,8 +4,71 @@
"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": "5e740fc02164dd61e791ba1ae1a34860",
"content-hash": "414181a9b439757b16b4938d109a80bd",
"packages": [
{
"name": "defuse/php-encryption",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/defuse/php-encryption.git",
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689",
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"paragonie/random_compat": "~2.0",
"php": ">=5.4.0"
},
"require-dev": {
"nikic/php-parser": "^2.0|^3.0",
"phpunit/phpunit": "^4|^5"
},
"bin": [
"bin/generate-defuse-key"
],
"type": "library",
"autoload": {
"psr-4": {
"Defuse\\Crypto\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Hornby",
"email": "taylor@defuse.ca",
"homepage": "https://defuse.ca/"
},
{
"name": "Scott Arciszewski",
"email": "info@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "Secure PHP Encryption Library",
"keywords": [
"aes",
"authenticated encryption",
"cipher",
"crypto",
"cryptography",
"encrypt",
"encryption",
"openssl",
"security",
"symmetric key cryptography"
],
"time": "2017-05-18T21:28:48+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.3.0",
@@ -257,6 +320,42 @@
],
"time": "2017-07-03T15:50:40+00:00"
},
{
"name": "lambdacasserole/condense",
"version": "v1.1",
"source": {
"type": "git",
"url": "https://github.com/lambdacasserole/condense.git",
"reference": "dcbe8d7ca5ee0909a0df7c47e493311d130cbe9d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lambdacasserole/condense/zipball/dcbe8d7ca5ee0909a0df7c47e493311d130cbe9d",
"reference": "dcbe8d7ca5ee0909a0df7c47e493311d130cbe9d",
"shasum": ""
},
"require": {
"defuse/php-encryption": "^2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Condense\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Saul Johnson",
"email": "saul.a.johnson@gmail.com"
}
],
"description": "Flat-file database in PHP.",
"time": "2017-01-30T14:35:04+00:00"
},
{
"name": "mustangostang/spyc",
"version": "0.5.1",
@@ -304,6 +403,54 @@
],
"time": "2013-02-21T10:52:01+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.10",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"pseudorandom",
"random"
],
"time": "2017-03-13T16:27:32+00:00"
},
{
"name": "pimple/pimple",
"version": "v3.0.2",
View File
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace Avogadrio;
use Condense\Database;
use \GuzzleHttp\Client;
/**
* Provides a conversion service between compound names and SMILES strings.
*
* @author Saul Johnson <saul.a.johnson@gmail.com>
* @since 06/08/2017
* @package Avogadrio
*/
class SmilesConverter
{
/**
* The compound name/SMILES cache database.
*
* @var Database
*/
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* Converts a compound name to SMILES notation.
*
* @param string $name the name of the compound
* @return null|string the SMILES notation for the named compound or null if not found
*/
public function nameToSmiles($name)
{
// Sanitize name for URLs.
$encoded = urlencode($name);
// Check if we've got the name cached already.
$cachedSmiles = $this->db->get('smiles', 'name', $encoded);
if ($cachedSmiles !== null) {
return $cachedSmiles;
}
// Convert chemical name to SMILES if we can using API.
$client = new Client(['verify' => false, 'exceptions' => false]);
$response = $client->request('GET', "https://cactus.nci.nih.gov/chemical/structure/$encoded/smiles");
// If request was successful.
if ($response->getStatusCode() === 200) {
$smiles = $response->getBody()->getContents();
$this->db->insert(['name' => $encoded, 'smiles' => $smiles]); // Cache name for future.
return $smiles;
}
// Request failed.
return null;
}
}
+14 -26
View File
@@ -1,6 +1,6 @@
<?php
require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -8,11 +8,17 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
use Intervention\Image\ImageManagerStatic as Image;
use Condense\Database;
use Avogadrio\SmilesConverter;
// Configure GD as image driver.
Image::configure(array('driver' => 'gd'));
// Load config.
$config = Spyc::YAMLLoad(__DIR__.'/../config/config.yaml');
$config = Spyc::YAMLLoad(__DIR__ . '/../config/config.yaml');
// Caching SMILES converter.
$smilesConverter = new SmilesConverter(new Database('names', __DIR__ . '/../db'));
$app = new Silex\Application();
@@ -59,24 +65,6 @@ function renderScaledMolecule($canvasWidth, $canvasHeight, $color, $smiles) {
return $molecule;
}
/**
* Converts a compound name to SMILES notation.
*
* @param array $config the configuration settings for the application
* @param string $name the name of the compound
* @return null|string the SMILES notation for the named compound or null if not found
*/
function nameToSmiles($config, $name) {
// Convert chemical name to SMILES if we can using API.
$client = new GuzzleHttp\Client(['verify' => false, 'exceptions' => false]);
$res = $client->request('GET',
str_replace('$name', urlencode($name), $config['chem_name_lookup_service']));
// If request successful return SMILES, otherwise null.
return $res->getStatusCode() == 200 ? $res->getBody() : null;
}
/*
* Route actions.
*/
@@ -104,10 +92,10 @@ $app->get('/api/smiles/{width}/{height}/{bgcolor}/{fgcolor}/{smiles}', function
);
});
$app->get('/api/name/{width}/{height}/{bgcolor}/{fgcolor}/{name}', function ($width, $height, $bgcolor, $fgcolor, $name) use ($app, $twig, $config) {
$app->get('/api/name/{width}/{height}/{bgcolor}/{fgcolor}/{name}', function ($width, $height, $bgcolor, $fgcolor, $name) use ($app, $smilesConverter) {
// Convert chemical name to SMILES if we can.
$smiles = nameToSmiles($config, $name);
$smiles = $smilesConverter->nameToSmiles($name);
// Forward to SMILES route.
if ($smiles !== null) {
@@ -127,14 +115,14 @@ $app->get('/api/smiles/{width}/{height}/{color}/{smiles}', function ($width, $he
);
});
$app->get('/api/name/exists/{name}', function ($name) use ($config) {
return new JsonResponse(nameToSmiles($config, $name) === null ? false : true);
$app->get('/api/name/exists/{name}', function ($name) use ($config, $smilesConverter) {
return new JsonResponse($smilesConverter->nameToSmiles($name) === null ? false : true);
});
$app->get('/api/name/{width}/{height}/{color}/{name}', function ($width, $height, $color, $name) use ($app, $twig, $config) {
$app->get('/api/name/{width}/{height}/{color}/{name}', function ($width, $height, $color, $name) use ($app, $twig, $config, $smilesConverter) {
// Convert chemical name to SMILES if we can.
$smiles = nameToSmiles($config, $name);
$smiles = $smilesConverter->nameToSmiles($name);
// Forward to SMILES route.
if ($smiles !== null) {