Initial checkin

This commit is contained in:
2019-07-08 01:13:30 +02:00
commit 6e662f0263
19 changed files with 795 additions and 0 deletions

73
src/Ingredient/Base.php Normal file
View File

@ -0,0 +1,73 @@
<?php
namespace NoccyLabs\Juicer\Ingredient;
class Base
{
const MASS_PG = 1.038;
const MASS_VG = 1.26;
protected static $MASS = [
'PG' => self::MASS_PG,
'VG' => self::MASS_VG,
];
protected $base;
protected $components = [];
protected $specificGravity;
public function __construct(string $base)
{
$this->components = self::parseComponents($base);
$this->base = $base;
$this->specificGravity = self::calculateSpecificGravity($this->components);
}
public function getSpecificGravity(): float
{
return $this->specificGravity;
}
public function getComponents(): array
{
return $this->components;
}
public static function parseComponents(string $base)
{
$found = [];
if (!preg_match('/^([A-Z]+)([0-9]{1,3}+)$/i', $base, $match)) {
throw new \Exception();
}
if ($match[1] == "PG") {
return [
'PG' => $match[2],
'VG' => 100 - $match[2]
];
} elseif ($match[1] == "VG") {
return [
'PG' => 100 - $match[2],
'VG' => $match[2]
];
}
}
public static function calculateSpecificGravity(array $components): float
{
$specificGravity = 0.0;
foreach ($components as $component=>$percent) {
$percentFloat = $percent / 100;
$specificGravity += (self::$MASS[$component] * $percentFloat);
}
return $specificGravity;
}
public function __toString()
{
return $this->base;
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace NoccyLabs\Juicer\Ingredient;
class Ingredient implements IngredientInterface
{
protected $name;
protected $brand;
protected $percent;
protected $base;
public function __construct(string $name, ?string $brand=null, float $percent=0.0, string $base="PG100")
{
$this->name = $name;
$this->brand = $brand;
$this->percent = $percent;
$this->base = $base;
}
/**
* {@inheritDoc}
*/
public function getFlavorName(): string
{
return $this->name;
}
/**
* {@inheritDoc}
*/
public function getFlavorBrand(): ?string
{
return $this->brand;
}
/**
* {@inheritDoc}
*/
public function getPercent(): float
{
return $this->percent;
}
/**
* {@inheritDoc}
*/
public function getBase(): ?string
{
return $this->base;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace NoccyLabs\Juicer\Ingredient;
interface IngredientInterface
{
/**
* Return the name of the flavor
*
* @return string The name of the flavor
*/
public function getFlavorName(): string;
/**
* Return the short name of the flavor brand. This should be the upper-case
* abbreviation, and not the complete name.
*
* @return string|null The upper-case abbreviation of the flavor brand
*/
public function getFlavorBrand(): ?string;
/**
* Return the percent (0-100)
*
* @return float The percent of the flavor to use
*/
public function getPercent(): float;
/**
* Return the base mix used for this flavoring (usually PG100)
*
* @return string|null The base mix used
*/
public function getBase(): ?string;
}

View File

@ -0,0 +1,24 @@
<?php
namespace NoccyLabs\Juicer\Ingredient;
class NicotineBase
{
protected $base;
protected $strength;
public function __construct(Base $base, int $strength)
{
$this->base = $base;
$this->nicotineStrength = $strength;
}
public function getSpecificGravity(): float
{
return 0.0;
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace NoccyLabs\Juicer\Recipe\Exporter;
use NoccyLabs\Juicer\Recipe\RecipeInterface;
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
class JsonExporter
{
public function export(RecipeInterface $recipe)
{
$ingredients = [];
/** @var IngredientInterface $ingredient */
foreach ($recipe->getIngredients() as $ingredient) {
$ingredients[] = [
'brand' => $ingredient->getFlavorBrand(),
'flavor' => $ingredient->getFlavorName(),
'percent' => $ingredient->getPercent()
];
}
$document = [
'recipe' => $recipe->getRecipeName(),
'author' => $recipe->getRecipeAuthor(),
'tags' => $recipe->getTags(),
'description' => $recipe->getDescription(),
'extra' => $recipe->getExtra(),
'ingredients' => $ingredients
];
return json_encode($document,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function writeToFile(RecipeInterface $recipe, string $filename)
{
$json = $this->export($recipe);
$fd = fopen($filename, "w");
if (!$fd) {
throw new \InvalidArgumentException();
}
fwrite($fd, $json, strlen($json));
fclose($fd);
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace NoccyLabs\Juicer\Recipe\Importer;
use NoccyLabs\Juicer\Recipe\RecipeInterface;
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
use NoccyLabs\Juicer\Recipe\Recipe;
use NoccyLabs\Juicer\Ingredient\Ingredient;
class JsonImporter
{
public function import(string $json): RecipeInterface
{
$data = json_decode($json);
$recipe = new Recipe();
$recipe->setRecipeName(@$data->recipe);
$recipe->setRecipeAuthor(@$data->author);
$recipe->setDescription(@$data->description);
$recipe->setExtra((array)@$data->extra);
foreach ((array)@$data->ingredients as $ingredientData) {
$ingredient = new Ingredient($ingredientData->flavor, $ingredientData->brand, $ingredientData->percent);
$recipe->addIngredient($ingredient);
}
return $recipe;
}
public function readFromFile(string $filename): RecipeInterface
{
$fd = fopen($filename, "r");
if (!$fd) {
throw new \InvalidArgumentException();
}
$json = fread($fd, filesize($filename));
fclose($fd);
return $this->import($json);
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace NoccyLabs\Juicer\Recipe\Mixer;
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
use NoccyLabs\Juicer\Ingredient\Base;
class MeasuredIngredient implements IngredientInterface
{
/** @var string */
protected $name;
/** @var string|null */
protected $brand;
/** @var string */
protected $base;
/** @var float The apparent specific gravity (ASG) of this ingredient in g/mL */
protected $asg;
/** @var float The percent of this ingredient in the final mix */
protected $pecent;
/** @var float Volume in milliliters (mL) */
protected $volume;
/** @var float Weight in grams (g) */
protected $weight;
public function __construct(string $name, ?string $brand, string $base, float $asg, float $percent, float $volume)
{
$this->name = $name;
$this->brand = $brand;
$this->base = $base;
$this->asg = $asg;
$this->percent = $percent;
$this->volume = $volume;
$this->weight = $volume * $asg;
}
public function getFlavorName(): string
{
return $this->name;
}
public function getFlavorBrand(): ?string
{
return $this->brand;
}
public function getBase(): ?string
{
return $this->base;
}
public function getPercent(): float
{
return $this->percent;
}
public function getSpecificGravity(): float
{
return $this->asg;
}
public function getVolume(): float
{
return $this->volume;
}
public function getWeight(): float
{
return $this->weight;
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace NoccyLabs\Juicer\Recipe\Mixer;
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
use NoccyLabs\Juicer\Recipe\RecipeInterface;
use NoccyLabs\Juicer\Ingredient\Base;
use NoccyLabs\Juicer\Ingredient\NicotineBase;
class Mixer
{
public function mixRecipe(RecipeInterface $recipe, int $volume, Base $base, int $nicotineStrength, ?NicotineBase $nicotineBase=null)
{
$mixed = [];
$components = $base->getComponents();
if (array_key_exists('VG', $components) && $components['VG'] > 0) {
$mixed[] = new MeasuredIngredient("VG", null, "VG100", Base::MASS_VG, 100, $volume);
}
if (array_key_exists('PG', $components) && $components['PG'] > 0) {
$mixed[] = new MeasuredIngredient("PG", null, "PG100", Base::MASS_PG, 100, $volume);
}
return $mixed;
}
}

110
src/Recipe/Recipe.php Normal file
View File

@ -0,0 +1,110 @@
<?php
namespace NoccyLabs\Juicer\Recipe;
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
class Recipe implements RecipeInterface
{
/** @var string */
protected $name;
/** @var string */
protected $author;
/** @var string[] */
protected $tags = [];
/** @var array */
protected $extra = [];
/** @var string */
protected $description;
/** @var IngredientInterface[] */
protected $ingredients = [];
public function setRecipeName(?string $name)
{
$this->name = $name;
}
public function setRecipeAuthor(?string $author)
{
$this->author = $author;
}
public function setTags(array $tags)
{
$this->tags = $tags;
}
public function addTag(string $tag)
{
$this->tags[] = $tag;
}
public function setDescription(?string $description)
{
$this->description = $description;
}
public function addIngredient(IngredientInterface $ingredient)
{
$this->ingredients[] = $ingredient;
}
public function setExtra(array $extra)
{
$this->extra = $extra;
}
/**
* {@inheritDoc}
*/
public function getRecipeName(): ?string
{
return $this->name;
}
/**
* {@inheritDoc}
*/
public function getRecipeAuthor(): ?string
{
return $this->author;
}
/**
* {@inheritDoc}
*/
public function getTags(): array
{
return $this->tags;
}
/**
* {@inheritDoc}
*/
public function getExtra(): array
{
return $this->extra;
}
/**
* {@inheritDoc}
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* {@inheritDoc}
*/
public function getIngredients(): array
{
return $this->ingredients;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace NoccyLabs\Juicer\Recipe;
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
interface RecipeInterface
{
public function getRecipeName(): ?string;
public function getRecipeAuthor(): ?string;
public function getTags(): array;
public function getDescription(): ?string;
public function getExtra(): array;
/**
* Get an array containing the ingredients of the recipe.
*
* @return IngredientInterface[] The ingredients
*/
public function getIngredients(): array;
}