: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
namespace NinjaForms\Includes\Database;
use NinjaForms\Includes\Contracts\SubmissionDataSource as ContractsSubmissionDataSource;
use NinjaForms\Includes\Entities\SingleSubmission;
use NinjaForms\Includes\Entities\SubmissionFilter;
use Caldera_Forms_Entry_Update;
use Caldera_Forms_Entry_Bulk;
* Retrieves a single Caldera Forms submission by its entry id
class CalderaSubmissionDataSource implements ContractsSubmissionDataSource
const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
* Identifier of where submission is stored
protected $dataSource = 'cf_form_entries';
* Collection of submissions keyed on Submission Record Id
* @var SingleSubmission[]
protected $submissionCollection = [];
/** @var SubmissionFilter */
protected $submissionFilter;
* Cross reference from NF Form Id to the CF form Id
* ex: '174' => 'CF60b547cfac102'
protected $formIdLookup = [];
public function retrieveSubmissionMeta(SubmissionFilter $submissionFilter): array
$this->submissionFilter = $submissionFilter;
if ([] !== $this->submissionFilter->getNfFormIds()) {
$formIdCollection = $this->submissionFilter->getNfFormIds();
$this->formId = $formIdCollection[0];
foreach ($formIdCollection as $nfFormId) {
$this->lookupCfFormIdByNfFormId($nfFormId);
if (!\is_null($this->formIdLookup[$nfFormId])) {
$this->retrieveSubmissionMetaByCfFormId($this->formIdLookup[$nfFormId]);
if(''!==$this->submissionFilter->getSearchString()){
$this->applySearchCriterion();
return $this->submissionCollection;
public function retrieveSingleSubmission(SingleSubmission $singleSubmission): SingleSubmission{
$submissionRecordId = $singleSubmission->getSubmissionRecordId();
// Initialize submission collection b/c retrievals only happen on submissions in collection
$this->submissionCollection[$submissionRecordId]=$singleSubmission;
$singleSubmission = $this->retrieveSubmissionValues($singleSubmission);
return $singleSubmission;
* Apply search string filter to submission collection
* Runs a WP Query to search for all post Ids with both a form Id from the
* submission filter and also a search string in any meta value of the same
* form. It then filters the submission collection to only those
* submissions that meet these additional requirements.
protected function applySearchCriterion(): void
$entriesTable = $wpdb->prefix . 'cf_form_entries';
$valuesTable = $wpdb->prefix . 'cf_form_entry_values';
$searchString = '%'.$this->submissionFilter->getSearchString() .'%';
/** @var array $searchCollection Array of submission Ids that match both form Id and search criterion */
foreach ($this->submissionFilter->getNfFormIds() as $nfFormId) {
if (\is_null($this->formIdLookup[$nfFormId])) {
$cfFormId = $this->formIdLookup[$nfFormId];
$searchResultIds = $wpdb->get_results(
INNER JOIN $valuesTable ON
($entriesTable.id = $valuesTable.entry_id)
$entriesTable.form_id = '%s' AND $valuesTable.value LIKE '%s'
$submissionIds = \array_column($searchResultIds, 'id');
$searchCollection = array_merge($searchCollection,$submissionIds);
$this->submissionCollection = \array_intersect_key($this->submissionCollection, \array_flip($searchCollection));
* Adds CF lookup for given NF form id
* If given NF id lookup is not set, checks to see if there is a
* corresponding CF form. If not, the value is set to `null` so that
* the instance knows that the form id has been checked.
* @param string $nfFormId
protected function lookupCfFormIdByNfFormId(string $nfFormId): void
if(isset($this->formIdLookup[$nfFormId])){
$form =Ninja_Forms()->form( $nfFormId )->get();
$cfFormId= $form->get_setting('key',null);
$this->formIdLookup[$nfFormId]=$cfFormId;
public function retrieveSubmissionValues(SingleSubmission $singleSubmission): SingleSubmission
$submissionRecordId = $singleSubmission->getSubmissionRecordId();
$table = $wpdb->prefix . 'cf_form_entry_values';
$r = $wpdb->get_results($wpdb->prepare("SELECT `slug`,`value` FROM $table WHERE `entry_id` = '%s'", $submissionRecordId), ARRAY_A);
$cfSub = array_combine(array_column($r, 'slug'), array_column($r, 'value'));
$updatedFieldValueCollection = [];
foreach ($singleSubmission->getSubmissionFieldCollection() as $fieldSlug => $submissionField) {
$value = isset($cfSub[$fieldSlug]) ? $cfSub[$fieldSlug] : null;
$submissionField->setValue($value);
$updatedFieldValueCollection[$fieldSlug] = $submissionField;
$singleSubmission->setSubmissionFieldCollection($updatedFieldValueCollection);
// only populate collection if submission is already present
if (isset($this->submissionCollection[$submissionRecordId])) {
$this->submissionCollection[$submissionRecordId] = $singleSubmission;
return $singleSubmission;
public function deleteSubmission(SingleSubmission $singleSubmission): ContractsSubmissionDataSource
$submissionId = $singleSubmission->getSubmissionRecordId();
$entry = Caldera_Forms::get_entry_detail( $submissionId );
if($entry['status'] === "active"){
Caldera_Forms_Entry_Update::update_entry_status( "trash", $submissionId);
Caldera_Forms_Entry_Bulk::delete_entries([$submissionId]);
public function restoreSubmission(SingleSubmission $singleSubmission): ContractsSubmissionDataSource
$submissionId = $singleSubmission->getSubmissionRecordId();
Caldera_Forms_Entry_Update::update_entry_status( "active", $submissionId);
public function updateSubmission(SingleSubmission $singleSubmission): ContractsSubmissionDataSource
// @TODO: Use CF API to delete submission
* Retrieve submissions for a given CF form Id
protected function retrieveSubmissionMetaByCfFormId(string $formId): void
$submissionRecordIdQuery = "select * from " . $wpdb->prefix . "cf_form_entries posts where form_id=%s";
$userId = $this->submissionFilter->getUserId();
// Filter on post author as submitter's user id
if (!\is_null($userId)) {
$submissionRecordIdQuery .= " AND user_id = %d";
$recordCollection = $wpdb->get_results($wpdb->prepare($submissionRecordIdQuery, $args));
$statuses = $this->submissionFilter->getStatus();
foreach ($recordCollection as $queryObject) {
if( empty($statuses) || in_array( $queryObject->status, $statuses ) ){
$submissionRecordId = $queryObject->id;
$subDate = $queryObject->datestamp;
$status = $queryObject->status;
$submitterId = $queryObject->user_id;
$include = $this->includeByDateFilter($subDate);
$this->submissionCollection[$submissionRecordId] = SingleSubmission::fromArray([
'submissionRecordId' => $submissionRecordId,
'dataSource' => $this->dataSource,
'submitterId' => $submitterId
* Boolean to include as per date filter
* true=>include, false=>omit
protected function includeByDateFilter($subDate): bool
$startDateUnix = $this->submissionFilter->getStartDate();
$startDate = (new \DateTime())->setTimestamp($startDateUnix)->format(self::TIMESTAMP_FORMAT);
$endDateUnix = $this->submissionFilter->getEndDate();
$endDate = (new \DateTime())->setTimestamp($endDateUnix)->format(self::TIMESTAMP_FORMAT);
if ('' !== $startDate && $subDate < $startDate) {
if ('' !== $endDate && $subDate > $endDate) {
public function getDataSource(): string
return $this->dataSource;