BigOrm.php

<?php

namespace Tlf\BigDb\Test;

class BigOrm extends \Tlf\Tester {
    
    protected \Tlf\BigDb $bigdb;
    protected \PDO $pdo;

    public function prepare(){
        $this->pdo = $this->getPdo();
        require_once($this->file('test/input/BigOrm/Article.php'));
        require_once($this->file('test/input/BigOrm/Author.php'));
        require_once($this->file('test/input/BigOrm/Status.php'));
        $this->create_article_table();
    }

    public function finish(){
        $this->pdo->exec("DROP TABLE `article`");
    }

    public function create_article_table(){
        $lilsql = new \Tlf\LilSql();
        $queries = $lilsql->load_files($this->file('test/input/BigOrm'));

        $this->pdo->exec($queries['article.create']);
        // print_r($queries);
        // exit;
    }

    public function pdo(){
        return $this->pdo;
    }
    public function db(){
        return new \Tlf\BigDb($this->pdo());
    }

    // public function test

    /**
     * This was just temporary code, probably don't need it any more.
     */
    public function testBinUuidToString(){
        $this->disable();
        return;
        $pdo = $this->pdo;
        // $pdo = new \PDO('mysql:dbname=DBNAME'.';host=localhost',
            // 'USER','PASSWORD');
        $pdo->exec('create table IF NOT EXISTS `bigdb_test` (`uuid` BINARY(16))');
        $pdo->exec("INSERT INTO `bigdb_test` (`uuid`) VALUES ( UUID_TO_BIN(UUID()) )");

        $stmt = $pdo->prepare("SELECT `uuid`, BIN_TO_UUID(`uuid`) as `uuid_str` FROM `bigdb_test`");
        $stmt->execute();
        $rows = $stmt->fetchAll();

        $row = $rows[0];

        $uuid = bin2hex($row['uuid']);

        var_dump($uuid);
        var_dump($row['uuid_str']);

        // var_export($row);
        // print_r($row);


        $pdo->exec('DROP table IF EXISTS `bigdb_test`');
    }

    public function testFromForm(){
        $article = new \Tlf\BigDb\Test\Article($this->db());
        $article->set_from_form(
            [ 
                'title'=> 'BigOrm from a form!',
                'body' => 'Testing out setting it from a form. <strong>Strong tag should be removed</strong>',
                'author_id' => 31,
                'status' => 'public',
                'slug' => '',
            ],
            'article.create'
        );

        $target_row = 
            [ 
                'title'=> 'BigOrm from a form!',
                'body' => 'Testing out setting it from a form. Strong tag should be removed',
                'author_id' => 31,
                'status' => 'public',
                'slug' => 'bigorm-from-a-form',
                'created_at' => (new \DateTime())->format('Y-m-d H:i:s'),
                'updated_at' => (new \DateTime())->format('Y-m-d H:i:s'),
            ];

        $this->test("set_from_form properly initialized the object.");
        $this->compare_arrays(
            $target_row,
            $article->get_db_row()
        );

        $article->save();

        $this->test("queried object (after save) matches from before save.");

        $article->refresh();
        $actual_row = $article->get_db_row();
        $target_row['id'] = $article->id;
        unset($actual_row['uuid']);
        $this->compare_arrays(
            $target_row,
            $actual_row
        );
        
    }

    public function testDeleteHooks(){
        $article = new \Tlf\BigDb\Test\Article($this->db());
        $article->title = 'BigOrm has delete now!';
        // $article->uuid = '036f9f19-9846-11ed-ba94-ac1f6bbcd39e';
        $article->body = 'Saving is done, and now we have deletion!';
        // $article->createdAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-02 10:18:37');
        // $article->updatedAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-03 11:58:46');
        $article->author = new Author($this->db());
        $article->author->id = 29;
        $article->status = Status::Public;
        $article->slug = 'bigorm-ads-delete';


        $article->delete();
        $this->test("Delete hooks do not get called if item is not already saved. Check that is_deleted and checked_will_delete are both false after calling delete(), but prior to saving");
        //in production, I would use `onDidDelete()` to erase the article content from disk, since I don't use a TEXT column
        //... but I just need a simple test case here, not a good example.
        $this->is_false($article->is_deleted);
        $this->is_false($article->checked_will_delete);

        $article->save();

        $this->test("is_deleted and checked_will_delete are both false after saving");
        $this->is_false($article->is_deleted);
        $this->is_false($article->checked_will_delete);

        $article->delete();

        $this->test("is_deleted and checked_will_delete are both true after deletion");
        $this->is_true($article->is_deleted);
        $this->is_true($article->checked_will_delete);

    }

    public function testSaveHooks(){
        $article = new \Tlf\BigDb\Test\Article($this->db());
        $article->title = 'BigOrm has delete now!';
        // $article->uuid = '036f9f19-9846-11ed-ba94-ac1f6bbcd39e';
        $article->body = 'Saving is done, and now we have deletion!';
        // $article->createdAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-02 10:18:37');
        // $article->updatedAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-03 11:58:46');
        $article->author = new Author($this->db());
        $article->author->id = 29;
        $article->status = Status::Public;
        $article->slug = 'bigorm-ads-delete';


        $this->test("uuid, createdAt & updatedAt are NOT set");
        $this->is_false(isset($article->createdAt));
        $this->is_false(isset($article->updatedAt));

        $article->save();
        // NOTE: uuid is set during onWillSave().
        // NOTE: createdAt and updatedAt are set during onDidSave(), simply by calling `refresh()`

        $this->test("createdAt & updatedAt are set and are DateTime instances");
        $this->is_true(isset($article->createdAt));
        $this->is_true(isset($article->updatedAt));
        $this->is_true($article->createdAt instanceof \DateTime);
        $this->is_true($article->updatedAt instanceof \DateTime);

        $this->test("uuid is set & is 36 characters");
        $this->is_true(isset($article->uuid));
        $this->is_true(strlen($article->uuid)==36);

    }

    public function testDeleteItem(){
        $article = new \Tlf\BigDb\Test\Article($this->db());
        $article->title = 'BigOrm has delete now!';
        $article->uuid = '036f9f19-9846-11ed-ba94-ac1f6bbcd39e';
        $article->body = 'Saving is done, and now we have deletion!';
        $article->createdAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-02 10:18:37');
        $article->updatedAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-03 11:58:46');
        $article->author = new Author($this->db());
        $article->author->id = 29;
        $article->status = Status::Public;
        $article->slug = 'bigorm-ads-delete';

        $article->save();
        $id = $article->id;

        $this->test("Article correctly saved.");
        $this->is_true($article->is_saved());
        $this->compare_arrays(
            $this->dbSelectById($this->pdo, 'article', $id),
            $article->get_db_row()
        );

        $article->delete();

        $this->test("Article successfully deleted (db row is empty).");

        $this->compare_arrays(
            [],
            $this->dbQuery($this->pdo, 'SELECT * FROM article WHERE id='.$id),
        );
    }

    public function testSaveItem(){
        $article = new \Tlf\BigDb\Test\Article($this->db());
        $article->title = 'BigOrm is getting there';
        $article->uuid = '036f9f19-9846-11ed-ba94-ac1f6bbcd39e';
        $article->body = 'BigOrm is being developed, thoughfully and thoroughly. It will be done eventually.';
        $article->createdAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-02 10:18:37');
        $article->updatedAt = \DateTime::createFromFormat('Y-m-d H:i:s', '2023-06-03 11:58:46');
        $article->author = new Author($this->db());
        $article->author->id = 29;
        $article->status = Status::Public;
        $article->slug = 'bigorm-getting-there';

        $this->test('storeable row is correct');
        $this->compare_arrays(
            $saveable_target = [ 
                'title'=>'BigOrm is getting there',
                'uuid'=> $article->uuid_to_bin('036f9f19-9846-11ed-ba94-ac1f6bbcd39e'),
                'body'=>'BigOrm is being developed, thoughfully and thoroughly. It will be done eventually.',
                'created_at'=>'2023-06-02 10:18:37',
                'updated_at'=>'2023-06-03 11:58:46',
                'author_id' => 29,
                'status' => 'public',
                'slug' => 'bigorm-getting-there'

            ],
            $article->get_db_row()
        );

        $article->save();
        $id = $article->id;

        // $rows = $this->dbQuery($this->pdo, 'SELECT * FROM article');
        // print_r($rows);

        $row = $this->dbSelectById($this->pdo, 'article', $id);

        $this->test("INSERT: Loaded id matches the id generated during save()");
        $this->compare($article->id, $row['id']);

        $this->test("INSERT: Loaded row matches saved row");
        unset($row['id']);
        $this->compare_arrays(
            $saveable_target,
            $row
        );

        $article->title = $new_title = 'BigOrm is still needs hooks';
        $article->slug = $new_slug = 'bigorm-needs-hooks';

        $article->save();

        $update_target_row = $saveable_target;
        $update_target_row['title'] = $new_title;
        $update_target_row['slug'] = $new_slug;
        $update_target_row['id'] = $id;


        $db_row = $this->dbSelectById($this->pdo, 'article', $id);

        $this->test("UPDATE: id is unchanged");
        $this->compare($id, $article->id);
        $this->compare($id, $db_row['id']);

        $this->test("UPDATE: Item is updated in the database");
        $this->compare_arrays($update_target_row, $article->get_db_row());
        $this->compare_arrays($update_target_row, $db_row);

    }

    public function testConvertToDbRow(){
        // I think $article NEEDS a bigDb instance.
        $article = new \Tlf\BigDb\Test\Article($this->db());
        /** set_from_db() is for setting from a database representation of the row */
        $article->set_from_db(
            $row = [ 
                'title'=>'BigOrm is under development',
                'uuid'=> $article->uuid_to_bin('036f9f19-9846-11ed-ba94-ac1f6bbcd39e'), // (binary uuid, as would be in the db)
                'body'=>'BigDb is a library simplifying database access. BigOrm is the lowest-level component representing a single item. BigOrm is under development. [and it would go on]',
                'created_at' => '2023-05-12 12:05:24',
                'updated_at' => '2023-05-12 13:15:36',
                'author_id' => 27,
                'status'=>'public',
                'slug'=>'bigorm-in-development',
            ]
        );

        $db_row = $article->get_db_row();

        $this->test("Storeable row");
        $this->compare_arrays(
            $row,
            $db_row
        );
    }

    /**
     * Test setting article props from a db row and using the dynamic properties
     */
    public function testSetFromDb(){
        // I think $article NEEDS a bigDb instance.
        $article = new \Tlf\BigDb\Test\Article($this->db());
        /** set_from_db() is for setting from a database representation of the row */
        $article->set_from_db(
            $row = [ 
                'title'=>'BigOrm is under development',
                'uuid'=> $article->uuid_to_bin('036f9f19-9846-11ed-ba94-ac1f6bbcd39e'), // (binary uuid, as would be in the db)
                'body'=>'BigDb is a library simplifying database access. BigOrm is the lowest-level component representing a single item. BigOrm is under development. [and it would go on]',
                'created_at' => '2023-05-12 12:05:24',
                'updated_at' => '2023-05-12 13:15:36',
                'author_id' => 27,
                'status'=>'public',
                'slug'=>'bigorm-in-development',
            ]
        );

        $this->test('Title, no changes');
        $this->compare(
            $row['title'],
            $article->title
        );

        $this->test("url: uses 'slug'");
        $this->compare(
            '/article/'.$row['slug'].'/',
            $article->url
        );

        $this->test("created_at:createdAt, Datetime");
        $this->compare(
            'May 12, 2023 1:15pm',
            $article->updatedAt->format('M d, Y g:ia')
        );

        $this->test("UUID bin-to-string");
        $this->compare(
            '036f9f19-9846-11ed-ba94-ac1f6bbcd39e',
            $article->uuid,
        );

        $this->test("status enum");
        $this->compare(
            $row['status'],
            $article->status->value
        );

        $this->test("Prop getter");
        $this->compare(
            $row['author_id'],
            $article->author->id,
        );
    }

}