diff --git a/src/View.php b/src/View.php index 74affd9..a74da97 100644 --- a/src/View.php +++ b/src/View.php @@ -3,7 +3,9 @@ namespace yii1tech\mailer; use CFileHelper; +use CMap; use Yii; +use yii1tech\mailer\widgets\ClipWidget; /** * View is a email template view renderer. @@ -14,6 +16,7 @@ * * @property string $viewPath the root directory of view files. Defaults to 'views/mail' under the application base path. * @property \IViewRenderer|\CViewRenderer|array|string|null|false $viewRenderer view renderer or its array configuration. + * @property \CMap $clips The list of clips. * * @author Paul Klimov * @since 1.0 @@ -38,6 +41,12 @@ class View extends \CBaseController */ private $_viewRenderer; + /** + * @var \CMap|null list of clips. + * @see \CClipWidget + */ + private $_clips; + /** * @return string the root directory of view files. Defaults to 'views/mail' under the application base path. */ @@ -178,6 +187,8 @@ public function render(string $view, ?array $data = null, ?string $locale = null $content = $this->renderPartial($this->layout, ['content' => $content], true); } } catch (\Throwable $e) { + throw $e; + } finally { while (ob_get_level() > $obInitialLevel) { if (!@ob_end_clean()) { ob_clean(); @@ -185,14 +196,10 @@ public function render(string $view, ?array $data = null, ?string $locale = null } $this->layout = $originalLayout; + $this->_clips = null; Yii::app()->setLanguage($originalLocale); - - throw $e; } - $this->layout = $originalLayout; - Yii::app()->setLanguage($originalLocale); - return $content; } @@ -220,4 +227,44 @@ public function renderPartial(string $view, ?array $data = null, bool $return = return $this->renderFile($viewFile, $data, $return); } + + /** + * Returns the list of clips. + * A clip is a named piece of rendering result that can be inserted at different places. + * + * @see \yii1tech\mailer\widgets\ClipWidget + * + * @return \CMap the list of clips + */ + public function getClips(): CMap + { + if ($this->_clips === null) { + $this->_clips = new CMap(); + } + + return $this->_clips; + } + + /** + * Begins recording a clip. + * This method is a shortcut to beginning {@see \yii1tech\mailer\widgets\ClipWidget}. + * + * @param string $id the clip ID. + * @param array $properties initial property values for {@see \yii1tech\mailer\widgets\ClipWidget}. + */ + public function beginClip($id, $properties = []): void + { + $properties['id'] = $id; + $properties['view'] = $this; + $this->beginWidget(ClipWidget::class, $properties); + } + + /** + * Ends recording a clip. + * This method is an alias to {@see endWidget()}. + */ + public function endClip(): void + { + $this->endWidget(ClipWidget::class); + } } \ No newline at end of file diff --git a/src/widgets/ClipWidget.php b/src/widgets/ClipWidget.php new file mode 100644 index 0000000..a7078b9 --- /dev/null +++ b/src/widgets/ClipWidget.php @@ -0,0 +1,52 @@ + + * @since 1.0 + */ +class ClipWidget extends CWidget +{ + /** + * @var \CBaseController|\yii1tech\mailer\View view, which renders this widget. + */ + public $view; + + /** + * @var bool whether to render the clip content in place. Defaults to false, + * meaning the captured clip will not be displayed. + */ + public $renderClip = false; + + /** + * Starts recording a clip. + */ + public function init() + { + ob_start(); + ob_implicit_flush(false); + } + + /** + * Ends recording a clip. + * This method stops output buffering and saves the rendering result as a named clip in the controller. + */ + public function run() + { + $clip = ob_get_clean(); + if ($this->renderClip) { + echo $clip; + } + + $this->view->getClips()->add($this->getId(), $clip); + } +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index 064e1fd..6c1d445 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -32,7 +32,7 @@ protected function tearDown(): void * @param array $config The application configuration, if needed * @param string $appClass name of the application class to create */ - protected function mockApplication($config = [], $appClass = CConsoleApplication::class) + protected function mockApplication($config = [], $appClass = \CWebApplication::class) { Yii::setApplication(null); diff --git a/tests/ViewTest.php b/tests/ViewTest.php index 389e54e..35c3a47 100644 --- a/tests/ViewTest.php +++ b/tests/ViewTest.php @@ -69,8 +69,10 @@ public function testRestoreOrigins(): void $this->assertStringContainsString('Locale = ru', $content); $this->assertStringContainsString('', $content); $this->assertStringContainsString('', $content); + $this->assertStringContainsString('Clip = Test Clip Content', $content); $this->assertSame('default-layout', $view->layout); $this->assertSame('en_us', Yii::app()->getLanguage()); + $this->assertCount(0, $view->getClips()); } } \ No newline at end of file diff --git a/tests/views/mail/layout.php b/tests/views/mail/layout.php index c69b2dd..06c1fe3 100644 --- a/tests/views/mail/layout.php +++ b/tests/views/mail/layout.php @@ -1,3 +1,9 @@ + +Clip = getClips()->itemAt('test-clip') ?> diff --git a/tests/views/mail/switch.php b/tests/views/mail/switch.php index ff089cb..1116c2e 100644 --- a/tests/views/mail/switch.php +++ b/tests/views/mail/switch.php @@ -8,4 +8,7 @@ Test switch mail template Name = Locale = getLanguage(); ?> +beginClip('test-clip'); ?> +Test Clip Content +endClip(); ?>