Question

I'm a little bit baffled by this, so I'm hoping someone can shed some light on it for me.

I have a function which is meant to return a column Status from one of my tables, visit.

function someFunction($visitId = null) {
  $visit = VisitQuery::create()
    ->select(array('Status'))
    ->findPk($visitId);
}

If I var_dump($visit), when calling the function for the first time, it outputs:

string '1' (length=1)

Subsequent, identical calls to the function however seem to return an entire object:

object(Visit)[30]
  protected 'startCopy' => boolean false
  protected 'id' => int 362
  protected 'job_id' => int 351
  protected 'company_id' => int 2
  protected 'type_id' => int 1
  protected 'visit_date' => string '2013-08-23 00:00:00' (length=19)
  protected 'status' => string '1' (length=1)
  ...

I'm calling the function for the first time with an (int) $visitId passed via a posted form:

var_dump($visitId); // int 362

Subsequent calls are made with an (int) $visitId which is returned from another function, saveVisit() (which uses Propel to save the record - I believe this may have something to do with it).

$visitId = saveVisit($visitId);
var_dump($visitId); // int 362

I tried to do some debugging, and for some reason the query issued to MySQL is different between the first function call and subsequent ones:

var_dump($con->getLastExecutedQuery());

SELECT visit.STATUS AS "Status" FROM `visit` WHERE visit.ID=362 // 1st call
SELECT `ID`, `JOB_ID`, `COMPANY_ID`, `TYPE_ID`, `VISIT_DATE`, `STATUS`, `REMIND`, `PRINTED` FROM `visit` WHERE `ID` = 362 // 2nd call
SELECT `ID`, `JOB_ID`, `COMPANY_ID`, `TYPE_ID`, `VISIT_DATE`, `STATUS`, `REMIND`, `PRINTED` FROM `visit` WHERE `ID` = 362 // 3rd call

Can anyone tell me why or how this is happening?

I'm using Propel 1.6.


Propel's create() method:

public static function create($modelAlias = null, $criteria = null)
{
    if ($criteria instanceof VisitQuery) {
        return $criteria;
    }
    $query = new VisitQuery();
    if (null !== $modelAlias) {
        $query->setModelAlias($modelAlias);
    }
    if ($criteria instanceof Criteria) {
        $query->mergeWith($criteria);
    }

    return $query;
}

Propel's findPk() method:

public function findPk($key, $con = null)
{
    if ($con === null) {
        $con = Propel::getConnection($this->getDbName(), Propel::CONNECTION_READ);
    }
    // As the query uses a PK condition, no limit(1) is necessary.
    $this->basePreSelect($con);
    $criteria = $this->isKeepQuery() ? clone $this : $this;
    $pkCols = $this->getTableMap()->getPrimaryKeyColumns();
    if (count($pkCols) == 1) {
        // simple primary key
        $pkCol = $pkCols[0];
        $criteria->add($pkCol->getFullyQualifiedName(), $key);
    } else {
        // composite primary key
        foreach ($pkCols as $pkCol) {
            $keyPart = array_shift($key);
            $criteria->add($pkCol->getFullyQualifiedName(), $keyPart);
        }
    }
    $stmt = $criteria->doSelect($con);

    return $criteria->getFormatter()->init($criteria)->formatOne($stmt);
}

My function to retrieve the visit status:

function getVisitStatus($visitId = null) {
  if (empty($visitId)) {
    return false;
  }
  try {
    $visit = VisitQuery::create()
      ->select(array('Status'))
      ->findPk($visitId);
  } catch (Exception $e) {
    echo $e->getMessage(); exit;
  }
  if (is_null($visit)) {
    return false;
  }
  return $visit;
}

The function which saves a visit record:

function saveVisit($data = null) {  
  if (empty($data)) {
    return false; 
  }     
  try {     
    $visit = (!empty($data['visit_id'])) ? VisitQuery::create()->findPk($data['visit_id']) : new Visit();   
    if (!is_object($visit)) {
      return false;
    }

    $visitDataMap = array(
      'JobId'  => 'job_id',
      'TypeId'  => 'type_id',
      'VisitDate'  => 'visit_date',
      'Status' => 'status',
      'CompanyId' => 'engineer_id',
      'Remind'  => 'remind'
    );  

    $visitData = array();
    foreach ($visitDataMap as $column => $value) {
      if (!empty($data[$value])) {
        $visitData[$column] = $data[$value];
      }
    }   
    $visit->fromArray($visitData);
    $visit->save();
    return $visit->getId(); 
  } catch (PropelException $e) { 
    echo $e->getMessage(); exit; 
  }
}
Était-ce utile?

La solution

It seems that on the first call will grab your data but then put a copy of the full object in to the instance pool. I am not sure if this is a bug or valid behaviour (your code would suggest the former, but I'd love to hear from someone who knows more about Propel such as a dev) but you can stop it happening with:

VisitPeer::clearInstancePool();

Bear in mind you're losing a bit of caching from other queries you might have done here with the visit relation.

You will be able to confirm this by adding an echo in the BaseVisitPeer.php file. You will see something like this:

public static function getInstanceFromPool($key)
{
    if (Propel::isInstancePoolingEnabled()) {
        if (isset(VisitPeer::$instances[$key])) {
            return VisitPeer::$instances[$key];
        }
    }

    return null; // just to be explicit
}

If you add an echo somewhere inside the if (isset(VisitPeer::$instances[$key])) { statement, you should see it appear only after the second and subsequent calls. If you were to comment this whole if statement out then you would get the same result back each time - the one you correctly get back from your original call.

Hope that helps!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top