Merge pull request #22669 from agileware/CIVICRM-1921
[civicrm-core.git] / CRM / Core / DAO.php
index 3e4dcba6d2d148fbd5cacd87684df53a626cb0ee..5eab8615f8dc1615136da8866f195648faff4b0c 100644 (file)
@@ -693,7 +693,8 @@ class CRM_Core_DAO extends DB_DataObject {
    *             we will build the condition only using the whereAdd's.  Default is to
    *             build the condition only using the object parameters.
    *
-   *     * @return mixed Int (No. of rows affected) on success, false on failure, 0 on no data affected
+   * @return int|false
+   *   Int (No. of rows affected) on success, false on failure, 0 on no data affected
    */
   public function delete($useWhere = FALSE) {
     $preEvent = new \Civi\Core\DAO\Event\PreDelete($this);
@@ -917,10 +918,14 @@ class CRM_Core_DAO extends DB_DataObject {
     $entityName = CRM_Core_DAO_AllCoreTables::getBriefName($className);
 
     \CRM_Utils_Hook::pre($op, $entityName, $record['id'] ?? NULL, $record);
-    $instance = new $className();
+    $fields = static::getSupportedFields();
+    $instance = new static();
     // Ensure fields exist before attempting to write to them
-    $values = array_intersect_key($record, self::getSupportedFields());
+    $values = array_intersect_key($record, $fields);
     $instance->copyValues($values);
+    if (empty($values['id']) && array_key_exists('name', $fields) && empty($values['name']) && !empty($values['label'])) {
+      $instance->makeNameFromLabel();
+    }
     $instance->save();
 
     if (!empty($record['custom']) && is_array($record['custom'])) {
@@ -1495,14 +1500,13 @@ LIKE %1
    * @param string $daoName
    *   Name of the dao object.
    * @param array $params
-   *   (reference ) an assoc array of name/value pairs.
+   *   (reference) an assoc array of name/value pairs.
    * @param array $defaults
-   *   (reference ) an assoc array to hold the flattened values.
+   *   (reference) an assoc array to hold the flattened values.
    * @param array $returnProperities
    *   An assoc array of fields that need to be returned, eg array( 'first_name', 'last_name').
    *
-   * @return object
-   *   an object of type referenced by daoName
+   * @return static|null
    */
   public static function commonRetrieve($daoName, &$params, &$defaults, $returnProperities = NULL) {
     $object = new $daoName();
@@ -1524,12 +1528,15 @@ LIKE %1
   /**
    * Delete the object records that are associated with this contact.
    *
+   * @deprecated
+   *
    * @param string $daoName
    *   Name of the dao object.
    * @param int $contactId
    *   Id of the contact to delete.
    */
   public static function deleteEntityContact($daoName, $contactId) {
+    CRM_Core_Error::deprecatedFunctionWarning('APIv4');
     $object = new $daoName();
 
     $object->entity_table = 'civicrm_contact';
@@ -3278,4 +3285,44 @@ SELECT contact_id
     return static::$_paths ?? [];
   }
 
+  /**
+   * When creating a record without a supplied name,
+   * create a unique, clean name derived from the label.
+   *
+   * Note: this function does nothing unless a unique index exists for "name" column.
+   */
+  private function makeNameFromLabel() {
+    $indexNameWith = NULL;
+    // Look for a unique index which includes the "name" field
+    if (method_exists($this, 'indices')) {
+      foreach ($this->indices(FALSE) as $index) {
+        if (!empty($index['unique']) && in_array('name', $index['field'], TRUE)) {
+          $indexNameWith = $index['field'];
+        }
+      }
+    }
+    if (!$indexNameWith) {
+      // No unique index on "name", do nothing
+      return;
+    }
+    $name = CRM_Utils_String::munge($this->label, '_', 252);
+
+    // Find existing records with the same name
+    $sql = new CRM_Utils_SQL_Select($this::getTableName());
+    $sql->select(['id', 'name']);
+    $sql->where('name LIKE @name', ['@name' => $name . '%']);
+    // Include all fields that are part of the index
+    foreach (array_diff($indexNameWith, ['name']) as $field) {
+      $sql->where("`$field` = @val", ['@val' => $this->$field]);
+    }
+    $query = $sql->toSQL();
+    $existing = self::executeQuery($query)->fetchMap('id', 'name');
+    $dupes = 0;
+    $suffix = '';
+    while (in_array($name . $suffix, $existing)) {
+      $suffix = '_' . (++$dupes);
+    }
+    $this->name = $name . $suffix;
+  }
+
 }