foreachelse

I always missed the foreachelse function I used in smarty-templates, so I created a ViewRenderer that handles this.

My regex skills are very bad, so if someone has a better solution, feel free to share the changes you’ve made here.

Usage example:




<div class="blogs">

	<h1>Blogs</h1>

	<? foreach ($blogs as $blog) : ?>

		<?= $this->renderPartial('_item', compact('blog')); ?>

	<? foreachelse ?>

		There aren't any blogs yet <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />

	<? endforeach; ?>

</div>



Becomes: (note, I also implemented a PHP shorthand tag replacement)




<div class="blogs">

	<h1>Blogs</h1>

	<?php if(count($blogs) > 0) foreach($blogs as $blog){ ?>

		<?php echo $this->renderPartial('_item', compact('blog')); ?>

	<?php  } else { ?>

		There aren't any blogs yet <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />

	<?php  }  ?>

</div>



Viewrenderer: (see http://www.yiiframework.com/doc/guide/topics.prado how to implement)




<?php


	class ViewRenderer extends CViewRenderer {


		private $_input;

		private $_output;

		private $_sourceFile;


		/**

		 * Parses the source view file and saves the results as another file.

		 * This method is required by the parent class.

		 * @param string the source view file path

		 * @param string the resulting view file path

		 */

		protected function generateViewFile($sourceFile, $viewFile) {

			static $regexRules = array(

				'<\?=*[^x]\s*', // PHP shorthand

				'foreach?\s*\(\s*(.*?)\s(.*?)\)?\s*[{:]', // foreach

				'foreachelse?\s*[{:]*', // foreachelse

				'endforeach;', // foreachelse

				);


			$this->_sourceFile = $sourceFile;

			$this->_input = file_get_contents($sourceFile);

			$n = preg_match_all('/'.implode('|', $regexRules).'/msS', $this->_input, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);

			$textStart = 0;


			$this->_output = '';


			for ($i = 0; $i < $n; ++$i) {

				$match =& $matches[$i];

				$str = $match[0][0];

				$matchStart = $match[0][1];

				$matchEnd = $matchStart + strlen($str) - 1;


				if ($matchStart > $textStart)

					$this->_output .= substr($this->_input, $textStart, $matchStart - $textStart);

				$textStart = $matchEnd + 1;


				if (strpos($str, '<?=') === 0) // expression

					$this->_output .= '<?php echo '.$match[1][0];

				else if (strpos($str, '<?') === 0) // statement

					$this->_output .= '<?php '.$match[1][0];

				else if (strpos($str, 'foreachelse') === 0)

					$this->_output .= ' } else { ';

				else if (strpos($str, 'endforeach') === 0)

					$this->_output .= ' } ';

				else if (strpos($str, 'foreach') === 0)

					$this->_output .= 'if(count('.$match[1][0].') > 0) foreach('.$match[1][0].' '.$match[2][0].'){';

			}

			if ($textStart < strlen($this->_input))

				$this->_output .= substr($this->_input, $textStart);


			//echo $this->_output; exit; //debug

			file_put_contents($viewFile, $this->_output);

		}


	}