Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
54 / 54
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
Seeder
100.00% covered (success)
100.00%
54 / 54
100.00% covered (success)
100.00%
2 / 2
21
100.00% covered (success)
100.00%
1 / 1
 create
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 run
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
1 / 1
18
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Db\Sql;
16
17use Pop\Db\Adapter\AbstractAdapter;
18use Pop\Db\Db;
19
20/**
21 * Sql seeder class
22 *
23 * @category   Pop
24 * @package    Pop\Db
25 * @author     Nick Sagona, III <nick@popphp.org>
26 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
27 * @license    https://www.popphp.org/license     New BSD License
28 * @version    7.0.0
29 */
30class Seeder
31{
32
33    /**
34     * Create new migration file
35     *
36     * @param  string  $class
37     * @param  ?string $path
38     * @throws Exception
39     * @return string
40     */
41    public static function create(string $class, ?string $path = null): string
42    {
43        $file          = date('YmdHis') . '_' . Parser\Table::parse($class) . '.php';
44        $classContents = str_replace(
45            'SeederTemplate', $class, file_get_contents(__DIR__ . '/Seeder/Template/SeederTemplate.php')
46        );
47
48        if ($path !== null) {
49            if (!is_dir($path)) {
50                throw new Exception('Error: That path does not exist');
51            }
52            $file = $path . DIRECTORY_SEPARATOR . $file;
53        }
54
55        file_put_contents($file, $classContents);
56
57        return $file;
58    }
59
60    /**
61     * Run the seeder
62     *
63     * @param  AbstractAdapter $db
64     * @param  string          $path
65     * @param  bool            $clear
66     * @return array
67     *@throws Exception|\Pop\Db\Exception
68     */
69    public static function run(AbstractAdapter $db, string $path, bool $clear = true): array
70    {
71        if (!file_exists($path)) {
72            throw new Exception("Error: That path doesn't not exist.");
73        }
74
75        // Clear the database out
76        if ($clear) {
77            $schema = $db->createSchema();
78            $tables = $db->getTables();
79
80            // The tables are dropped one statement at a time, so the schema object has to be
81            // cleared between them - rendering it does not clear it.
82            if (($db instanceof \Pop\Db\Adapter\Mysql) ||
83                (($db instanceof \Pop\Db\Adapter\Pdo) && ($db->getType() == 'mysql'))) {
84                $db->query('SET foreign_key_checks = 0');
85                foreach ($tables as $table) {
86                    $schema->drop($table);
87                    $db->query($schema);
88                    $schema->reset();
89                }
90                $db->query('SET foreign_key_checks = 1');
91            } else if (($db instanceof \Pop\Db\Adapter\Pgsql) ||
92                (($db instanceof \Pop\Db\Adapter\Pdo) && ($db->getType() == 'pgsql'))) {
93                foreach ($tables as $table) {
94                    $schema->drop($table)->cascade();
95                    $db->query($schema);
96                    $schema->reset();
97                }
98            } else {
99                foreach ($tables as $table) {
100                    $schema->drop($table);
101                    $db->query($schema);
102                    $schema->reset();
103                }
104            }
105        }
106
107        $seedFilesRun = [];
108        $seedFiles    = array_filter(scandir($path), function($value) {
109            return (($value != '.') && ($value != '..'));
110        });
111
112        // Run the SQL seeds
113        foreach ($seedFiles as $seed) {
114            if (stripos($seed, '.sql') !== false) {
115                Db::executeSqlFile($path . DIRECTORY_SEPARATOR . $seed, $db);
116            } else {
117                $fileContents = trim(file_get_contents($path . DIRECTORY_SEPARATOR . $seed));
118                if ((str_contains($fileContents, 'extends AbstractSeeder'))) {
119                    $namespace = null;
120                    if (str_contains($fileContents, 'namespace ')) {
121                        $namespace = substr($fileContents, (strpos($fileContents, 'namespace ') + 10));
122                        $namespace = trim(substr($namespace, 0, strpos($namespace, ';'))) . '\\';
123                    }
124                    $class = substr($fileContents, (strpos($fileContents, 'class ') + 6));
125                    $class = $namespace . substr($class, 0, strpos($class, ' extends'));
126
127                    include_once $path . DIRECTORY_SEPARATOR . $seed;
128                    $dbSeed = new $class();
129                    if ($dbSeed instanceof Seeder\SeederInterface) {
130                        $dbSeed->run($db);
131                    }
132                }
133            }
134            $seedFilesRun[] = $seed;
135        }
136
137        return $seedFilesRun;
138    }
139
140}