<?php
abstract class ModelCriteriaObjectPathExtension extends ModelCriteria
{
  /**
   * This method allows to join this model with the relations mentioned in the 
   * provided objectPath. 
   * 
   * An ObjectPath is a recursive path of relation-names, separated by dots, 
   * E.G. when you have a BookReview-ModelCriteria an objectPath to the author 
   * of the reviewed book will be: Book.Author
   * 
   * @param     string $objectPaths  an objectPath (or optionally an array of objectPaths)
   * @param     TableMap $currentTableMap the currentTableMap, required if not equal to $this->getTableMap
   * @return    string
   */
  public function joinByObjectPath($objectPaths, TableMap $currentTableMap = null)
  {
    if (!$currentTableMap)
    {
      $currentTableMap = $this->getTableMap();
    }

    // convert to array, if not already
    if (!is_array($objectPaths))
    {
      $objectPaths = array($objectPaths);
    }

    // process all objectPaths
    foreach ($objectPaths as $objectPath)
    {
      // get first (two) elements from the objectPath
      $parts = explode('.', $objectPath, 2);

      // resolve the (first) relationName
      if (count($parts)<1)
      {
        throw new PropelException('joinByObjectPath expects objectPaths with at least one object.relation-pair');
      }
      $relationName = $parts[0];

      // resolve related ClassName from relation from Current
      $relatedTable = $this->getRelatedTableFromRelationName($relationName, $currentTableMap);
      $relatedClass = $relatedTable->getPhpName();
      $joinType     = $this->getJoinTypeFromRelationName($relationName, $currentTableMap);

      // build relation string
      $relation = $currentTableMap->getPhpName().'.'.$relatedClass.' '.$relationName;

      // similiar to joinWith, except this does not add selectColumns multiple times
      if (!array_key_exists($relationName, $this->joins))
      {
        $this->join($relation, $joinType);
        end($this->joins);
        
        $this->with($relationName);
      }

      // continue (recursively) parsing the objectPath if more relations are provided
      if (isset($parts[1]))
      {
        $this->joinByObjectPath($parts[1], $relatedTable);
      }
    }

    return $this;
  }

  /**
   * Resolves the RelatedTable for a given RelationName
   *
   * @param     string $relationName      the relationName from the currentTableMap
   * @param     TableMap $currentTableMap the currentTableMap, required if not equal to $this->getTableMap
   * @return    TableMap
   */
  public function getRelatedTableFromRelationName($relationName, TableMap $currentTableMap = null)
  {
    if (!$currentTableMap)
    {
      $currentTableMap = $this->getTableMap();
    }

    return $currentTableMap->getRelation($relationName)->getRightTable();
  }
}