FormsTest.php

<?php

namespace Phad\Test\Integration;

/**
 * This class appears to test both form compilation and form submission
 *
 * @notice Several of these tests incidentally test the submit target/redirect feature.
 */
class Forms extends \Phad\Tester {

    protected array $blogTableColumns = ['id'=>'INTEGER PRIMARY KEY','title'=>'VARCHAR(200)', 'body'=>'VARCHAR(2000)'];

    public function testDeleteItem(){
        $lildb = \Tlf\LilDb::sqlite();
        $pdo = $lildb->pdo();
        $phad = $this->phad();
        $phad->pdo = $pdo;
        $lildb->create('blog',['id'=>'integer', 'title'=>'varchar(90)']);
        $lildb->insert('blog',['id'=>1,'title'=>'title 1']);
        $lildb->insert('blog',['id'=>2,'title'=>'title 2']);
        $lildb->insert('blog',['id'=>3,'title'=>'title 3']);


        $form = new \Phad\View('Form/Deleteable', $this->file('test/input/views/'), 
            ['id'=>2, 'phad'=>$phad]);
        $form->force_compile = true;
        $form->delete();

        $blogs = $lildb->select('blog');
        $this->compare(
            [ ['id'=>1,'title'=>'title 1'],
              ['id'=>3,'title'=>'title 3'],
            ],
            $blogs
        );

    }

    public function testErrorMessage(){
        $pdo = $this->getPdo();
        $phad = $this->phad();
        $phad->pdo = $pdo;
        $view = $phad->view('Form/SimpleBlogWithError');

        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

        $BlogRow = ['body'=>'smol body', 'title'=>''];

        $out = $view->submit($BlogRow);
        
        $msg = $phad->validationErrorMessage($phad->failed_submit_columns);
        $this->test('Error Message Written');
            $this->str_not_contains($out, ['<error>','</error>']);
            $this->str_contains($out, '<div class="my-error-class">'.$msg.'</div>');

        $this->test('Headers empty');
            $this->compare(
                [],
                $phad->getHeaders(),
            );
    }

    public function testSubmitDocumentation(){
        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

        $ldb = \Tlf\LilDb::sqlite();
        $pdo = $ldb->pdo();
        
        $ldb->create('blog', $this->blogTableColumns);

        $phad = $this->phad();
        $phad->pdo = $pdo;
        $view = $phad->view('Form/SimpleBlogNoTarget');

        //if `id` were set, an UPDATE would be done instead.
        $BlogRow = ['title'=>'Fine Title', 'body'=>'I have to be at least 50 characters. But that isn\'t very long.'];
        $out = $view->submit($BlogRow);
        $BlogRow['id'] = $pdo->lastInsertId();

        $headers = $phad->getHeaders();
        //you can foreach(as $h){ header(...$h) }
        //@export_end(Forms.ManualSubmission)

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Inserted');
            $this->compare(
                [$BlogRow],
                $ldb->query('SELECT * FROM blog')
            );
    }

    public function testControllerOnSubmitDocumentation(){
        $phad = new class() extends \Phad {
            public function onSubmit($ItemData, &$ItemRow){
                if ($ItemData->name!='Blog')return true;
                $ItemRow['slug'] = str_replace(' ', '-', strtolower($ItemRow['title']));
                return true;
            }
        };
        $pdo = $this->getPdo();
        $phad = $this->phad($phad);
        $phad->pdo = $pdo;
        $phad->target_url = '/blog/{slug}/{id}/';
        $cols = $this->blogTableColumns;
        $cols['slug'] = 'VARCHAR(100)';
        $this->createTable($pdo, 'blog', $cols);

        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

 
        $BlogRow = 
            [
            'title'=>'Fine Title', 
            'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'
            ];
        /** anonymous class to use as our controller */
        /** passing our custom controller & submitting manually */
        $view = $phad->view('Form/SimpleBlogNoTarget');
        /** $BlogRow is just an array with 'title' & 'body' **/
        $output = $view->submit($BlogRow);
        
        $BlogRow['id'] = $pdo->lastInsertId();
        $BlogRow['slug'] = 'fine-title';

        $this->test('There should be no output');
            $this->handleDidPass(strlen(trim($output))===0);

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/blog/fine-title/'.$BlogRow['id'].'/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Inserted');
            $this->compare(
                $BlogRow,
                $this->queryOne($pdo, 'SELECT * FROM blog'),
            );
    }

    public function testWithInlineOnSubmit(){
        $pdo = $this->getPdo();
        $phad = $this->phad();
        $phad->pdo = $pdo;
        $phad->target_url = '/blog/{slug}/{id}/';
        $cols = $this->blogTableColumns;
        $cols['slug'] = 'VARCHAR(100)';
        $this->createTable($pdo, 'blog', $cols);

        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

 
        $BlogRow = 
            [
            'title'=>'Fine Title', 
            'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'
            ];

        $view = $phad->view('Form/BlogWithOnSubmit');
        $output = $view->submit($BlogRow);
        
        $BlogRow['id'] = $pdo->lastInsertId();
        $BlogRow['slug'] = 'fine-title';

        $this->test('Backend Prop is removed');
            $this->str_not_contains($phad->view('Form/BlogWithOnSubmit', $BlogRow), 'type="backend"');

        $this->test('<onsubmit> tag was removed');
            $this->str_not_contains($phad->view('Form/BlogWithOnSubmit', $BlogRow), '<onsubmit>');

        $this->test('There should be no output');
            $this->handleDidPass(strlen(trim($output))===0);

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/blog/fine-title/'.$BlogRow['id'].'/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Inserted');
            $this->compare(
                $BlogRow,
                $this->queryOne($pdo, 'SELECT * FROM blog'),
            );
    }
    public function testInsertWithValidOption(){
        $pdo = $this->getPdo();
        $phad = $this->phad();
        $phad->pdo = $pdo;
        $view = $phad->view('Form/BlogWithCategories');
        $cols = $this->blogTableColumns;
        $cols['category'] = 'VARCHAR(100)';
        $this->createTable($pdo, 'blog', $cols);

        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

        $BlogRow = ['title'=>'Police Brutality super sucks', 'body'=>'Its been well documented that police brutality is a reality, yet there\'s still overwhelming controversy about what we should do with our society. Some say: Let the police to what they gotta do. Others say: Lets rethink this society that\'s built upon punishing people who misbehave & actually help people instead. Mayb ewe could redirect some of the MASSIVE tax dollars that go to police departments to actually help someone. That\'s me. I say that. - Reed',
            'category'=>'Police Brutality'];

        $out = $view->submit($BlogRow);
        
        $BlogRow['id'] = $pdo->lastInsertId();

        $this->test('There should be no output');
            $this->handleDidPass(strlen(trim($out))===0);

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/blog/'.$BlogRow['title'].'/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Inserted');
            $this->compare(
                $BlogRow,
                $this->queryOne($pdo, 'SELECT * FROM blog'),
            );
    }

    public function testUpdateRedirectsToTarget(){
        // $phad = $this->phad();
        $pdo = $this->getPdo();
        // $phad->pdo = $pdo;
        $this->createTable($pdo, 'blog', $this->blogTableColumns);

        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

        
        $phad = new class() extends \Phad {
            public function t(){
                echo "\ntttttttttttttttt\n";
            }
            public function objectFromRow($ItemData, $BlogRow){
                $Blog = (object)$BlogRow;
                $Blog->slug = str_replace(' ', '-', strtolower($Blog->title));
                return $Blog;
            }
        };
        $phad = $this->phad($phad);
        $phad->target_url = '/blog/{slug}/{id}/';
        $phad->pdo = $pdo;

        $view = $phad->view('Form/SimpleBlogNoTarget', ['phad'=>$phad]);

        $BlogRow = 
            [
            'title'=>'Fine Title', 
            'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'
            ];

        $out = $view->submit($BlogRow);
        
        $BlogRow['id'] = $pdo->lastInsertId();

        $this->test('There should be no output');
            $this->handleDidPass(strlen(trim($out))===0);

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/blog/fine-title/'.$BlogRow['id'].'/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Inserted');
            $this->compare(
                $BlogRow,
                $this->queryOne($pdo, 'SELECT * FROM blog'),
            );
    }

    public function testUpdateValid(){
        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';
        $ldb = \Tlf\LilDb::sqlite();
        $phad = $this->phad();
        $phad->pdo = $ldb->pdo();
        $view = $phad->view('Form/SimpleBlog');
        $ldb->create('blog', $this->blogTableColumns);

        $BlogRow = ['id'=>0, 'title'=>'Fine Title', 'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'];
        $ldb->insert('blog', $BlogRow);
        $UpdatedBlog = $BlogRow;
        $UpdatedBlog['title'] = 'New Title';



        $out = $view->submit($UpdatedBlog);

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/blog/'.$UpdatedBlog['title'].'/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Updated');
            $this->compare(
                [$UpdatedBlog],
                $ldb->query('SELECT * FROM blog')
            );
        
        $this->test('No Output Present');
            $this->compare(
                '',
                trim($out)
            );
    }

    public function testInsertValid(){
        $phad = $this->phad();
        $phad->pdo = $this->getPdo();
        $view = $phad->view('Form/SimpleBlog');
        $this->createTable($phad->pdo, 'blog', $this->blogTableColumns);

        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['HTTPS'] = 'non-empty-value';

        $BlogRow = ['title'=>'Fine Title', 'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'];

        $out = $view->submit($BlogRow);
        
        $BlogRow['id'] = $phad->pdo->lastInsertId();

        $this->test('There should be no output');
            $this->handleDidPass(strlen(trim($out))===0);

        $this->test('Headers');
            $this->compare(
                [['Location: https://localhost/blog/'.$BlogRow['title'].'/', true]],
                $phad->getHeaders(),
            );

        $this->test('Data Was Inserted');
            $this->compare(
                $BlogRow,
                $this->queryOne($phad->pdo, 'SELECT * FROM blog'),
            );
    }

    /**
     * @test that a partially filled in form is returned when submission fails.
     */
    public function testSubmitInvalid(){
        $phad = $this->phad();
        $phad->force_compile = false;
        $this->createTable($phad->pdo, 'blog', $this->blogTableColumns);

        // View contains: 
        // <textarea name="body" maxlength="2000" minlength="50"></textarea>
        $view = $phad->view('Form/SimpleBlog');


        // should fail because body is less than 50 chars
        $Blog = ['title'=>'Fine Title', 'body'=>'body too short'];
        $out = $view->submit($Blog);
        $Blog = (object)$Blog;


        echo $out;
        
        $this->test('Form cleaned up');
            $this->str_not_contains($view, ['item=']);

        $this->test('Submitted Blog Content');
            $this->str_contains($out, 'value="'.$Blog->title.'"');
            $this->str_contains($out, '>'.$Blog->body.'</textarea>');
    }

    public function testDisplayWithNoObject(){
        $view = $this->view('Form/SimpleBlog');

        $Blog = ['title'=>'Fine Title', 'body'=>'body too short'];
        $out = $view->outputWithEmptyObject($Blog);
        $Blog = (object)$Blog;

        
        echo $out;

        $this->test('Form cleaned up');
            $this->str_not_contains($out, ['item=']);
        $this->test('Target Attribute Removed');
            $this->str_not_contains($out, 'target="');

        $this->test('Submitted Blog Content');
            $this->str_contains($out, 'value=""');
            $this->str_contains($out, '></textarea>');

    }

    /**
     * @test getting each selectable-option from a form's compiled view
     */
    public function testHasSelectOptions(){
        $view = $this->view('Form/BlogWithCategories');
        $ItemData = $view->getItemData();

        $expect = [
            'title' => 
            [
                'type' => 'text',
                'maxlength' => '75',
                'tagName' => 'input',
            ],
            'body' => 
            [
                'maxlength' => '2000',
                'minlength' => '50',
                'tagName' => 'textarea',
            ],
            'category'=>
            [
                'tagName'=> 'select',
                'options'=>[
                    "social-justice",
                    "policy",
                    "Police Brutality",
                    "Election",
                ],
            ],
            'id'=>
            [
                'tagName'=>'input',
                'type'=>'hidden',
            ]
        ];
        $this->compare($expect, $ItemData->properties);
    }

    /**
     * @test getting info about properties from the compiled view.
     */
    public function testHasPropertiesData(){
        $view = $this->view('Form/SimpleBlog');
        $ItemData = $view->getItemData();

        $expect = [
            'title' => 
            [
                'type' => 'text',
                'maxlength' => '75',
                'tagName' => 'input',
            ],
            'body' => 
            [
                'maxlength' => '2000',
                'minlength' => '50',
                'tagName' => 'textarea',
            ],
            'id'=>
            [
                'tagName'=>'input',
                'type'=>'hidden',
            ]
        ];
        $this->compare($expect, $ItemData->properties);
    }
}