4
0

update 2023-07-31 06:51:05

This commit is contained in:
Robot 2023-07-31 06:51:05 +02:00
parent 6cbfb33301
commit b9d1657195
Signed by: Robot
GPG Key ID: 14DECD44E7E1BB95
36 changed files with 2607 additions and 1086 deletions

View File

@ -44,6 +44,7 @@ This repository contains an index (see below) of all the approved powers within
- **Namespace**: [VDM\Joomla\GetBible\Abstraction](#vdm-joomla-getbible-abstraction)
- **abstract class Api** | [Details](src/7b490e63-8d1f-46de-a0c4-154272fd5d7f) | [Code](src/7b490e63-8d1f-46de-a0c4-154272fd5d7f/code.php) | [Settings](src/7b490e63-8d1f-46de-a0c4-154272fd5d7f/settings.json) | Super__7b490e63_8d1f_46de_a0c4_154272fd5d7f__Power
- **abstract class Watcher** | [Details](src/37e36c41-16a7-4c5d-972c-99acad5fd0b1) | [Code](src/37e36c41-16a7-4c5d-972c-99acad5fd0b1/code.php) | [Settings](src/37e36c41-16a7-4c5d-972c-99acad5fd0b1/settings.json) | Super__37e36c41_16a7_4c5d_972c_99acad5fd0b1__Power
- **Namespace**: [VDM\Joomla\GetBible\Api](#vdm-joomla-getbible-api)
- **final class Books** | [Details](src/491c91ce-6355-40d3-bbbd-622473c6c026) | [Code](src/491c91ce-6355-40d3-bbbd-622473c6c026/code.php) | [Settings](src/491c91ce-6355-40d3-bbbd-622473c6c026/settings.json) | Super__491c91ce_6355_40d3_bbbd_622473c6c026__Power
@ -83,6 +84,7 @@ This repository contains an index (see below) of all the approved powers within
- **class Model** | [Details](src/116eb429-bc51-4d14-b9aa-7145c86a29d1) | [Code](src/116eb429-bc51-4d14-b9aa-7145c86a29d1/code.php) | [Settings](src/116eb429-bc51-4d14-b9aa-7145c86a29d1/settings.json) | Super__116eb429_bc51_4d14_b9aa_7145c86a29d1__Power
- **class Openai** | [Details](src/ac5c7679-dd6e-4817-8e48-489e521122f1) | [Code](src/ac5c7679-dd6e-4817-8e48-489e521122f1/code.php) | [Settings](src/ac5c7679-dd6e-4817-8e48-489e521122f1/settings.json) | Super__ac5c7679_dd6e_4817_8e48_489e521122f1__Power
- **class Utilities** | [Details](src/b89d74ef-c71c-4a58-8455-5dbdfe94027a) | [Code](src/b89d74ef-c71c-4a58-8455-5dbdfe94027a/code.php) | [Settings](src/b89d74ef-c71c-4a58-8455-5dbdfe94027a/settings.json) | Super__b89d74ef_c71c_4a58_8455_5dbdfe94027a__Power
- **class Watcher** | [Details](src/c5077cd8-b042-4295-99cf-3a5ba2af7dce) | [Code](src/c5077cd8-b042-4295-99cf-3a5ba2af7dce/code.php) | [Settings](src/c5077cd8-b042-4295-99cf-3a5ba2af7dce/settings.json) | Super__c5077cd8_b042_4295_99cf_3a5ba2af7dce__Power
- **Namespace**: [VDM\Joomla\GetBible\Tagged](#vdm-joomla-getbible-tagged)
- **final class Paragraphs** | [Details](src/4cfff1bc-02b3-4c52-9e6e-7ceefb505a32) | [Code](src/4cfff1bc-02b3-4c52-9e6e-7ceefb505a32/code.php) | [Settings](src/4cfff1bc-02b3-4c52-9e6e-7ceefb505a32/settings.json) | Super__4cfff1bc_02b3_4c52_9e6e_7ceefb505a32__Power
@ -93,6 +95,11 @@ This repository contains an index (see below) of all the approved powers within
- **final class SessionHelper** | [Details](src/84e84cd1-c938-4559-8414-d5692db4118e) | [Code](src/84e84cd1-c938-4559-8414-d5692db4118e/code.php) | [Settings](src/84e84cd1-c938-4559-8414-d5692db4118e/settings.json) | Super__84e84cd1_c938_4559_8414_d5692db4118e__Power
- **final class StringHelper** | [Details](src/a5b32737-207d-4cf6-b8ae-ee815612c3a0) | [Code](src/a5b32737-207d-4cf6-b8ae-ee815612c3a0/code.php) | [Settings](src/a5b32737-207d-4cf6-b8ae-ee815612c3a0/settings.json) | Super__a5b32737_207d_4cf6_b8ae_ee815612c3a0__Power
- **final class Uri** | [Details](src/fc9ab6f0-c31b-4077-bb1c-2dcddd36f6bb) | [Code](src/fc9ab6f0-c31b-4077-bb1c-2dcddd36f6bb/code.php) | [Settings](src/fc9ab6f0-c31b-4077-bb1c-2dcddd36f6bb/settings.json) | Super__fc9ab6f0_c31b_4077_bb1c_2dcddd36f6bb__Power
- **Namespace**: [VDM\Joomla\GetBible\Watcher](#vdm-joomla-getbible-watcher)
- **final class Book** | [Details](src/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98) | [Code](src/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98/code.php) | [Settings](src/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98/settings.json) | Super__c2a8a5fa_8e7f_443a_86d7_a8c1e4cdfa98__Power
- **final class Chapter** | [Details](src/07d3888a-5f35-4ba7-977f-fb2f5cf99061) | [Code](src/07d3888a-5f35-4ba7-977f-fb2f5cf99061/code.php) | [Settings](src/07d3888a-5f35-4ba7-977f-fb2f5cf99061/settings.json) | Super__07d3888a_5f35_4ba7_977f_fb2f5cf99061__Power
- **final class Translation** | [Details](src/7d592acd-f031-4d0f-b667-584c88ae0495) | [Code](src/7d592acd-f031-4d0f-b667-584c88ae0495/code.php) | [Settings](src/7d592acd-f031-4d0f-b667-584c88ae0495/settings.json) | Super__7d592acd_f031_4d0f_b667_584c88ae0495__Power
---
```

View File

@ -0,0 +1,105 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# final class Chapter (Details)
> namespace: **VDM\Joomla\GetBible\Watcher**
```uml
@startuml
class Chapter << (F,LightGreen) >> #Green {
# Chapters $chapters
# Verses $verses
+ __construct(Load $load, Insert $insert, ...)
+ sync(string $translation, int $book, ...) : bool
- chapter(string $translation, int $book, ...) : bool
- verses(string $translation, int $book, ...) : bool
- update(string $translation, int $book, ...) : bool
- hash(string $hash) : bool
}
note right of Chapter::__construct
Constructor
since: 2.0.1
arguments:
Load $load
Insert $insert
Update $update
Chapters $chapters
Verses $verses
end note
note right of Chapter::sync
Sync the target being watched
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
end note
note right of Chapter::chapter
Load the chapter numbers
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
end note
note right of Chapter::verses
Load verses
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
end note
note right of Chapter::update
Trigger the update of the verses of a translation-book-chapter
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
end note
note right of Chapter::hash
Trigger the update of a chapter hash value
since: 2.0.1
return: bool
end note
@enduml
```
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,279 @@
<?php
/**
* @package GetBible
*
* @created 30th May, 2023
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git GetBible <https://git.vdm.dev/getBible>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\GetBible\Watcher;
use VDM\Joomla\GetBible\Database\Load;
use VDM\Joomla\GetBible\Database\Insert;
use VDM\Joomla\GetBible\Database\Update;
use VDM\Joomla\GetBible\Api\Chapters;
use VDM\Joomla\GetBible\Api\Verses;
use VDM\Joomla\GetBible\Abstraction\Watcher;
/**
* The GetBible Chapter Watcher
*
* @since 2.0.1
*/
final class Chapter extends Watcher
{
/**
* The Chapters class
*
* @var Chapters
* @since 2.0.1
*/
protected Chapters $chapters;
/**
* The Verses class
*
* @var Verses
* @since 2.0.1
*/
protected Verses $verses;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Chapters $chapters The chapters API object.
* @param Verses $verses The verses API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Chapters $chapters,
Verses $verses)
{
// load the parent constructor
parent::__construct($load, $insert, $update);
$this->chapters = $chapters;
$this->verses = $verses;
// set the table
$this->table = 'book';
}
/**
* Sync the target being watched
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation, int $book, int $chapter): bool
{
// load the target if not found
if ($this->chapter($translation, $book, $chapter)
&& $this->verses($translation, $book, $chapter))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API hash value
$hash = $this->chapters->sha($translation, $book, $chapter);
// confirm hash has not changed
if (hash_equals($hash, $this->target->sha))
{
return $this->bump();
}
if ($this->update($translation, $book, $chapter)
&& $this->hash($hash))
{
return true;
}
}
return false;
}
/**
* Load the chapter numbers
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
private function chapter(string $translation, int $book, int $chapter): bool
{
// check local value
if (($this->target = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'chapter'
)) !== null)
{
return true;
}
// get all the books
$chapters = $this->chapters->list($translation, $book);
// check return data
if (!isset($chapters->{$chapter}) || !isset($chapters->{$chapter}->sha))
{
return false;
}
// add them to the database
$this->insert->items((array) $chapters, 'chapter');
// check local value
if (($this->target = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'chapter'
)) !== null)
{
return true;
}
return false;
}
/**
* Load verses
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if in local database
* @since 2.0.1
*/
private function verses(string $translation, int $book, int $chapter): bool
{
// check local value
if (($text = $this->load->value(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter, 'verse' => 1],
'text', 'verse'
)) !== null)
{
return true;
}
// get all the verses
if (($verses = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
// dynamic update all verse objects
$insert = ['book_nr' => $book, 'abbreviation' => $translation];
array_walk($verses->verses, function ($item, $key) use ($insert) {
foreach ($insert as $k => $v) { $item->$k = $v; }
});
// add them to the database
$this->fresh = $this->insert->items((array) $verses->verses, 'verse');
return true;
}
/**
* Trigger the update of the verses of a translation-book-chapter
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(string $translation, int $book, int $chapter): bool
{
// load all the verses from the local database
if (($verses = $this->load->items(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'verse'
)) !== null)
{
// get verses from the API
if (($api = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
$update = [];
$insert = [];
$match = ['key' => 'verse', 'value' => ''];
// dynamic update all verse objects
foreach ($api->verses as $verse)
{
// check if the verse exist
$match['value'] = (int) $verse->verse;
if (($object = $this->getTarget($match, $verses)) !== null)
{
$verse->id = $object->id;
$verse->modified = $this->today;
$update[] = $verse;
}
else
{
$insert[] = $verse;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, 'verse');
}
// update the local verses
if ($update !== [] && $this->update->items($update, 'id', 'verse'))
{
return true;
}
}
return false;
}
/**
* Trigger the update of a chapter hash value
*
* @param string $hash The API chapter hash value.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function hash(string $hash): bool
{
// load the chapter
$update = [];
$update['id'] = $this->target->id;
$update['sha'] = $hash;
$update['created'] = $this->today;
// update the local chapter
return $this->update->row($update, 'id', 'chapter');
}
}

View File

@ -0,0 +1,248 @@
/**
* The Chapters class
*
* @var Chapters
* @since 2.0.1
*/
protected Chapters $chapters;
/**
* The Verses class
*
* @var Verses
* @since 2.0.1
*/
protected Verses $verses;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Chapters $chapters The chapters API object.
* @param Verses $verses The verses API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Chapters $chapters,
Verses $verses)
{
// load the parent constructor
parent::__construct($load, $insert, $update);
$this->chapters = $chapters;
$this->verses = $verses;
// set the table
$this->table = 'book';
}
/**
* Sync the target being watched
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation, int $book, int $chapter): bool
{
// load the target if not found
if ($this->chapter($translation, $book, $chapter)
&& $this->verses($translation, $book, $chapter))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API hash value
$hash = $this->chapters->sha($translation, $book, $chapter);
// confirm hash has not changed
if (hash_equals($hash, $this->target->sha))
{
return $this->bump();
}
if ($this->update($translation, $book, $chapter)
&& $this->hash($hash))
{
return true;
}
}
return false;
}
/**
* Load the chapter numbers
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
private function chapter(string $translation, int $book, int $chapter): bool
{
// check local value
if (($this->target = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'chapter'
)) !== null)
{
return true;
}
// get all the books
$chapters = $this->chapters->list($translation, $book);
// check return data
if (!isset($chapters->{$chapter}) || !isset($chapters->{$chapter}->sha))
{
return false;
}
// add them to the database
$this->insert->items((array) $chapters, 'chapter');
// check local value
if (($this->target = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'chapter'
)) !== null)
{
return true;
}
return false;
}
/**
* Load verses
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if in local database
* @since 2.0.1
*/
private function verses(string $translation, int $book, int $chapter): bool
{
// check local value
if (($text = $this->load->value(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter, 'verse' => 1],
'text', 'verse'
)) !== null)
{
return true;
}
// get all the verses
if (($verses = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
// dynamic update all verse objects
$insert = ['book_nr' => $book, 'abbreviation' => $translation];
array_walk($verses->verses, function ($item, $key) use ($insert) {
foreach ($insert as $k => $v) { $item->$k = $v; }
});
// add them to the database
$this->fresh = $this->insert->items((array) $verses->verses, 'verse');
return true;
}
/**
* Trigger the update of the verses of a translation-book-chapter
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(string $translation, int $book, int $chapter): bool
{
// load all the verses from the local database
if (($verses = $this->load->items(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'verse'
)) !== null)
{
// get verses from the API
if (($api = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
$update = [];
$insert = [];
$match = ['key' => 'verse', 'value' => ''];
// dynamic update all verse objects
foreach ($api->verses as $verse)
{
// check if the verse exist
$match['value'] = (int) $verse->verse;
if (($object = $this->getTarget($match, $verses)) !== null)
{
$verse->id = $object->id;
$verse->modified = $this->today;
$update[] = $verse;
}
else
{
$insert[] = $verse;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, 'verse');
}
// update the local verses
if ($update !== [] && $this->update->items($update, 'id', 'verse'))
{
return true;
}
}
return false;
}
/**
* Trigger the update of a chapter hash value
*
* @param string $hash The API chapter hash value.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function hash(string $hash): bool
{
// load the chapter
$update = [];
$update['id'] = $this->target->id;
$update['sha'] = $hash;
$update['created'] = $this->today;
// update the local chapter
return $this->update->row($update, 'id', 'chapter');
}

View File

@ -0,0 +1,39 @@
{
"add_head": "0",
"add_licensing_template": "2",
"extends": "37e36c41-16a7-4c5d-972c-99acad5fd0b1",
"guid": "07d3888a-5f35-4ba7-977f-fb2f5cf99061",
"implements": null,
"load_selection": null,
"name": "Chapter",
"power_version": "1.0.0",
"system_name": "Joomla.GetBible.Watcher.Chapter",
"type": "final class",
"use_selection": {
"use_selection0": {
"use": "c03b9c61-17d3-4774-a335-783903719f83",
"as": "default"
},
"use_selection1": {
"use": "a07d90f6-6ff2-40a1-99c1-0f2cf33c9adf",
"as": "default"
},
"use_selection2": {
"use": "d7a5f0c6-de60-4d31-b3e4-5d668a8f7d2e",
"as": "default"
},
"use_selection3": {
"use": "a752e4b2-9b5e-4188-8d33-3799c46d5119",
"as": "default"
},
"use_selection4": {
"use": "afa508bf-78f8-4616-97cc-f2809584c086",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\GetBible\\Watcher.Chapter",
"description": "The GetBible Chapter Watcher\r\n\r\n@since 2.0.1",
"licensing_template": "\/**\r\n * @package GetBible\r\n *\r\n * @created 30th May, 2023\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git GetBible <https:\/\/git.vdm.dev\/getBible>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "",
"composer": ""
}

View File

@ -15,6 +15,7 @@ namespace VDM\Joomla\GetBible;
use Joomla\DI\Container;
use VDM\Joomla\GetBible\Service\Api;
use VDM\Joomla\GetBible\Service\Utilities;
use VDM\Joomla\GetBible\Service\Watcher;
use VDM\Joomla\GetBible\Service\App;
use VDM\Joomla\GetBible\Service\Model;
use VDM\Joomla\GetBible\Service\Database;
@ -76,6 +77,7 @@ abstract class Factory implements FactoryInterface
return (new Container())
->registerServiceProvider(new Utilities())
->registerServiceProvider(new Api())
->registerServiceProvider(new Watcher())
->registerServiceProvider(new App())
->registerServiceProvider(new Model())
->registerServiceProvider(new Database());

View File

@ -46,6 +46,7 @@
return (new Container())
->registerServiceProvider(new Utilities())
->registerServiceProvider(new Api())
->registerServiceProvider(new Watcher())
->registerServiceProvider(new App())
->registerServiceProvider(new Model())
->registerServiceProvider(new Database());

View File

@ -20,6 +20,10 @@
"use": "b89d74ef-c71c-4a58-8455-5dbdfe94027a",
"as": "default"
},
"use_selection5": {
"use": "c5077cd8-b042-4295-99cf-3a5ba2af7dce",
"as": "default"
},
"use_selection2": {
"use": "56465044-94ed-4e00-b6db-160c67163df8",
"as": "default"

View File

@ -33,6 +33,7 @@ class Linker << (F,LightGreen) >> #Green {
- getPassword(string $linker, string $pass) : ?object
- setLinker(string $linker) : bool
- setPassword(string $linker, string $pass) : bool
- getGuid(string $table) : string
}
note right of Linker::__construct
@ -164,6 +165,13 @@ note right of Linker::setPassword
return: bool
end note
note left of Linker::getGuid
Get a GUID
since: 2.0.1
return: string
end note
@enduml
```

View File

@ -140,7 +140,8 @@ final class Linker
if ($setup)
{
$guid = (string) GuidHelper::get();
$guid = $this->getGuid('linker');
$this->session->set('getbible_active_linker_guid', $guid);
return $guid;
@ -537,19 +538,31 @@ final class Linker
return false;
}
$guid = (string) GuidHelper::get();
while (!GuidHelper::valid($guid, 'password', 0, 'getbible'))
{
// must always be set
$guid = (string) GuidHelper::get();
}
return $this->insert->row([
'name' => 'Favourite-Verse',
'linker' => $linker,
'password' => UserHelper::hashPassword($pass),
'guid' => $guid
'guid' => $this->getGuid('password')
], 'password');
}
/**
* Get a GUID
*
* @param string $table The table its for
*
* @return string The GUID value
* @since 2.0.1
**/
private function getGuid(string $table): string
{
$guid = (string) GuidHelper::get();
while (!GuidHelper::valid($guid, $table, 0, 'getbible'))
{
// must always be set
$guid = (string) GuidHelper::get();
}
return $guid;
}
}

View File

@ -110,7 +110,8 @@
if ($setup)
{
$guid = (string) GuidHelper::get();
$guid = $this->getGuid('linker');
$this->session->set('getbible_active_linker_guid', $guid);
return $guid;
@ -507,17 +508,29 @@
return false;
}
$guid = (string) GuidHelper::get();
while (!GuidHelper::valid($guid, 'password', 0, '[[[component]]]'))
{
// must always be set
$guid = (string) GuidHelper::get();
}
return $this->insert->row([
'name' => 'Favourite-Verse',
'linker' => $linker,
'password' => UserHelper::hashPassword($pass),
'guid' => $guid
'guid' => $this->getGuid('password')
], 'password');
}
/**
* Get a GUID
*
* @param string $table The table its for
*
* @return string The GUID value
* @since 2.0.1
**/
private function getGuid(string $table): string
{
$guid = (string) GuidHelper::get();
while (!GuidHelper::valid($guid, $table, 0, '[[[component]]]'))
{
// must always be set
$guid = (string) GuidHelper::get();
}
return $guid;
}

View File

@ -0,0 +1,79 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# abstract class Watcher (Details)
> namespace: **VDM\Joomla\GetBible\Abstraction**
```uml
@startuml
abstract Watcher #Orange {
# Load $load
# Insert $insert
# Update $update
# bool $fresh
# ?object $target
# string $table
+ __construct(Load $load, Insert $insert, ...)
+ isNew() : bool
# hold() : bool
# bump() : bool
# getTarget(array $match, array $local) : ?object
}
note right of Watcher::__construct
Constructor
since: 2.0.1
arguments:
Load $load
Insert $insert
Update $update
end note
note right of Watcher::isNew
The see if new target is newly installed
since: 2.0.1
return: bool
end note
note right of Watcher::hold
Check if its time to match the API hash
since: 2.0.1
return: bool
end note
note right of Watcher::bump
Bump the checking time
since: 2.0.1
return: bool
end note
note right of Watcher::getTarget
Get local targeted object
since: 2.0.1
return: ?object
end note
@enduml
```
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,177 @@
<?php
/**
* @package GetBible
*
* @created 30th May, 2023
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git GetBible <https://git.vdm.dev/getBible>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\GetBible\Abstraction;
use Joomla\CMS\Date\Date;
use VDM\Joomla\GetBible\Database\Load;
use VDM\Joomla\GetBible\Database\Insert;
use VDM\Joomla\GetBible\Database\Update;
/**
* The GetBible Watcher
*
* @since 2.0.1
*/
abstract class Watcher
{
/**
* The Load class
*
* @var Load
* @since 2.0.1
*/
protected Load $load;
/**
* The Insert class
*
* @var Insert
* @since 2.0.1
*/
protected Insert $insert;
/**
* The Update class
*
* @var Update
* @since 2.0.1
*/
protected Update $update;
/**
* The fresh load switch
*
* @var bool
* @since 2.0.1
*/
protected bool $fresh = false;
/**
* The target
*
* @var object|null
* @since 2.0.1
*/
protected ?object $target;
/**
* The target table
*
* @var string
* @since 2.0.1
*/
protected string $table;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update)
{
$this->load = $load;
$this->insert = $insert;
$this->update = $update;
// just in-case we set a date
$this->today = (new Date())->toSql();
}
/**
* The see if new target is newly installed
*
* @return bool true if is new
* @since 2.0.1
*/
public function isNew(): bool
{
return $this->fresh;
}
/**
* Check if its time to match the API hash
*
* @return bool false if its time to check for an update
* @since 2.0.1
*/
protected function hold(): bool
{
// Create DateTime objects from the strings
try {
$today = new \DateTime($this->today);
$created = new \DateTime($this->target->created);
} catch (\Exception $e) {
return false;
}
// Calculate the difference
$interval = $today->diff($created);
// Check if the interval is more than 1 month
if ($interval->m >= 1 || $interval->y >= 1)
{
return false; // More than a month, it's time to check for an update
}
else
{
return true; // Within the last month, hold off on the update check
}
}
/**
* Bump the checking time
*
* @return bool true when the update was a success
* @since 2.0.1
*/
protected function bump(): bool
{
$update = [];
$update['id'] = $this->target->id;
$update['created'] = $this->today;
// update the local verse
return $this->update->row($update, 'id', $this->table);
}
/**
* Get local targeted object
*
* @param array $match The [key, value].
* @param array $local The local values.
*
* @return object|null The found value
* @since 2.0.1
*/
protected function getTarget(array $match, array &$local): ?object
{
foreach ($local as $_value)
{
if ($_value->{$match['key']} === $match['value'])
{
return $value;
}
}
return null;
}
}

View File

@ -0,0 +1,148 @@
/**
* The Load class
*
* @var Load
* @since 2.0.1
*/
protected Load $load;
/**
* The Insert class
*
* @var Insert
* @since 2.0.1
*/
protected Insert $insert;
/**
* The Update class
*
* @var Update
* @since 2.0.1
*/
protected Update $update;
/**
* The fresh load switch
*
* @var bool
* @since 2.0.1
*/
protected bool $fresh = false;
/**
* The target
*
* @var object|null
* @since 2.0.1
*/
protected ?object $target;
/**
* The target table
*
* @var string
* @since 2.0.1
*/
protected string $table;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update)
{
$this->load = $load;
$this->insert = $insert;
$this->update = $update;
// just in-case we set a date
$this->today = (new Date())->toSql();
}
/**
* The see if new target is newly installed
*
* @return bool true if is new
* @since 2.0.1
*/
public function isNew(): bool
{
return $this->fresh;
}
/**
* Check if its time to match the API hash
*
* @return bool false if its time to check for an update
* @since 2.0.1
*/
protected function hold(): bool
{
// Create DateTime objects from the strings
try {
$today = new \DateTime($this->today);
$created = new \DateTime($this->target->created);
} catch (\Exception $e) {
return false;
}
// Calculate the difference
$interval = $today->diff($created);
// Check if the interval is more than 1 month
if ($interval->m >= 1 || $interval->y >= 1)
{
return false; // More than a month, it's time to check for an update
}
else
{
return true; // Within the last month, hold off on the update check
}
}
/**
* Bump the checking time
*
* @return bool true when the update was a success
* @since 2.0.1
*/
protected function bump(): bool
{
$update = [];
$update['id'] = $this->target->id;
$update['created'] = $this->today;
// update the local verse
return $this->update->row($update, 'id', $this->table);
}
/**
* Get local targeted object
*
* @param array $match The [key, value].
* @param array $local The local values.
*
* @return object|null The found value
* @since 2.0.1
*/
protected function getTarget(array $match, array &$local): ?object
{
foreach ($local as $_value)
{
if ($_value->{$match['key']} === $match['value'])
{
return $value;
}
}
return null;
}

View File

@ -0,0 +1,31 @@
{
"add_head": "1",
"add_licensing_template": "2",
"extends": "0",
"guid": "37e36c41-16a7-4c5d-972c-99acad5fd0b1",
"implements": null,
"load_selection": null,
"name": "Watcher",
"power_version": "1.0.0",
"system_name": "Joomla.GetBible.Abstraction.Watcher",
"type": "abstract class",
"use_selection": {
"use_selection0": {
"use": "c03b9c61-17d3-4774-a335-783903719f83",
"as": "default"
},
"use_selection1": {
"use": "a07d90f6-6ff2-40a1-99c1-0f2cf33c9adf",
"as": "default"
},
"use_selection2": {
"use": "d7a5f0c6-de60-4d31-b3e4-5d668a8f7d2e",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\GetBible\\Abstraction.Watcher",
"description": "The GetBible Watcher\r\n\r\n@since 2.0.1",
"licensing_template": "\/**\r\n * @package GetBible\r\n *\r\n * @created 30th May, 2023\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git GetBible <https:\/\/git.vdm.dev\/getBible>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "use Joomla\\CMS\\Date\\Date;",
"composer": ""
}

View File

@ -16,7 +16,6 @@ class App #Gold {
+ getTable(Container $container) : Table
+ getDailyScripture(Container $container) : DailyScripture
+ getSearch(Container $container) : Search
+ getWatcher(Container $container) : Watcher
+ getLoader(Container $container) : Loader
+ getLinker(Container $container) : Linker
+ getNote(Container $container) : Note
@ -60,49 +59,42 @@ note right of App::getSearch
return: Search
end note
note left of App::getWatcher
Get the Watcher class
since: 2.0.1
return: Watcher
end note
note right of App::getLoader
note left of App::getLoader
Get the Loader class
since: 2.0.1
return: Loader
end note
note left of App::getLinker
note right of App::getLinker
Get the Linker class
since: 2.0.1
return: Linker
end note
note right of App::getNote
note left of App::getNote
Get the Note class
since: 2.0.1
return: Note
end note
note left of App::getTag
note right of App::getTag
Get the Tag class
since: 2.0.1
return: Tag
end note
note right of App::getTagged
note left of App::getTagged
Get the Tagged class
since: 2.0.1
return: Tagged
end note
note left of App::getTaggedParagraphs
note right of App::getTaggedParagraphs
Get the Paragraphs class
since: 2.0.1

View File

@ -18,7 +18,6 @@ use VDM\Joomla\GetBible\Config;
use VDM\Joomla\GetBible\Table;
use VDM\Joomla\GetBible\DailyScripture;
use VDM\Joomla\GetBible\Search;
use VDM\Joomla\GetBible\Watcher;
use VDM\Joomla\GetBible\Loader;
use VDM\Joomla\GetBible\Linker;
use VDM\Joomla\GetBible\Note;
@ -56,9 +55,6 @@ class App implements ServiceProviderInterface
$container->alias(Search::class, 'GetBible.Search')
->share('GetBible.Search', [$this, 'getSearch'], true);
$container->alias(Watcher::class, 'GetBible.Watcher')
->share('GetBible.Watcher', [$this, 'getWatcher'], true);
$container->alias(Loader::class, 'GetBible.Loader')
->share('GetBible.Loader', [$this, 'getLoader'], true);
@ -134,27 +130,6 @@ class App implements ServiceProviderInterface
return new Search();
}
/**
* Get the Watcher class
*
* @param Container $container The DI container.
*
* @return Watcher
* @since 2.0.1
*/
public function getWatcher(Container $container): Watcher
{
return new Watcher(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Translations'),
$container->get('GetBible.Api.Books'),
$container->get('GetBible.Api.Chapters'),
$container->get('GetBible.Api.Verses')
);
}
/**
* Get the Loader class
*

View File

@ -20,9 +20,6 @@
$container->alias(Search::class, 'GetBible.Search')
->share('GetBible.Search', [$this, 'getSearch'], true);
$container->alias(Watcher::class, 'GetBible.Watcher')
->share('GetBible.Watcher', [$this, 'getWatcher'], true);
$container->alias(Loader::class, 'GetBible.Loader')
->share('GetBible.Loader', [$this, 'getLoader'], true);
@ -98,27 +95,6 @@
return new Search();
}
/**
* Get the Watcher class
*
* @param Container $container The DI container.
*
* @return Watcher
* @since 2.0.1
*/
public function getWatcher(Container $container): Watcher
{
return new Watcher(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Translations'),
$container->get('GetBible.Api.Books'),
$container->get('GetBible.Api.Chapters'),
$container->get('GetBible.Api.Verses')
);
}
/**
* Get the Loader class
*

View File

@ -29,10 +29,6 @@
"as": "default"
},
"use_selection4": {
"use": "f815fb33-f721-48a5-a84e-53f1986e8881",
"as": "default"
},
"use_selection10": {
"use": "fb5683e2-67ec-413d-96fa-8465fd2f511c",
"as": "default"
},

View File

@ -0,0 +1,67 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# final class Translation (Details)
> namespace: **VDM\Joomla\GetBible\Watcher**
```uml
@startuml
class Translation << (F,LightGreen) >> #Green {
# Translations $translations
+ __construct(Load $load, Insert $insert, ...)
+ sync(string $translation) : bool
- load(string $translation) : bool
- update() : bool
}
note right of Translation::__construct
Constructor
since: 2.0.1
arguments:
Load $load
Insert $insert
Update $update
Translations $translations
end note
note right of Translation::sync
Sync the target being watched
since: 2.0.1
return: bool
end note
note right of Translation::load
Load Translation
since: 2.0.1
return: bool
end note
note right of Translation::update
Trigger the update of all translations
since: 2.0.1
return: bool
end note
@enduml
```
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,187 @@
<?php
/**
* @package GetBible
*
* @created 30th May, 2023
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git GetBible <https://git.vdm.dev/getBible>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\GetBible\Watcher;
use VDM\Joomla\GetBible\Database\Load;
use VDM\Joomla\GetBible\Database\Insert;
use VDM\Joomla\GetBible\Database\Update;
use VDM\Joomla\GetBible\Api\Translations;
use VDM\Joomla\GetBible\Abstraction\Watcher;
/**
* The GetBible Translation Watcher
*
* @since 2.0.1
*/
final class Translation extends Watcher
{
/**
* The Translations class
*
* @var Translations
* @since 2.0.1
*/
protected Translations $translations;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Translations $translations The translations API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Translations $translations)
{
// load the parent constructor
parent::__construct($load, $insert, $update);
$this->translations = $translations;
// set the table
$this->table = 'translation';
}
/**
* Sync the target being watched
*
* @param string $translation The translation.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation): bool
{
// load the target if not found
if ($this->load($translation))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API hash value
$hash = $this->translations->sha($translation);
// confirm hash has not changed
if (hash_equals($hash, $this->target->sha))
{
return $this->bump();
}
if ($this->update())
{
return true;
}
}
return false;
}
/**
* Load Translation
*
* @param string $translation The translation.
*
* @return bool True if translation found
* @since 2.0.1
*/
private function load(string $translation): bool
{
// check local value
if (($this->target = $this->load->item(['abbreviation' => $translation], $this->table)) !== null)
{
return true;
}
// get all the translations
$translations = $this->translations->list();
// check return data
if (!isset($translations->{$translation}) || !isset($translations->{$translation}->sha))
{
return false;
}
// add them to the database
$this->insert->items((array) $translations, 'translation');
if (($this->target = $this->load->item(['abbreviation' => $translation], $this->table)) !== null)
{
$this->fresh = true;
}
return $this->fresh;
}
/**
* Trigger the update of all translations
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(): bool
{
// get translations from the API
if (($translations = $this->translations->list()) === null)
{
return false;
}
// get the local published translations
$local_translations = $this->load->items(['published' => 1], $this->table);
$update = [];
$insert = [];
$match = ['key' => 'abbreviation', 'value' => ''];
// dynamic update all translations
foreach ($translations as $translation)
{
// check if the verse exist
$match['value'] = $translation->abbreviation ?? null;
if (($object = $this->getTarget($match, $local_translations)) !== null)
{
$translation->id = $object->id;
$translation->created = $this->today;
$update[] = $translation;
}
else
{
$insert[] = $translation;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, $this->table);
}
// update the local values
if ($update !== [] && $this->update->items($update, 'id', $this->table))
{
return true;
}
return false;
}
}

View File

@ -0,0 +1,157 @@
/**
* The Translations class
*
* @var Translations
* @since 2.0.1
*/
protected Translations $translations;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Translations $translations The translations API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Translations $translations)
{
// load the parent constructor
parent::__construct($load, $insert, $update);
$this->translations = $translations;
// set the table
$this->table = 'translation';
}
/**
* Sync the target being watched
*
* @param string $translation The translation.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation): bool
{
// load the target if not found
if ($this->load($translation))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API hash value
$hash = $this->translations->sha($translation);
// confirm hash has not changed
if (hash_equals($hash, $this->target->sha))
{
return $this->bump();
}
if ($this->update())
{
return true;
}
}
return false;
}
/**
* Load Translation
*
* @param string $translation The translation.
*
* @return bool True if translation found
* @since 2.0.1
*/
private function load(string $translation): bool
{
// check local value
if (($this->target = $this->load->item(['abbreviation' => $translation], $this->table)) !== null)
{
return true;
}
// get all the translations
$translations = $this->translations->list();
// check return data
if (!isset($translations->{$translation}) || !isset($translations->{$translation}->sha))
{
return false;
}
// add them to the database
$this->insert->items((array) $translations, 'translation');
if (($this->target = $this->load->item(['abbreviation' => $translation], $this->table)) !== null)
{
$this->fresh = true;
}
return $this->fresh;
}
/**
* Trigger the update of all translations
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(): bool
{
// get translations from the API
if (($translations = $this->translations->list()) === null)
{
return false;
}
// get the local published translations
$local_translations = $this->load->items(['published' => 1], $this->table);
$update = [];
$insert = [];
$match = ['key' => 'abbreviation', 'value' => ''];
// dynamic update all translations
foreach ($translations as $translation)
{
// check if the verse exist
$match['value'] = $translation->abbreviation ?? null;
if (($object = $this->getTarget($match, $local_translations)) !== null)
{
$translation->id = $object->id;
$translation->created = $this->today;
$update[] = $translation;
}
else
{
$insert[] = $translation;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, $this->table);
}
// update the local values
if ($update !== [] && $this->update->items($update, 'id', $this->table))
{
return true;
}
return false;
}

View File

@ -0,0 +1,35 @@
{
"add_head": "0",
"add_licensing_template": "2",
"extends": "37e36c41-16a7-4c5d-972c-99acad5fd0b1",
"guid": "7d592acd-f031-4d0f-b667-584c88ae0495",
"implements": null,
"load_selection": null,
"name": "Translation",
"power_version": "1.0.0",
"system_name": "Joomla.GetBible.Watcher.Translation",
"type": "final class",
"use_selection": {
"use_selection0": {
"use": "c03b9c61-17d3-4774-a335-783903719f83",
"as": "default"
},
"use_selection1": {
"use": "a07d90f6-6ff2-40a1-99c1-0f2cf33c9adf",
"as": "default"
},
"use_selection2": {
"use": "d7a5f0c6-de60-4d31-b3e4-5d668a8f7d2e",
"as": "default"
},
"use_selection3": {
"use": "be0cae8b-4b78-4f59-b97b-9e31ee6f52e0",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\GetBible\\Watcher.Translation",
"description": "The GetBible Translation Watcher\r\n\r\n@since 2.0.1",
"licensing_template": "\/**\r\n * @package GetBible\r\n *\r\n * @created 30th May, 2023\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git GetBible <https:\/\/git.vdm.dev\/getBible>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "",
"composer": ""
}

View File

@ -0,0 +1,67 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# final class Book (Details)
> namespace: **VDM\Joomla\GetBible\Watcher**
```uml
@startuml
class Book << (F,LightGreen) >> #Green {
# Books $books
+ __construct(Load $load, Insert $insert, ...)
+ sync(string $translation, int $book) : bool
- load(string $translation, int $book) : bool
- update(string $translation) : bool
}
note right of Book::__construct
Constructor
since: 2.0.1
arguments:
Load $load
Insert $insert
Update $update
Books $books
end note
note right of Book::sync
Sync the target being watched
since: 2.0.1
return: bool
end note
note right of Book::load
Load Book
since: 2.0.1
return: bool
end note
note right of Book::update
Trigger the update of all books of this translation
since: 2.0.1
return: bool
end note
@enduml
```
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,191 @@
<?php
/**
* @package GetBible
*
* @created 30th May, 2023
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git GetBible <https://git.vdm.dev/getBible>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\GetBible\Watcher;
use VDM\Joomla\GetBible\Database\Load;
use VDM\Joomla\GetBible\Database\Insert;
use VDM\Joomla\GetBible\Database\Update;
use VDM\Joomla\GetBible\Api\Books;
use VDM\Joomla\GetBible\Abstraction\Watcher;
/**
* The GetBible Book Watcher
*
* @since 2.0.1
*/
final class Book extends Watcher
{
/**
* The Books class
*
* @var Books
* @since 2.0.1
*/
protected Books $books;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Books $books The books API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Books $books)
{
// load the parent constructor
parent::__construct($load, $insert, $update);
$this->books = $books;
// set the table
$this->table = 'book';
}
/**
* Sync the target being watched
*
* @param string $translation The translation.
* @param int $book The book number.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation, int $book): bool
{
// load the target if not found
if ($this->load($translation, $book))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API hash value
$hash = $this->books->sha($translation, $book);
// confirm hash has not changed
if (hash_equals($hash, $this->target->sha))
{
return $this->bump();
}
if ($this->update($translation))
{
return true;
}
}
return false;
}
/**
* Load Book
*
* @param string $translation The translation.
* @param int $book The book number.
*
* @return bool True if translation found
* @since 2.0.1
*/
private function load(string $translation, int $book): bool
{
// check local value
if (($this->target = $this->load->item(['abbreviation' => $translation, 'nr' => $book], $this->table)) !== null)
{
return true;
}
// get all this translation books
$books = $this->books->list($translation);
// check return data
if (!isset($books->{$book}) || !isset($books->{$book}->sha))
{
return false;
}
// add them to the database
$this->insert->items((array) $books, 'book');
if (($this->target = $this->load->item(['abbreviation' => $translation, 'nr' => $book], $this->table)) !== null)
{
$this->fresh = true;
}
return $this->fresh;
}
/**
* Trigger the update of all books of this translation
*
* @param string $translation The translation.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(string $translation): bool
{
// get translations from the API
if (($books = $this->books->list($translation)) === null)
{
return false;
}
// get the local books
$local_books = $this->load->items(['abbreviation' => $translation], $this->table);
$update = [];
$insert = [];
$match = ['key' => 'nr', 'value' => ''];
// dynamic update all books
foreach ($books as $book)
{
// check if the verse exist
$match['value'] = (int) $book->nr;
if (($object = $this->getTarget($match, $local_books)) !== null)
{
$book->id = $object->id;
$book->created = $this->today;
$update[] = $book;
}
else
{
$insert[] = $book;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, $this->table);
}
// update the local values
if ($update !== [] && $this->update->items($update, 'id', $this->table))
{
return true;
}
return false;
}
}

View File

@ -0,0 +1,161 @@
/**
* The Books class
*
* @var Books
* @since 2.0.1
*/
protected Books $books;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Books $books The books API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Books $books)
{
// load the parent constructor
parent::__construct($load, $insert, $update);
$this->books = $books;
// set the table
$this->table = 'book';
}
/**
* Sync the target being watched
*
* @param string $translation The translation.
* @param int $book The book number.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation, int $book): bool
{
// load the target if not found
if ($this->load($translation, $book))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API hash value
$hash = $this->books->sha($translation, $book);
// confirm hash has not changed
if (hash_equals($hash, $this->target->sha))
{
return $this->bump();
}
if ($this->update($translation))
{
return true;
}
}
return false;
}
/**
* Load Book
*
* @param string $translation The translation.
* @param int $book The book number.
*
* @return bool True if translation found
* @since 2.0.1
*/
private function load(string $translation, int $book): bool
{
// check local value
if (($this->target = $this->load->item(['abbreviation' => $translation, 'nr' => $book], $this->table)) !== null)
{
return true;
}
// get all this translation books
$books = $this->books->list($translation);
// check return data
if (!isset($books->{$book}) || !isset($books->{$book}->sha))
{
return false;
}
// add them to the database
$this->insert->items((array) $books, 'book');
if (($this->target = $this->load->item(['abbreviation' => $translation, 'nr' => $book], $this->table)) !== null)
{
$this->fresh = true;
}
return $this->fresh;
}
/**
* Trigger the update of all books of this translation
*
* @param string $translation The translation.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(string $translation): bool
{
// get translations from the API
if (($books = $this->books->list($translation)) === null)
{
return false;
}
// get the local books
$local_books = $this->load->items(['abbreviation' => $translation], $this->table);
$update = [];
$insert = [];
$match = ['key' => 'nr', 'value' => ''];
// dynamic update all books
foreach ($books as $book)
{
// check if the verse exist
$match['value'] = (int) $book->nr;
if (($object = $this->getTarget($match, $local_books)) !== null)
{
$book->id = $object->id;
$book->created = $this->today;
$update[] = $book;
}
else
{
$insert[] = $book;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, $this->table);
}
// update the local values
if ($update !== [] && $this->update->items($update, 'id', $this->table))
{
return true;
}
return false;
}

View File

@ -0,0 +1,35 @@
{
"add_head": "0",
"add_licensing_template": "2",
"extends": "37e36c41-16a7-4c5d-972c-99acad5fd0b1",
"guid": "c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98",
"implements": null,
"load_selection": null,
"name": "Book",
"power_version": "1.0.0",
"system_name": "Joomla.GetBible.Watcher.Book",
"type": "final class",
"use_selection": {
"use_selection0": {
"use": "c03b9c61-17d3-4774-a335-783903719f83",
"as": "default"
},
"use_selection1": {
"use": "a07d90f6-6ff2-40a1-99c1-0f2cf33c9adf",
"as": "default"
},
"use_selection2": {
"use": "d7a5f0c6-de60-4d31-b3e4-5d668a8f7d2e",
"as": "default"
},
"use_selection3": {
"use": "491c91ce-6355-40d3-bbbd-622473c6c026",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\GetBible\\Watcher.Book",
"description": "The GetBible Book Watcher\r\n\r\n@since 2.0.1",
"licensing_template": "\/**\r\n * @package GetBible\r\n *\r\n * @created 30th May, 2023\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git GetBible <https:\/\/git.vdm.dev\/getBible>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "",
"composer": ""
}

View File

@ -0,0 +1,69 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# class Watcher (Details)
> namespace: **VDM\Joomla\GetBible\Service**
```uml
@startuml
class Watcher #Gold {
+ register(Container $container) : void
+ getWatcher(Container $container) : Watch
+ getTranslation(Container $container) : Translation
+ getBook(Container $container) : Book
+ getChapter(Container $container) : Chapter
}
note right of Watcher::register
Registers the service provider with a DI container.
since: 2.0.1
return: void
end note
note right of Watcher::getWatcher
Get the Watcher class
since: 2.0.1
return: Watch
end note
note right of Watcher::getTranslation
Get the Translation class
since: 2.0.1
return: Translation
end note
note right of Watcher::getBook
Get the Book class
since: 2.0.1
return: Book
end note
note right of Watcher::getChapter
Get the Chapter class
since: 2.0.1
return: Chapter
end note
@enduml
```
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,126 @@
<?php
/**
* @package GetBible
*
* @created 30th May, 2023
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git GetBible <https://git.vdm.dev/getBible>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\GetBible\Service;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use VDM\Joomla\GetBible\Watcher as Watch;
use VDM\Joomla\GetBible\Watcher\Translation;
use VDM\Joomla\GetBible\Watcher\Book;
use VDM\Joomla\GetBible\Watcher\Chapter;
/**
* The GetBible Watcher Service
*
* @since 2.0.1
*/
class Watcher implements ServiceProviderInterface
{
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
* @since 2.0.1
*/
public function register(Container $container)
{
$container->alias(Watch::class, 'GetBible.Watcher')
->share('GetBible.Watcher', [$this, 'getWatcher'], true);
$container->alias(Translation::class, 'GetBible.Watcher.Translation')
->share('GetBible.Watcher.Translation', [$this, 'getTranslation'], true);
$container->alias(Book::class, 'GetBible.Watcher.Book')
->share('GetBible.Watcher.Book', [$this, 'getBook'], true);
$container->alias(Chapter::class, 'GetBible.Watcher.Chapter')
->share('GetBible.Watcher.Chapter', [$this, 'getChapter'], true);
}
/**
* Get the Watcher class
*
* @param Container $container The DI container.
*
* @return Watch
* @since 2.0.1
*/
public function getWatcher(Container $container): Watch
{
return new Watch(
$container->get('GetBible.Load'),
$container->get('GetBible.Watcher.Translation'),
$container->get('GetBible.Watcher.Book'),
$container->get('GetBible.Watcher.Chapter')
);
}
/**
* Get the Translation class
*
* @param Container $container The DI container.
*
* @return Translation
* @since 2.0.1
*/
public function getTranslation(Container $container): Translation
{
return new Translation(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Translations')
);
}
/**
* Get the Book class
*
* @param Container $container The DI container.
*
* @return Book
* @since 2.0.1
*/
public function getBook(Container $container): Book
{
return new Book(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Books')
);
}
/**
* Get the Chapter class
*
* @param Container $container The DI container.
*
* @return Chapter
* @since 2.0.1
*/
public function getChapter(Container $container): Chapter
{
return new Chapter(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Chapters'),
$container->get('GetBible.Api.Verses')
);
}
}

View File

@ -0,0 +1,95 @@
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
* @since 2.0.1
*/
public function register(Container $container)
{
$container->alias(Watch::class, 'GetBible.Watcher')
->share('GetBible.Watcher', [$this, 'getWatcher'], true);
$container->alias(Translation::class, 'GetBible.Watcher.Translation')
->share('GetBible.Watcher.Translation', [$this, 'getTranslation'], true);
$container->alias(Book::class, 'GetBible.Watcher.Book')
->share('GetBible.Watcher.Book', [$this, 'getBook'], true);
$container->alias(Chapter::class, 'GetBible.Watcher.Chapter')
->share('GetBible.Watcher.Chapter', [$this, 'getChapter'], true);
}
/**
* Get the Watcher class
*
* @param Container $container The DI container.
*
* @return Watch
* @since 2.0.1
*/
public function getWatcher(Container $container): Watch
{
return new Watch(
$container->get('GetBible.Load'),
$container->get('GetBible.Watcher.Translation'),
$container->get('GetBible.Watcher.Book'),
$container->get('GetBible.Watcher.Chapter')
);
}
/**
* Get the Translation class
*
* @param Container $container The DI container.
*
* @return Translation
* @since 2.0.1
*/
public function getTranslation(Container $container): Translation
{
return new Translation(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Translations')
);
}
/**
* Get the Book class
*
* @param Container $container The DI container.
*
* @return Book
* @since 2.0.1
*/
public function getBook(Container $container): Book
{
return new Book(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Books')
);
}
/**
* Get the Chapter class
*
* @param Container $container The DI container.
*
* @return Chapter
* @since 2.0.1
*/
public function getChapter(Container $container): Chapter
{
return new Chapter(
$container->get('GetBible.Load'),
$container->get('GetBible.Insert'),
$container->get('GetBible.Update'),
$container->get('GetBible.Api.Chapters'),
$container->get('GetBible.Api.Verses')
);
}

View File

@ -0,0 +1,38 @@
{
"add_head": "1",
"add_licensing_template": "2",
"extends": "0",
"guid": "c5077cd8-b042-4295-99cf-3a5ba2af7dce",
"implements": [
"-1"
],
"load_selection": null,
"name": "Watcher",
"power_version": "1.0.0",
"system_name": "Joomla.GetBible.Service.Watcher",
"type": "class",
"use_selection": {
"use_selection0": {
"use": "f815fb33-f721-48a5-a84e-53f1986e8881",
"as": "Watch"
},
"use_selection1": {
"use": "7d592acd-f031-4d0f-b667-584c88ae0495",
"as": "default"
},
"use_selection2": {
"use": "c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98",
"as": "default"
},
"use_selection3": {
"use": "07d3888a-5f35-4ba7-977f-fb2f5cf99061",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\GetBible\\Service.Watcher",
"description": "The GetBible Watcher Service\r\n\r\n@since 2.0.1",
"implements_custom": "ServiceProviderInterface",
"licensing_template": "\/**\r\n * @package GetBible\r\n *\r\n * @created 30th May, 2023\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git GetBible <https:\/\/git.vdm.dev\/getBible>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "use Joomla\\DI\\Container;\r\nuse Joomla\\DI\\ServiceProviderInterface;",
"composer": ""
}

View File

@ -12,34 +12,20 @@
@startuml
class Watcher << (F,LightGreen) >> #Green {
# Load $load
# Insert $insert
# Update $update
# Translations $translations
# Books $books
# Chapters $chapters
# Verses $verses
# Translation $translation
# Book $book
# Chapter $chapter
# bool $fresh
# string $today
# ?object $verse
+ __construct(Load $load, Insert $insert, ...)
+ __construct(Load $load, Translation $translation, ...)
+ sync(string $translation, int $book, ...) : bool
+ isNew() : bool
+ enoughVerses(string $translation = 'kjv') : bool
+ totalVerses(string $translation = 'kjv') : ?int
+ api(string $translation, int $book, ...) : bool
+ getNextChapter(string $translation, int $book, ...) : ?int
+ getPreviousChapter(int $chapter, bool $force = false) : ?int
+ getLastChapter(string $translation, int $book) : ?int
+ getNextBook(string $translation, int $book, ...) : ?int
+ getPreviousBook(string $translation, int $book, ...) : ?int
- translation(string $translation) : ?string
- book(string $translation, int $book) : ?string
- chapter(string $translation, int $book, ...) : ?string
- verses(string $translation, int $book, ...) : bool
- update(string $translation, int $book, ...) : bool
- getVerse(int $number, array $verses) : ?object
- updateHash(string $translation, int $book, ...) : bool
- hold() : bool
- bump() : bool
}
note right of Watcher::__construct
@ -49,36 +35,12 @@ note right of Watcher::__construct
arguments:
Load $load
Insert $insert
Update $update
Translations $translations
Books $books
Chapters $chapters
Verses $verses
Translation $translation
Book $book
Chapter $chapter
end note
note left of Watcher::isNew
The see if new chapters was installed, and therefore new
since: 2.0.1
return: bool
end note
note right of Watcher::enoughVerses
Check if a translation has enough verses
since: 2.0.1
return: bool
end note
note left of Watcher::totalVerses
Get the total number of verses in the database of a given translation
since: 2.0.1
return: ?int
end note
note right of Watcher::api
note left of Watcher::sync
Watching that the local Database and API is in sync
since: 2.0.1
@ -90,6 +52,27 @@ note right of Watcher::api
int $chapter
end note
note right of Watcher::isNew
The see if new chapters was installed, and therefore new
since: 2.0.1
return: bool
end note
note left of Watcher::enoughVerses
Check if a translation has enough verses
since: 2.0.1
return: bool
end note
note right of Watcher::totalVerses
Get the total number of verses in the database of a given translation
since: 2.0.1
return: ?int
end note
note left of Watcher::getNextChapter
Get the next chapter
@ -141,90 +124,6 @@ note left of Watcher::getPreviousBook
int $try
end note
note right of Watcher::translation
Get Translation Hash Value
since: 2.0.1
return: ?string
end note
note left of Watcher::book
Get Book Hash Value
since: 2.0.1
return: ?string
end note
note right of Watcher::chapter
Get Chapter Hash Value
since: 2.0.1
return: ?string
arguments:
string $translation
int $book
int $chapter
end note
note left of Watcher::verses
Load verses if not in local database
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
end note
note right of Watcher::update
Trigger the update of the verses of a translation-book-chapter
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
end note
note left of Watcher::getVerse
Get a verse text from the API array of verses
since: 2.0.1
return: ?object
end note
note right of Watcher::updateHash
Trigger the update of a chapter hash value
since: 2.0.1
return: bool
arguments:
string $translation
int $book
int $chapter
string $hash
end note
note left of Watcher::hold
Check if its time to match the API hash
since: 2.0.1
return: bool
end note
note right of Watcher::bump
Bump the checking time
since: 2.0.1
return: bool
end note
@enduml
```

View File

@ -12,14 +12,10 @@
namespace VDM\Joomla\GetBible;
use Joomla\CMS\Date\Date;
use VDM\Joomla\GetBible\Database\Load;
use VDM\Joomla\GetBible\Database\Insert;
use VDM\Joomla\GetBible\Database\Update;
use VDM\Joomla\GetBible\Api\Translations;
use VDM\Joomla\GetBible\Api\Books;
use VDM\Joomla\GetBible\Api\Chapters;
use VDM\Joomla\GetBible\Api\Verses;
use VDM\Joomla\GetBible\Watcher\Translation;
use VDM\Joomla\GetBible\Watcher\Book;
use VDM\Joomla\GetBible\Watcher\Chapter;
/**
@ -38,52 +34,28 @@ final class Watcher
protected Load $load;
/**
* The Insert class
* The Translation class
*
* @var Insert
* @var Translation
* @since 2.0.1
*/
protected Insert $insert;
protected Translation $translation;
/**
* The Update class
* The Book class
*
* @var Update
* @var Book
* @since 2.0.1
*/
protected Update $update;
protected Book $book;
/**
* The Translations class
* The Chapter class
*
* @var Translations
* @var Chapter
* @since 2.0.1
*/
protected Translations $translations;
/**
* The Books class
*
* @var Books
* @since 2.0.1
*/
protected Books $books;
/**
* The Chapters class
*
* @var Chapters
* @since 2.0.1
*/
protected Chapters $chapters;
/**
* The Verses class
*
* @var Verses
* @since 2.0.1
*/
protected Verses $verses;
protected Chapter $chapter;
/**
* The fresh load switch
@ -93,54 +65,62 @@ final class Watcher
*/
protected bool $fresh = false;
/**
* The sql date of today
*
* @var string
* @since 2.0.1
*/
protected string $today;
/**
* The target verse
*
* @var object|null
* @since 2.0.1
*/
protected ?object $verse;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Translations $translations The translations API object.
* @param Books $books The books API object.
* @param Chapters $chapters The chapters API object.
* @param Verses $verses The verses API object.
* @param Translation $translation The translations API object.
* @param Book $book The books API object.
* @param Chapter $chapter The chapters API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Translations $translations,
Books $books,
Chapters $chapters,
Verses $verses)
Translation $translation,
Book $book,
Chapter $chapter)
{
$this->load = $load;
$this->insert = $insert;
$this->update = $update;
$this->translations = $translations;
$this->books = $books;
$this->chapters = $chapters;
$this->verses = $verses;
$this->translation = $translation;
$this->book = $book;
$this->chapter = $chapter;
}
// just in-case we set a date
$this->today = (new Date())->toSql();
/**
* Watching that the local Database and API is in sync
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation, int $book, int $chapter): bool
{
// is the translation details in sync
if (!$this->translation->sync($translation))
{
return false;
}
// is the book details in sync
if (!$this->book->sync($translation, $book))
{
return false;
}
// is the chapter and its verses in sync
if (!$this->chapter->sync($translation, $book, $chapter))
{
return false;
}
// if any is new, then this is class should not load any more stuff
$this->fresh = ($this->translation->isNew() || $this->book->isNew() || $this->chapter->isNew());
return true;
}
/**
@ -189,63 +169,6 @@ final class Watcher
);
}
/**
* Watching that the local Database and API is in sync
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
public function api(string $translation, int $book, int $chapter): bool
{
// does the translation exist
if ($this->translation($translation) === null)
{
return false;
}
// does the book exist
if ($this->book($translation, $book) === null)
{
return false;
}
// does the chapter exist, and get hash value
if (($hash = $this->chapter($translation, $book, $chapter)) === null)
{
return false;
}
// load the verses if not found
if ($this->verses($translation, $book, $chapter))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API chapter hash value
$api_hash = $this->chapters->sha($translation, $book, $chapter);
// confirm chapter hash has not changed
if (hash_equals($hash, $api_hash))
{
return $this->bump();
}
if ($this->update($translation, $book, $chapter))
{
// now update the hash of this chapter
return $this->updateHash($translation, $book, $chapter, $api_hash);
}
}
return false;
}
/**
* Get the next chapter
*
@ -393,301 +316,5 @@ final class Watcher
return $this->getPreviousBook($translation, $previous, $try);
}
/**
* Get Translation Hash Value
*
* @param string $translation The translation.
*
* @return string|null The sha of the translation
* @since 2.0.1
*/
private function translation(string $translation): ?string
{
// check local value
if (($translation_sha = $this->load->value(['abbreviation' => $translation], 'sha', 'translation')) !== null)
{
return $translation_sha;
}
// get all the translations
$translations = $this->translations->list();
// check return data
if (!isset($translations->{$translation}) || !isset($translations->{$translation}->sha))
{
return null;
}
// add them to the database
$this->insert->items((array) $translations, 'translation');
return $translations->{$translation}->sha;
}
/**
* Get Book Hash Value
*
* @param string $translation The translation.
* @param int $book The book number.
*
* @return string|null The sha of the book
* @since 2.0.1
*/
private function book(string $translation, int $book): ?string
{
// check local value
if (($book_sha = $this->load->value(['abbreviation' => $translation, 'nr' => $book], 'sha', 'book')) !== null)
{
return $book_sha;
}
// get all the books
$books = $this->books->list($translation);
// check return data
if (!isset($books->{$book}) || !isset($books->{$book}->sha))
{
return null;
}
// add them to the database
$this->insert->items((array) $books, 'book');
return $books->{$book}->sha;
}
/**
* Get Chapter Hash Value
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return string|null The sha of the chapter
* @since 2.0.1
*/
private function chapter(string $translation, int $book, int $chapter): ?string
{
// check local value
if (($chapter_sha = $this->load->value(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'sha', 'chapter'
)) !== null)
{
return $chapter_sha;
}
// get all the books
$chapters = $this->chapters->list($translation, $book);
// check return data
if (!isset($chapters->{$chapter}) || !isset($chapters->{$chapter}->sha))
{
return null;
}
// add them to the database
$this->insert->items((array) $chapters, 'chapter');
return $chapters->{$chapter}->sha;
}
/**
* Load verses if not in local database
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if in local database
* @since 2.0.1
*/
private function verses(string $translation, int $book, int $chapter): bool
{
// check local value
if (($this->verse = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter, 'verse' => 1],
'verse'
)) !== null)
{
return true;
}
// get all the verses
if (($verses = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
// dynamic update all verse objects
$insert = ['book_nr' => $book, 'abbreviation' => $translation];
array_walk($verses->verses, function ($item, $key) use ($insert) {
foreach ($insert as $k => $v) { $item->$k = $v; }
});
$this->fresh = true;
// add them to the database
return $this->insert->items((array) $verses->verses, 'verse');
}
/**
* Trigger the update of the verses of a translation-book-chapter
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(string $translation, int $book, int $chapter): bool
{
// load all the verses from the local database
if (($verses = $this->load->items(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'verse'
)) !== null)
{
// get verses from the API
if (($api = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
$update = [];
$insert = [];
// dynamic update all verse objects
foreach ($api->verses as $verse)
{
// check if the verse exist
if (($object = $this->getVerse((int) $verse->verse, $verses)) !== null)
{
$verse->id = $object->id;
$verse->created = $this->today;
$update[] = $verse;
}
else
{
$insert[] = $verse;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, 'verse');
}
// update the local verses
if ($update !== [] && $this->update->items($update, 'id', 'verse'))
{
return true;
}
}
return false;
}
/**
* Get a verse text from the API array of verses
*
* @param int $number The verse number.
* @param array $verses The api verses
*
* @return object|null The verse string
* @since 2.0.1
*/
private function getVerse(int $number, array &$verses): ?object
{
foreach ($verses as $verse)
{
if ($verse->verse === $number)
{
return $verse;
}
}
return null;
}
/**
* Trigger the update of a chapter hash value
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
* @param string $hash The API chapter hash value.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function updateHash(string $translation, int $book, int $chapter, string $hash): bool
{
// load the chapter
if (($item = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'chapter'
)) !== null)
{
$update = [];
$update['id'] = $item->id;
$update['sha'] = $hash;
$update['created'] = $this->today;
// update the local chapter
return $this->update->row($update, 'id', 'chapter');
}
return false;
}
/**
* Check if its time to match the API hash
*
* @return bool false if its time to check for an update
* @since 2.0.1
*/
private function hold(): bool
{
// Create DateTime objects from the strings
try {
$today = new \DateTime($this->today);
$created = new \DateTime($this->verse->created);
} catch (\Exception $e) {
return false;
}
// Calculate the difference
$interval = $today->diff($created);
// Check if the interval is more than 1 month
if ($interval->m >= 1 || $interval->y >= 1)
{
return false; // More than a month, it's time to check for an update
}
else
{
return true; // Within the last month, hold off on the update check
}
}
/**
* Bump the checking time
*
* @return bool true when the update was a success
* @since 2.0.1
*/
private function bump(): bool
{
$update = [];
$update['id'] = $this->verse->id;
$update['created'] = $this->today;
// update the local verse
return $this->update->row($update, 'id', 'verse');
}
}

View File

@ -7,52 +7,28 @@
protected Load $load;
/**
* The Insert class
* The Translation class
*
* @var Insert
* @var Translation
* @since 2.0.1
*/
protected Insert $insert;
protected Translation $translation;
/**
* The Update class
* The Book class
*
* @var Update
* @var Book
* @since 2.0.1
*/
protected Update $update;
protected Book $book;
/**
* The Translations class
* The Chapter class
*
* @var Translations
* @var Chapter
* @since 2.0.1
*/
protected Translations $translations;
/**
* The Books class
*
* @var Books
* @since 2.0.1
*/
protected Books $books;
/**
* The Chapters class
*
* @var Chapters
* @since 2.0.1
*/
protected Chapters $chapters;
/**
* The Verses class
*
* @var Verses
* @since 2.0.1
*/
protected Verses $verses;
protected Chapter $chapter;
/**
* The fresh load switch
@ -62,54 +38,62 @@
*/
protected bool $fresh = false;
/**
* The sql date of today
*
* @var string
* @since 2.0.1
*/
protected string $today;
/**
* The target verse
*
* @var object|null
* @since 2.0.1
*/
protected ?object $verse;
/**
* Constructor
*
* @param Load $load The load object.
* @param Insert $insert The insert object.
* @param Update $update The update object.
* @param Translations $translations The translations API object.
* @param Books $books The books API object.
* @param Chapters $chapters The chapters API object.
* @param Verses $verses The verses API object.
* @param Translation $translation The translations API object.
* @param Book $book The books API object.
* @param Chapter $chapter The chapters API object.
*
* @since 2.0.1
*/
public function __construct(
Load $load,
Insert $insert,
Update $update,
Translations $translations,
Books $books,
Chapters $chapters,
Verses $verses)
Translation $translation,
Book $book,
Chapter $chapter)
{
$this->load = $load;
$this->insert = $insert;
$this->update = $update;
$this->translations = $translations;
$this->books = $books;
$this->chapters = $chapters;
$this->verses = $verses;
$this->translation = $translation;
$this->book = $book;
$this->chapter = $chapter;
}
// just in-case we set a date
$this->today = (new Date())->toSql();
/**
* Watching that the local Database and API is in sync
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
public function sync(string $translation, int $book, int $chapter): bool
{
// is the translation details in sync
if (!$this->translation->sync($translation))
{
return false;
}
// is the book details in sync
if (!$this->book->sync($translation, $book))
{
return false;
}
// is the chapter and its verses in sync
if (!$this->chapter->sync($translation, $book, $chapter))
{
return false;
}
// if any is new, then this is class should not load any more stuff
$this->fresh = ($this->translation->isNew() || $this->book->isNew() || $this->chapter->isNew());
return true;
}
/**
@ -158,63 +142,6 @@
);
}
/**
* Watching that the local Database and API is in sync
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True on success
* @since 2.0.1
*/
public function api(string $translation, int $book, int $chapter): bool
{
// does the translation exist
if ($this->translation($translation) === null)
{
return false;
}
// does the book exist
if ($this->book($translation, $book) === null)
{
return false;
}
// does the chapter exist, and get hash value
if (($hash = $this->chapter($translation, $book, $chapter)) === null)
{
return false;
}
// load the verses if not found
if ($this->verses($translation, $book, $chapter))
{
if ($this->isNew() || $this->hold())
{
return true;
}
// get API chapter hash value
$api_hash = $this->chapters->sha($translation, $book, $chapter);
// confirm chapter hash has not changed
if (hash_equals($hash, $api_hash))
{
return $this->bump();
}
if ($this->update($translation, $book, $chapter))
{
// now update the hash of this chapter
return $this->updateHash($translation, $book, $chapter, $api_hash);
}
}
return false;
}
/**
* Get the next chapter
*
@ -362,299 +289,3 @@
return $this->getPreviousBook($translation, $previous, $try);
}
/**
* Get Translation Hash Value
*
* @param string $translation The translation.
*
* @return string|null The sha of the translation
* @since 2.0.1
*/
private function translation(string $translation): ?string
{
// check local value
if (($translation_sha = $this->load->value(['abbreviation' => $translation], 'sha', 'translation')) !== null)
{
return $translation_sha;
}
// get all the translations
$translations = $this->translations->list();
// check return data
if (!isset($translations->{$translation}) || !isset($translations->{$translation}->sha))
{
return null;
}
// add them to the database
$this->insert->items((array) $translations, 'translation');
return $translations->{$translation}->sha;
}
/**
* Get Book Hash Value
*
* @param string $translation The translation.
* @param int $book The book number.
*
* @return string|null The sha of the book
* @since 2.0.1
*/
private function book(string $translation, int $book): ?string
{
// check local value
if (($book_sha = $this->load->value(['abbreviation' => $translation, 'nr' => $book], 'sha', 'book')) !== null)
{
return $book_sha;
}
// get all the books
$books = $this->books->list($translation);
// check return data
if (!isset($books->{$book}) || !isset($books->{$book}->sha))
{
return null;
}
// add them to the database
$this->insert->items((array) $books, 'book');
return $books->{$book}->sha;
}
/**
* Get Chapter Hash Value
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return string|null The sha of the chapter
* @since 2.0.1
*/
private function chapter(string $translation, int $book, int $chapter): ?string
{
// check local value
if (($chapter_sha = $this->load->value(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'sha', 'chapter'
)) !== null)
{
return $chapter_sha;
}
// get all the books
$chapters = $this->chapters->list($translation, $book);
// check return data
if (!isset($chapters->{$chapter}) || !isset($chapters->{$chapter}->sha))
{
return null;
}
// add them to the database
$this->insert->items((array) $chapters, 'chapter');
return $chapters->{$chapter}->sha;
}
/**
* Load verses if not in local database
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if in local database
* @since 2.0.1
*/
private function verses(string $translation, int $book, int $chapter): bool
{
// check local value
if (($this->verse = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter, 'verse' => 1],
'verse'
)) !== null)
{
return true;
}
// get all the verses
if (($verses = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
// dynamic update all verse objects
$insert = ['book_nr' => $book, 'abbreviation' => $translation];
array_walk($verses->verses, function ($item, $key) use ($insert) {
foreach ($insert as $k => $v) { $item->$k = $v; }
});
$this->fresh = true;
// add them to the database
return $this->insert->items((array) $verses->verses, 'verse');
}
/**
* Trigger the update of the verses of a translation-book-chapter
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function update(string $translation, int $book, int $chapter): bool
{
// load all the verses from the local database
if (($verses = $this->load->items(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'verse'
)) !== null)
{
// get verses from the API
if (($api = $this->verses->get($translation, $book, $chapter)) === null)
{
return false;
}
$update = [];
$insert = [];
// dynamic update all verse objects
foreach ($api->verses as $verse)
{
// check if the verse exist
if (($object = $this->getVerse((int) $verse->verse, $verses)) !== null)
{
$verse->id = $object->id;
$verse->created = $this->today;
$update[] = $verse;
}
else
{
$insert[] = $verse;
}
}
// check if we have values to insert
if ($insert !== [])
{
$this->insert->items($insert, 'verse');
}
// update the local verses
if ($update !== [] && $this->update->items($update, 'id', 'verse'))
{
return true;
}
}
return false;
}
/**
* Get a verse text from the API array of verses
*
* @param int $number The verse number.
* @param array $verses The api verses
*
* @return object|null The verse string
* @since 2.0.1
*/
private function getVerse(int $number, array &$verses): ?object
{
foreach ($verses as $verse)
{
if ($verse->verse === $number)
{
return $verse;
}
}
return null;
}
/**
* Trigger the update of a chapter hash value
*
* @param string $translation The translation.
* @param int $book The book number.
* @param int $chapter The chapter number.
* @param string $hash The API chapter hash value.
*
* @return bool True if update was a success
* @since 2.0.1
*/
private function updateHash(string $translation, int $book, int $chapter, string $hash): bool
{
// load the chapter
if (($item = $this->load->item(
['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter],
'chapter'
)) !== null)
{
$update = [];
$update['id'] = $item->id;
$update['sha'] = $hash;
$update['created'] = $this->today;
// update the local chapter
return $this->update->row($update, 'id', 'chapter');
}
return false;
}
/**
* Check if its time to match the API hash
*
* @return bool false if its time to check for an update
* @since 2.0.1
*/
private function hold(): bool
{
// Create DateTime objects from the strings
try {
$today = new \DateTime($this->today);
$created = new \DateTime($this->verse->created);
} catch (\Exception $e) {
return false;
}
// Calculate the difference
$interval = $today->diff($created);
// Check if the interval is more than 1 month
if ($interval->m >= 1 || $interval->y >= 1)
{
return false; // More than a month, it's time to check for an update
}
else
{
return true; // Within the last month, hold off on the update check
}
}
/**
* Bump the checking time
*
* @return bool true when the update was a success
* @since 2.0.1
*/
private function bump(): bool
{
$update = [];
$update['id'] = $this->verse->id;
$update['created'] = $this->today;
// update the local verse
return $this->update->row($update, 'id', 'verse');
}

View File

@ -1,5 +1,5 @@
{
"add_head": "1",
"add_head": "0",
"add_licensing_template": "2",
"extends": "0",
"guid": "f815fb33-f721-48a5-a84e-53f1986e8881",
@ -15,33 +15,21 @@
"as": "default"
},
"use_selection1": {
"use": "a07d90f6-6ff2-40a1-99c1-0f2cf33c9adf",
"use": "7d592acd-f031-4d0f-b667-584c88ae0495",
"as": "default"
},
"use_selection2": {
"use": "d7a5f0c6-de60-4d31-b3e4-5d668a8f7d2e",
"use": "c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98",
"as": "default"
},
"use_selection3": {
"use": "be0cae8b-4b78-4f59-b97b-9e31ee6f52e0",
"as": "default"
},
"use_selection4": {
"use": "491c91ce-6355-40d3-bbbd-622473c6c026",
"as": "default"
},
"use_selection5": {
"use": "a752e4b2-9b5e-4188-8d33-3799c46d5119",
"as": "default"
},
"use_selection6": {
"use": "afa508bf-78f8-4616-97cc-f2809584c086",
"use": "07d3888a-5f35-4ba7-977f-fb2f5cf99061",
"as": "default"
}
},
"namespace": "VDM\\Joomla\\GetBible\\Watcher",
"description": "The GetBible Watcher\r\n\r\n@since 2.0.1",
"licensing_template": "\/**\r\n * @package GetBible\r\n *\r\n * @created 30th May, 2023\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git GetBible <https:\/\/git.vdm.dev\/getBible>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "use Joomla\\CMS\\Date\\Date;",
"head": "",
"composer": ""
}

View File

@ -1,4 +1,15 @@
{
"07d3888a-5f35-4ba7-977f-fb2f5cf99061": {
"name": "Chapter",
"type": "final class",
"namespace": "VDM\\Joomla\\GetBible\\Watcher",
"code": "src\/07d3888a-5f35-4ba7-977f-fb2f5cf99061\/code.php",
"power": "src\/07d3888a-5f35-4ba7-977f-fb2f5cf99061\/code.power",
"settings": "src\/07d3888a-5f35-4ba7-977f-fb2f5cf99061\/settings.json",
"path": "src\/07d3888a-5f35-4ba7-977f-fb2f5cf99061",
"spk": "Super__07d3888a_5f35_4ba7_977f_fb2f5cf99061__Power",
"guid": "07d3888a-5f35-4ba7-977f-fb2f5cf99061"
},
"116eb429-bc51-4d14-b9aa-7145c86a29d1": {
"name": "Model",
"type": "class",
@ -65,6 +76,17 @@
"spk": "Super__36ab759f_7b42_4465_9c17_56ba1dd05f90__Power",
"guid": "36ab759f-7b42-4465-9c17-56ba1dd05f90"
},
"37e36c41-16a7-4c5d-972c-99acad5fd0b1": {
"name": "Watcher",
"type": "abstract class",
"namespace": "VDM\\Joomla\\GetBible\\Abstraction",
"code": "src\/37e36c41-16a7-4c5d-972c-99acad5fd0b1\/code.php",
"power": "src\/37e36c41-16a7-4c5d-972c-99acad5fd0b1\/code.power",
"settings": "src\/37e36c41-16a7-4c5d-972c-99acad5fd0b1\/settings.json",
"path": "src\/37e36c41-16a7-4c5d-972c-99acad5fd0b1",
"spk": "Super__37e36c41_16a7_4c5d_972c_99acad5fd0b1__Power",
"guid": "37e36c41-16a7-4c5d-972c-99acad5fd0b1"
},
"3af7864b-f1f3-491e-b16f-0504f890086d": {
"name": "Config",
"type": "class",
@ -186,6 +208,17 @@
"spk": "Super__7b490e63_8d1f_46de_a0c4_154272fd5d7f__Power",
"guid": "7b490e63-8d1f-46de-a0c4-154272fd5d7f"
},
"7d592acd-f031-4d0f-b667-584c88ae0495": {
"name": "Translation",
"type": "final class",
"namespace": "VDM\\Joomla\\GetBible\\Watcher",
"code": "src\/7d592acd-f031-4d0f-b667-584c88ae0495\/code.php",
"power": "src\/7d592acd-f031-4d0f-b667-584c88ae0495\/code.power",
"settings": "src\/7d592acd-f031-4d0f-b667-584c88ae0495\/settings.json",
"path": "src\/7d592acd-f031-4d0f-b667-584c88ae0495",
"spk": "Super__7d592acd_f031_4d0f_b667_584c88ae0495__Power",
"guid": "7d592acd-f031-4d0f-b667-584c88ae0495"
},
"8336e3c4-f11b-41bc-a2b1-976f99442a84": {
"name": "Search",
"type": "final class",
@ -384,6 +417,17 @@
"spk": "Super__c03b9c61_17d3_4774_a335_783903719f83__Power",
"guid": "c03b9c61-17d3-4774-a335-783903719f83"
},
"c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98": {
"name": "Book",
"type": "final class",
"namespace": "VDM\\Joomla\\GetBible\\Watcher",
"code": "src\/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98\/code.php",
"power": "src\/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98\/code.power",
"settings": "src\/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98\/settings.json",
"path": "src\/c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98",
"spk": "Super__c2a8a5fa_8e7f_443a_86d7_a8c1e4cdfa98__Power",
"guid": "c2a8a5fa-8e7f-443a-86d7-a8c1e4cdfa98"
},
"c4098e1a-46dd-4d60-9277-b3668a09edc8": {
"name": "Translation",
"type": "final class",
@ -395,6 +439,17 @@
"spk": "Super__c4098e1a_46dd_4d60_9277_b3668a09edc8__Power",
"guid": "c4098e1a-46dd-4d60-9277-b3668a09edc8"
},
"c5077cd8-b042-4295-99cf-3a5ba2af7dce": {
"name": "Watcher",
"type": "class",
"namespace": "VDM\\Joomla\\GetBible\\Service",
"code": "src\/c5077cd8-b042-4295-99cf-3a5ba2af7dce\/code.php",
"power": "src\/c5077cd8-b042-4295-99cf-3a5ba2af7dce\/code.power",
"settings": "src\/c5077cd8-b042-4295-99cf-3a5ba2af7dce\/settings.json",
"path": "src\/c5077cd8-b042-4295-99cf-3a5ba2af7dce",
"spk": "Super__c5077cd8_b042_4295_99cf_3a5ba2af7dce__Power",
"guid": "c5077cd8-b042-4295-99cf-3a5ba2af7dce"
},
"c99e85a0-d120-4f25-bcbf-0940dd7b773b": {
"name": "Response",
"type": "final class",