3 namespace OpenEMR\Tests\Fixtures
;
5 use OpenEMR\Common\Database\QueryUtils
;
6 use OpenEMR\Common\Database\SqlQueryException
;
7 use OpenEMR\Common\Logging\SystemLogger
;
8 use OpenEMR\Common\Uuid\UuidRegistry
;
9 use OpenEMR\Services\Search\SearchQueryFragment
;
13 * Provides OpenEMR Fixtures/Sample Records to test cases as Objects or Database Records.
16 * @link http://www.open-emr.org
17 * @author Yash Bothra <yashrajbothra786gmail.com>
18 * @copyright Copyright (c) 2020 Yash Bothra <yashrajbothra786gmail.com>
19 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
21 abstract class BaseFixtureManager
23 // use a prefix so we can easily remove fixtures
24 const FIXTURE_PREFIX
= "test-fixture";
28 private $hasInstalledFixtured;
31 public function __construct($fileName = "", $tableName = "")
33 $this->fileName
= $fileName;
34 $this->tableName
= $tableName;
35 $this->hasInstalledFixtured
= false;
38 protected function getFixturesFromFile()
40 if (empty($this->fixtures
)) {
41 $this->fixtures
= $this->loadJsonFile($this->fileName
);
43 return $this->fixtures
;
47 * Loads a JSON fixture from a file within the Fixture namespace, returning the data as an array of records.
48 * @param $fileName The file name to load.
49 * @return array of records.
51 protected function loadJsonFile($fileName)
53 $filePath = dirname(__FILE__
) . "/" . $fileName;
54 $jsonData = file_get_contents($filePath);
55 $parsedRecords = json_decode($jsonData, true);
56 return $parsedRecords;
61 * This will return a recorded uuid (recorded in uuid_registry)
63 * @param $tableName The target OpenEMR DB table name.
66 protected function getUuid($tableName)
68 return (new UuidRegistry(['table_name' => $tableName]))->createUuid();
72 * @return the next available id/identifier in the table.
74 protected function getNextId($tableName, $idField)
76 $idQuery = "SELECT IFNULL(MAX($idField), 0) + 1 FROM $tableName";
77 $idResult = sqlQueryNoLog($idQuery);
78 $idValue = intval(array_values($idResult)[0]);
83 * Returns an unregistered/unlogged UUID for use in testing fixtures
84 * @return uuid4 string value
86 public function getUnregisteredUuid()
88 return UuidRegistry
::uuidToString((new UuidRegistry(['disable_tracker' => true]))->createUuid());
92 * Installs fixtures into the OpenEMR DB.
94 * @param $tableName The target OpenEMR DB table name.
95 * @param $fixtures Array of fixture objects to install.
96 * @return the number of fixtures installed.
98 protected function installFixturesForTable($tableName, $fixtures)
101 $sqlInsert = "INSERT INTO " . escape_table_name($tableName) . " SET ";
103 foreach ($fixtures as $index => $fixture) {
104 $sqlColumnValues = "";
107 foreach ($fixture as $field => $fieldValue) {
108 if (is_array($fieldValue) && $this->isForeignReference($fieldValue)) {
109 $fragment = $this->getQueryForForeignReference($fieldValue);
110 $sqlColumnValues .= $field . " = " . $fragment->getFragment() . ", ";
111 $sqlBinds = array_merge($sqlBinds, $fragment->getBoundValues());
112 } else if ($this->isFunctionCall($fieldValue)) {
113 $sqlColumnValues .= $field . " = ?, ";
114 $fieldValue = $this->getValueFromFunction($fieldValue);
115 array_push($sqlBinds, $fieldValue);
117 $sqlColumnValues .= $field . " = ?, ";
118 array_push($sqlBinds, $fieldValue);
121 $sqlColumnValues = rtrim($sqlColumnValues, " ,");
122 $isInserted = QueryUtils
::sqlInsert($sqlInsert . $sqlColumnValues, $sqlBinds);
130 public function installFixtures()
132 $fixtures = $this->getFixturesFromFile();
133 $insertCount = $this->installFixturesForTable($this->tableName
, $fixtures);
134 $this->hasInstalledFixtured
= true;
138 // we don't have a good way to solve this so we will force all sub classes to implement.
139 public function removeFixtures()
141 // we have no generic way of signifying what the primary key of the table is so we force sub classes
142 // to implement the remove fixture method
143 $this->removeInstalledFixtures();
144 $this->hasInstalledFixtured
= false;
147 public function hasInstalledFixtures()
149 return $this->hasInstalledFixtured
;
153 * @return a random fixture.
155 public function getSingleFixture()
157 $fixtures = $this->getFixturesFromFile();
158 return $this->getSingleEntry($fixtures);
161 abstract protected function removeInstalledFixtures();
163 private function getValueFromFunction($value)
165 $functionName = strtok($value, "()");
167 // white list our functions here
168 if ($functionName === "uuid") {
169 $table = strtok("(,)");
170 if ($table !== false) {
171 // trim spaces, and quotes
172 $table = trim($table, "'\" \t\n\r\0\x0B");
173 return $this->getUuid($table);
175 throw new \
BadMethodCallException("uuid(table_name) function is missing table name");
177 } else if ($functionName === "generateId") {
178 return QueryUtils
::generateId();
180 throw new \
BadMethodCallException("Function could not be interpreted from fixture: " . $value);
182 return ""; // return empty string
185 private function isFunctionCall($value)
187 return preg_match("/[a-zA-Z]+\(['a-zA-Z_0-9\-]*\)/", $value) === 1;
190 private function isForeignReference(array $reference)
192 return isset($reference['table']) && isset($reference['columnSearch']) && isset($reference['columnSearchValue']) && isset($reference['columnReference']);
195 private function getQueryForForeignReference(array $reference): SearchQueryFragment
198 $table_name = escape_table_name($reference['table']);
199 $column = escape_sql_column_name($reference['columnSearch'], [$reference['table']], false, true);
200 $referenceColumn = escape_sql_column_name($reference['columnReference'], [$reference['table']], false, true);
201 $searchValue = $reference['columnSearchValue'];
202 $sql = "( SELECT $referenceColumn FROM $table_name WHERE $column = ? )";
203 } catch (SqlQueryException
$exception) {
204 (new SystemLogger())->error("Failed to escape column for foreign key reference ", ['reference' => $reference]);
207 return new SearchQueryFragment($sql, [$reference['columnSearchValue']]);
211 * @return random single entry from an array.
213 protected function getSingleEntry($array)
216 throw new \
InvalidArgumentException("cannot get single entry from empty array");
218 $randomIndex = array_rand($array, 1);
219 return $array[$randomIndex];