예제 #1
0
 /**
  * Render paste top button. Returns null if no button should be rendered.
  *
  * @param string $sorting The sorting mode.
  *
  * @return string
  */
 protected function renderPasteTopButton($sorting)
 {
     $definition = $this->getEnvironment()->getDataDefinition();
     $dispatcher = $this->getEnvironment()->getEventDispatcher();
     $basicDefinition = $definition->getBasicDefinition();
     $clipboard = $this->getEnvironment()->getClipboard();
     $filter = new Filter();
     $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
     if ($sorting && $clipboard->isNotEmpty($filter)) {
         $allowPasteTop = ViewHelpers::getManualSortingProperty($this->environment);
         if ($allowPasteTop) {
             /** @var AddToUrlEvent $urlEvent */
             $urlEvent = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent('act=paste&after=' . IdSerializer::fromValues($definition->getName(), 0)->getSerialized()));
             /** @var GenerateHtmlEvent $imageEvent */
             $imageEvent = $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, new GenerateHtmlEvent('pasteafter.gif', $this->translate('pasteafter.0', $definition->getName()), 'class="blink"'));
             return sprintf('<a href="%s" title="%s" onclick="Backend.getScrollOffset()">%s</a>', $urlEvent->getUrl(), specialchars($this->translate('pasteafter.0', $definition->getName())), $imageEvent->getHtml());
         }
     }
     return null;
 }
 /**
  * Fetch actions from the clipboard.
  *
  * @param FilterInterface|null $filter        The clipboard filter.
  * @param ModelIdInterface     $parentModelId The parent id.
  *
  * @return array
  */
 private function fetchModelsFromClipboard(FilterInterface $filter = null, ModelIdInterface $parentModelId = null)
 {
     $environment = $this->getEnvironment();
     $dataDefinition = $environment->getDataDefinition();
     if (!$filter) {
         $filter = new Filter();
     }
     $basicDefinition = $dataDefinition->getBasicDefinition();
     $modelProviderName = $basicDefinition->getDataProvider();
     $filter->andModelIsFromProvider($modelProviderName);
     if ($parentModelId) {
         $filter->andParentIsFromProvider($parentModelId->getDataProviderName());
     } else {
         $filter->andHasNoParent();
     }
     $environment = $this->getEnvironment();
     $clipboard = $environment->getClipboard();
     $items = $clipboard->fetch($filter);
     $actions = array();
     foreach ($items as $item) {
         $model = null;
         if (!$item->isCreate() && $item->getModelId()) {
             $modelId = $item->getModelId();
             $dataProvider = $environment->getDataProvider($item->getDataProviderName());
             $config = $dataProvider->getEmptyConfig()->setId($modelId->getId());
             $model = $dataProvider->fetch($config);
         }
         $actions[] = array('model' => $model, 'item' => $item);
     }
     return $actions;
 }
예제 #3
0
 /**
  * Calculate all clipboard items for the current view.
  *
  * @return ItemInterface[]
  */
 private function calculateClipboardItems()
 {
     $dataDefinition = $this->environment->getDataDefinition();
     $basicDefinition = $dataDefinition->getBasicDefinition();
     $clipboard = $this->environment->getClipboard();
     $filter = new Filter();
     $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
     if ($parentDataProviderName = $basicDefinition->getParentDataProvider()) {
         $filter->andParentIsFromProvider($parentDataProviderName);
     } else {
         $filter->andHasNoParent();
     }
     return $clipboard->fetch($filter);
 }
 /**
  * Handle view.
  *
  * @param ViewEvent $event The view event.
  *
  * @return void
  */
 public function handleView(ViewEvent $event)
 {
     if (DcGeneralViews::CLIPBOARD !== $event->getViewName()) {
         return;
     }
     $environment = $event->getEnvironment();
     $input = $environment->getInputProvider();
     $clipboard = $environment->getClipboard();
     $eventDispatcher = $environment->getEventDispatcher();
     $basicDefinition = $environment->getDataDefinition()->getBasicDefinition();
     $modelProviderName = $basicDefinition->getDataProvider();
     $parentProviderName = $basicDefinition->getParentDataProvider();
     $filter = new Filter();
     $filter->andModelIsFromProvider($modelProviderName);
     if ($parentProviderName) {
         $filter->andParentIsFromProvider($parentProviderName);
     } else {
         $filter->andHasNoParent();
     }
     $options = array();
     foreach ($clipboard->fetch($filter) as $item) {
         $modelId = $item->getModelId();
         $dataProvider = $environment->getDataProvider($item->getDataProviderName());
         if ($modelId) {
             $config = $dataProvider->getEmptyConfig();
             $config->setId($modelId->getId());
             $model = $dataProvider->fetch($config);
             // The model might have been deleted meanwhile.
             if (!$model) {
                 continue;
             }
             $formatModelLabelEvent = new FormatModelLabelEvent($environment, $model);
             $eventDispatcher->dispatch(DcGeneralEvents::FORMAT_MODEL_LABEL, $formatModelLabelEvent);
             $label = $formatModelLabelEvent->getLabel();
             $label = array_shift($label);
             $label = $label['content'];
         } else {
             $model = $dataProvider->getEmptyModel();
             $label = $environment->getTranslator()->translate('new.0', $item->getDataProviderName());
         }
         $options[$item->getClipboardId()] = array('item' => $item, 'model' => $model, 'label' => $label);
     }
     $addToUrlEvent = new AddToUrlEvent('act=clear-clipboard&original-act=' . $input->getParameter('act'));
     $eventDispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, $addToUrlEvent);
     $clearUrl = $addToUrlEvent->getUrl();
     $addToUrlEvent = new AddToUrlEvent('clipboard-item=%id%&act=clear-clipboard&original-act=' . $input->getParameter('act'));
     $eventDispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, $addToUrlEvent);
     $clearItemUrl = $addToUrlEvent->getUrl();
     $template = new \BackendTemplate('dcbe_general_clipboard');
     $template->setData(array('environment' => $environment, 'options' => $options, 'clearUrl' => $clearUrl, 'clearItemUrl' => $clearItemUrl));
     $event->setResponse($template->parse());
 }
예제 #5
0
 /**
  * Test and sub filter.
  *
  * @dataProvider provideSubFilter()
  */
 public function testOrSub($expected, FilterInterface $subFilter)
 {
     $item = new MockedAbstractItem(ItemInterface::CREATE);
     $firstSub = new MockedFilter(false);
     $filter = new Filter();
     $filter->orSub($firstSub);
     $filter->orSub($subFilter);
     $this->assertEquals($expected, $filter->accepts($item));
 }
예제 #6
0
 /**
  * Create the "new" button.
  *
  * @return null|Command
  */
 protected function getCreateModelCommand()
 {
     $environment = $this->getEnvironment();
     $definition = $environment->getDataDefinition();
     $basicDefinition = $definition->getBasicDefinition();
     $providerName = $environment->getDataDefinition()->getName();
     $mode = $basicDefinition->getMode();
     $config = $this->getEnvironment()->getBaseConfigRegistry()->getBaseConfig();
     if ($serializedPid = $environment->getInputProvider()->getParameter('pid')) {
         $pid = ModelId::fromSerialized($serializedPid);
     } else {
         $pid = null;
     }
     if (!$basicDefinition->isCreatable()) {
         return null;
     }
     $command = new Command();
     $parameters = $command->getParameters();
     $extra = $command->getExtra();
     $extra['class'] = 'header_new';
     $extra['accesskey'] = 'n';
     $extra['attributes'] = 'onclick="Backend.getScrollOffset();"';
     $command->setName('button_new')->setLabel($this->translate('new.0', $providerName))->setDescription($this->translate('new.1', $providerName));
     $this->getPanel()->initialize($config);
     // Add new button.
     if ($mode == BasicDefinitionInterface::MODE_PARENTEDLIST || $mode == BasicDefinitionInterface::MODE_HIERARCHICAL) {
         $filter = new Filter();
         $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
         if ($parentDataProviderName = $basicDefinition->getParentDataProvider()) {
             $filter->andParentIsFromProvider($parentDataProviderName);
         } else {
             $filter->andHasNoParent();
         }
         if ($environment->getClipboard()->isNotEmpty($filter)) {
             return null;
         }
     }
     $parameters['act'] = 'create';
     // Add new button.
     if ($pid) {
         $parameters['pid'] = $pid->getSerialized();
     }
     return $command;
 }
예제 #7
0
 /**
  * Generate the paste button.
  *
  * @param GetPasteButtonEvent $event The event.
  *
  * @return void
  *
  * @SuppressWarnings(PHPMD.Superglobals)
  * @SuppressWarnings(PHPMD.CamelCaseVariableName)
  */
 public function generatePasteButton(GetPasteButtonEvent $event)
 {
     if ($event->getEnvironment()->getDataDefinition()->getName() !== 'tl_metamodel_dcasetting_condition') {
         return;
     }
     $environment = $event->getEnvironment();
     $model = $event->getModel();
     $clipboard = $environment->getClipboard();
     // Disable all buttons if there is a circular reference.
     if ($clipboard->fetch(Filter::create()->andActionIs(ItemInterface::CUT)->andModelIs(ModelId::fromModel($model)))) {
         $event->setPasteAfterDisabled(true)->setPasteIntoDisabled(true);
         return;
     }
     $flags = $GLOBALS['METAMODELS']['inputscreen_conditions'][$model->getProperty('type')];
     // If setting does not support children, omit them.
     if ($model->getId() && !$flags['nestingAllowed']) {
         $event->setPasteIntoDisabled(true);
         return;
     }
     if (isset($flags['maxChildren']) && count($event->getEnvironment()->getController()->assembleAllChildrenFrom($model)) > $flags['maxChildren']) {
         $event->setPasteIntoDisabled(true);
     }
 }
예제 #8
0
파일: Subscriber.php 프로젝트: zonky2/core
 /**
  * Generate the paste button.
  *
  * @param GetPasteButtonEvent $event The event.
  *
  * @return void
  */
 public function generatePasteButton(GetPasteButtonEvent $event)
 {
     if ($event->getEnvironment()->getDataDefinition()->getName() !== 'tl_metamodel_filtersetting') {
         return;
     }
     $environment = $event->getEnvironment();
     $model = $event->getModel();
     $clipboard = $environment->getClipboard();
     $filter = new Filter();
     $filter->andModelIs(ModelId::fromModel($model))->andActionIs($clipboard::MODE_CUT);
     // Disable all buttons if there is a circular reference.
     if ($event->isCircularReference() || !$clipboard->isEmpty($filter)) {
         $event->setPasteAfterDisabled(true)->setPasteIntoDisabled(true);
         return;
     }
     $factory = $this->getServiceContainer()->getFilterFactory()->getTypeFactory($model->getProperty('type'));
     // If setting does not support children, omit them.
     if ($model->getId() && !($factory && $factory->isNestedType())) {
         $event->setPasteIntoDisabled(true);
     }
 }
예제 #9
0
 /**
  * Retrieve a list of html buttons to use in the top panel (submit area).
  *
  * @param ModelInterface $parentModel The parent model.
  *
  * @return string
  */
 protected function getHeaderButtons($parentModel)
 {
     $environment = $this->getEnvironment();
     $definition = $environment->getDataDefinition();
     $clipboard = $environment->getClipboard();
     $basicDefinition = $definition->getBasicDefinition();
     $headerButtons = array();
     if (!$this->isSelectModeActive()) {
         return '';
     }
     $dispatcher = $environment->getEventDispatcher();
     $objConfig = $this->getEnvironment()->getBaseConfigRegistry()->getBaseConfig();
     $this->getPanel()->initialize($objConfig);
     $sorting = $objConfig->getSorting();
     $headerButtons['editHeader'] = $this->getHeaderEditButtons($parentModel);
     $filter = new Filter();
     $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
     if ($parentDataProviderName = $basicDefinition->getParentDataProvider()) {
         $filter->andParentIsFromProvider($parentDataProviderName);
     } else {
         $filter->andHasNoParent();
     }
     if ($sorting && $clipboard->isEmpty($filter) && $basicDefinition->isCreatable()) {
         /** @var AddToUrlEvent $urlEvent */
         $urlEvent = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent('act=edit&amp;pid=' . ModelId::fromModel($parentModel)->getSerialized()));
         /** @var GenerateHtmlEvent $imageEvent */
         $imageEvent = $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, new GenerateHtmlEvent('new.gif', $this->translate('pastenew.0', $definition->getName())));
         $headerButtons['pasteNew'] = sprintf('<a href="%s" title="%s" onclick="Backend.getScrollOffset()">%s</a>', $urlEvent->getUrl(), specialchars($this->translate('pastenew.1', $definition->getName())), $imageEvent->getHtml());
     }
     $filter = new Filter();
     $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
     $filter->andParentIsFromProvider($basicDefinition->getParentDataProvider());
     if ($sorting && $clipboard->isNotEmpty($filter)) {
         $allowPasteTop = ViewHelpers::getManualSortingProperty($this->environment);
         if (!$allowPasteTop) {
             $subFilter = new Filter();
             $subFilter->andActionIsNotIn(array(ItemInterface::COPY, ItemInterface::DEEP_COPY));
             $subFilter->andParentIsNot(ModelId::fromModel($parentModel));
             $subFilter->orActionIsIn(array(ItemInterface::COPY, ItemInterface::DEEP_COPY));
             $filter = new Filter();
             $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
             $filter->andParentIsFromProvider($basicDefinition->getParentDataProvider());
             $filter->andSub($subFilter);
             $allowPasteTop = (bool) $clipboard->fetch($filter);
         }
         if ($allowPasteTop) {
             /** @var AddToUrlEvent $urlEvent */
             $urlEvent = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent('act=paste' . '&amp;pid=' . ModelId::fromModel($parentModel)->getSerialized()));
             /** @var GenerateHtmlEvent $imageEvent */
             $imageEvent = $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, new GenerateHtmlEvent('pasteafter.gif', $this->translate('pasteafter.0', $definition->getName()), 'class="blink"'));
             $headerButtons['pasteAfter'] = sprintf('<a href="%s" title="%s" onclick="Backend.getScrollOffset()">%s</a>', $urlEvent->getUrl(), specialchars($this->translate('pasteafter.0', $definition->getName())), $imageEvent->getHtml());
         } else {
             /** @var GenerateHtmlEvent $imageEvent */
             $imageEvent = $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, new GenerateHtmlEvent('pasteafter_.gif', $this->translate('pasteafter.0', $definition->getName()), 'class="blink"'));
             $headerButtons['pasteAfter'] = $imageEvent->getHtml();
         }
     }
     return implode(' ', $headerButtons);
 }
예제 #10
0
 /**
  * Check the buttons based on the action.
  *
  * @param ClipboardInterface $clipboard The clipboard.
  *
  * @param string             $action    The action to be checked.
  *
  * @return void
  */
 protected function checkForAction($clipboard, $action)
 {
     // Make a filter for the given action.
     $filter = new Filter();
     $filter->andActionIs($action);
     $items = $clipboard->fetch($filter);
     // Check if there are items.
     if ($items === null) {
         return;
     }
     /** @var ItemInterface[] $items */
     foreach ($items as $item) {
         // Check the context.
         $itemProviderName = $item->getModelId()->getDataProviderName();
         $modelId = $item->getModelId()->getId();
         if ($this->providerName !== $itemProviderName) {
             continue;
         }
         $containedModel = $this->getModelById($modelId);
         if ($this->currentModel == null) {
             $this->checkForRoot($containedModel, $action);
         } elseif ($containedModel) {
             $this->checkForModel($containedModel, $action);
         } else {
             $this->checkEmpty($action);
         }
     }
 }
예제 #11
0
 /**
  * Compile buttons from the table configuration array and return them as HTML.
  *
  * @param ModelInterface $model    The model for which the buttons shall be generated for.
  * @param ModelInterface $previous The previous model in the collection.
  * @param ModelInterface $next     The next model in the collection.
  *
  * @return string
  */
 protected function generateButtons(ModelInterface $model, ModelInterface $previous = null, ModelInterface $next = null)
 {
     $environment = $this->getEnvironment();
     $dataDefinition = $environment->getDataDefinition();
     $basicDefinition = $dataDefinition->getBasicDefinition();
     $commands = $this->getViewSection()->getModelCommands();
     $clipboard = $environment->getClipboard();
     $dispatcher = $environment->getEventDispatcher();
     $filter = new Filter();
     $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
     if ($parentDataProviderName = $basicDefinition->getParentDataProvider()) {
         $filter->andParentIsFromProvider($parentDataProviderName);
     } else {
         $filter->andHasNoParent();
     }
     if ($clipboard->isNotEmpty($filter)) {
         $circularIds = $clipboard->getCircularIds();
         $isCircular = in_array(ModelId::fromModel($model)->getSerialized(), $circularIds);
     } else {
         $circularIds = array();
         $isCircular = false;
     }
     $arrButtons = array();
     foreach ($commands->getCommands() as $command) {
         $arrButtons[$command->getName()] = $this->buildCommand($command, $model, $isCircular, $circularIds, $previous, $next);
     }
     if (ViewHelpers::getManualSortingProperty($this->environment)) {
         $clipboardIsEmpty = $clipboard->isEmpty($filter);
         if ($clipboardIsEmpty && BasicDefinitionInterface::MODE_HIERARCHICAL !== $basicDefinition->getMode()) {
             /** @var AddToUrlEvent $urlEvent */
             $urlEvent = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent('act=create&amp;after=' . ModelId::fromModel($model)->getSerialized()));
             /** @var GenerateHtmlEvent $imageEvent */
             $imageEvent = $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, new GenerateHtmlEvent('new.gif', $this->translate('pastenew.0', $this->getDataDefinition()->getName())));
             $arrButtons['pasteNew'] = sprintf('<a href="%s" title="%s" onclick="Backend.getScrollOffset()">%s</a>', $urlEvent->getUrl(), specialchars($this->translate('pastenew.1', $this->getDataDefinition()->getName())), $imageEvent->getHtml());
         }
         // Add paste into/after icons.
         if (!$clipboardIsEmpty) {
             if ($clipboard->isCreate()) {
                 // Add ext. information.
                 $add2UrlAfter = sprintf('act=create&after=%s&', ModelId::fromModel($model)->getSerialized());
                 $add2UrlInto = sprintf('act=create&into=%s&', ModelId::fromModel($model)->getSerialized());
             } else {
                 // Add ext. information.
                 $add2UrlAfter = sprintf('act=paste&after=%s&', ModelId::fromModel($model)->getSerialized());
                 $add2UrlInto = sprintf('act=paste&into=%s&', ModelId::fromModel($model)->getSerialized());
             }
             /** @var AddToUrlEvent $urlAfter */
             $urlAfter = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent($add2UrlAfter));
             /** @var AddToUrlEvent $urlInto */
             $urlInto = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent($add2UrlInto));
             $models = $this->environment->getController()->getModelsFromClipboard($parentDataProviderName ? IdSerializer::fromValues($parentDataProviderName, null) : null);
             $buttonEvent = new GetPasteButtonEvent($this->getEnvironment());
             $buttonEvent->setModel($model)->setCircularReference($isCircular)->setPrevious($previous)->setNext($next)->setHrefAfter($urlAfter->getUrl())->setHrefInto($urlInto->getUrl())->setPasteAfterDisabled($clipboard->isCut() && $isCircular)->setPasteIntoDisabled($clipboard->isCut() && $isCircular)->setContainedModels($models);
             $this->getEnvironment()->getEventDispatcher()->dispatch(GetPasteButtonEvent::NAME, $buttonEvent);
             $arrButtons['pasteafter'] = $this->renderPasteAfterButton($buttonEvent);
             if ($this->getDataDefinition()->getBasicDefinition()->getMode() == BasicDefinitionInterface::MODE_HIERARCHICAL) {
                 $arrButtons['pasteinto'] = $this->renderPasteIntoButton($buttonEvent);
             }
         }
     }
     return implode(' ', $arrButtons);
 }
예제 #12
0
 /**
  * Render the tree view.
  *
  * @param CollectionInterface $collection The collection of items.
  *
  * @return string
  */
 protected function viewTree($collection)
 {
     $definition = $this->getDataDefinition();
     $listing = $this->getViewSection()->getListingConfig();
     $basicDefinition = $definition->getBasicDefinition();
     $environment = $this->getEnvironment();
     $dispatcher = $environment->getEventDispatcher();
     // Init some Vars
     switch (6) {
         case 6:
             $treeClass = 'tree_xtnd';
             break;
         default:
             $treeClass = 'tree';
     }
     // Label + Icon.
     if (strlen($listing->getRootLabel()) == 0) {
         $strLabelText = 'DC General Tree BackendView Ultimate';
     } else {
         $strLabelText = $listing->getRootLabel();
     }
     if (strlen($listing->getRootIcon()) == 0) {
         $strLabelIcon = 'pagemounts.gif';
     } else {
         $strLabelIcon = $listing->getRootIcon();
     }
     $filter = new Filter();
     $filter->andModelIsFromProvider($basicDefinition->getDataProvider());
     if ($parentDataProviderName = $basicDefinition->getParentDataProvider()) {
         $filter->andParentIsFromProvider($parentDataProviderName);
     } else {
         $filter->andHasNoParent();
     }
     // Root paste into.
     if ($environment->getClipboard()->isNotEmpty($filter)) {
         /** @var AddToUrlEvent $urlEvent */
         $urlEvent = $dispatcher->dispatch(ContaoEvents::BACKEND_ADD_TO_URL, new AddToUrlEvent(sprintf('act=paste&amp;into=%s::0', $definition->getName())));
         $buttonEvent = new GetPasteRootButtonEvent($this->getEnvironment());
         $buttonEvent->setHref($urlEvent->getUrl())->setPasteDisabled(false);
         $dispatcher->dispatch($buttonEvent::NAME, $buttonEvent);
         $strRootPasteInto = $this->renderPasteRootButton($buttonEvent);
     } else {
         $strRootPasteInto = '';
     }
     /** @var GenerateHtmlEvent $imageEvent */
     $imageEvent = $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, new GenerateHtmlEvent($strLabelIcon));
     // Build template.
     $objTemplate = $this->getTemplate('dcbe_general_treeview');
     $objTemplate->treeClass = 'tl_' . $treeClass;
     $objTemplate->tableName = $definition->getName();
     $objTemplate->strLabelIcon = $imageEvent->getHtml();
     $objTemplate->strLabelText = $strLabelText;
     $objTemplate->strHTML = $this->generateTreeView($collection, $treeClass);
     $objTemplate->strRootPasteinto = $strRootPasteInto;
     $objTemplate->select = $this->isSelectModeActive();
     $objTemplate->selectButtons = $this->getSelectButtons();
     $objTemplate->intMode = 6;
     // Add breadcrumb, if we have one.
     $strBreadcrumb = $this->breadcrumb();
     if ($strBreadcrumb != null) {
         $objTemplate->breadcrumb = $strBreadcrumb;
     }
     return $objTemplate->parse();
 }
예제 #13
0
 /**
  * Add sub filter.
  *
  * @param string $conjunction AND or OR.
  * @param Filter $filter      The sub filter.
  *
  * @return static
  */
 private function sub($conjunction, Filter $filter)
 {
     if (!empty($this->expression)) {
         $this->expression[] = $conjunction;
     }
     $expression = $filter->getExpression();
     $variables = $filter->getVariables();
     $index = count($this->variables);
     $expression = str_replace('variables', 'variables[' . $index . ']', $expression);
     $this->expression[] = '(' . $expression . ')';
     $this->variables[] = $variables;
     return $this;
 }