New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use view blocks generated by cell within main layout/vew/request #10166

Open
saeideng opened this Issue Feb 3, 2017 · 24 comments

Comments

Projects
None yet
6 participants
@saeideng
Member

saeideng commented Feb 3, 2017

This is a (multiple allowed):

  • bug

  • enhancement

  • feature-discussion (RFC)

  • CakePHP Version: 3.4.x

What you did

A way to render blocks(like js making with scriptBlock() ) within main layout

//cell
$this->Html->scriptBlock('alert("hi")', ['block' => 'blockName']);
//layout : outside of cell
$this->fetch('blockName');

I can explain more with sample if you need

@saeideng saeideng changed the title from use view blocks generated in cell within main layout/vew/request to use view blocks generated by cell within main layout/vew/request Feb 3, 2017

@markstory markstory added this to the 3.5.0 milestone Feb 3, 2017

@markstory

This comment has been minimized.

Show comment
Hide comment
@markstory

markstory Feb 3, 2017

Member

I don't really understand what you're trying to do here.

Member

markstory commented Feb 3, 2017

I don't really understand what you're trying to do here.

@markstory markstory added the view label Feb 3, 2017

@dereuromark

This comment has been minimized.

Show comment
Hide comment
@dereuromark

dereuromark Feb 3, 2017

Member

I think he wants to share view blocks between cells and the main view rendering process.

Member

dereuromark commented Feb 3, 2017

I think he wants to share view blocks between cells and the main view rendering process.

@saeideng

This comment has been minimized.

Show comment
Hide comment
@saeideng

saeideng Feb 3, 2017

Member

I think he wants to share view blocks between cells and the main view rendering process.

yes

Member

saeideng commented Feb 3, 2017

I think he wants to share view blocks between cells and the main view rendering process.

yes

@dereuromark

This comment has been minimized.

Show comment
Hide comment
@dereuromark

dereuromark Feb 3, 2017

Member

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.
If you need to share things, then maybe it should all be in the main one, using helpers, elements and alike instead.

Member

dereuromark commented Feb 3, 2017

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.
If you need to share things, then maybe it should all be in the main one, using helpers, elements and alike instead.

@saeideng

This comment has been minimized.

Show comment
Hide comment
@saeideng

saeideng Feb 3, 2017

Member

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.

I agree with you but for some usage we need for that , like when using scriptBlock() within Cell and we need render it after other js in mail view
element cannot support total of usages, because we need access to model (for example)

Member

saeideng commented Feb 3, 2017

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.

I agree with you but for some usage we need for that , like when using scriptBlock() within Cell and we need render it after other js in mail view
element cannot support total of usages, because we need access to model (for example)

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 3, 2017

Member

You have one call render the html for the cell, and a second call render the Javascript for the cell.

Cells are isolated and decoupled from the parent view for good reasons, and it makes it a lot easier to cache the results.

  echo $this->cell('Example:stuff')->render();
  $this->Blocks->start('script');
  echo $this->cell('Example:javascript')->render();
  $this->Blocks->end();
Member

thinkingmedia commented Feb 3, 2017

You have one call render the html for the cell, and a second call render the Javascript for the cell.

Cells are isolated and decoupled from the parent view for good reasons, and it makes it a lot easier to cache the results.

  echo $this->cell('Example:stuff')->render();
  $this->Blocks->start('script');
  echo $this->cell('Example:javascript')->render();
  $this->Blocks->end();
@saeideng

This comment has been minimized.

Show comment
Hide comment
@saeideng

saeideng Feb 3, 2017

Member

You have one call render the html for the cell, and a second call render the Javascript for the cell.

if js vars/Html created by model data( DB/... ) we need access 2 time to DB(for example)
I know we can using cache But ... is not fast way for developing 😃
and using of 2 cells is not clear

Member

saeideng commented Feb 3, 2017

You have one call render the html for the cell, and a second call render the Javascript for the cell.

if js vars/Html created by model data( DB/... ) we need access 2 time to DB(for example)
I know we can using cache But ... is not fast way for developing 😃
and using of 2 cells is not clear

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 3, 2017

Member

I'm sorry, it wasn't the best solution but that's how you have to do it with the current way it is. I have a graph cell that has to embed the script inline because of this limitation. So I feel your pain.

We need a solution that's compatible with caching.

How about a new view class that you can use with a cell that returns an object instead of a string, and that object has a getBody() and getBlock($name) methods. This object could be serializable to continue support for caching.

Member

thinkingmedia commented Feb 3, 2017

I'm sorry, it wasn't the best solution but that's how you have to do it with the current way it is. I have a graph cell that has to embed the script inline because of this limitation. So I feel your pain.

We need a solution that's compatible with caching.

How about a new view class that you can use with a cell that returns an object instead of a string, and that object has a getBody() and getBlock($name) methods. This object could be serializable to continue support for caching.

@markstory

This comment has been minimized.

Show comment
Hide comment
@markstory

markstory Feb 4, 2017

Member

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.

They are not cells are intentionally isolated from the main rendering flow. If you want to share view context then use elements.

Member

markstory commented Feb 4, 2017

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.

They are not cells are intentionally isolated from the main rendering flow. If you want to share view context then use elements.

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 4, 2017

Member

@markstory yes an element solves the view context, but then you loose the ability to perform queries on a model. Think of a Graph cell as an example. You have to render the HTML for the canvas, but you also want to append the JavaScript code at the bottom of the layout, and you have to query the data for the graph. The graph itself is heavy so you want to cache this.

Element won't solve cache because of the scripts block, and a cell can't use blocks.

What's the solution?

Member

thinkingmedia commented Feb 4, 2017

@markstory yes an element solves the view context, but then you loose the ability to perform queries on a model. Think of a Graph cell as an example. You have to render the HTML for the canvas, but you also want to append the JavaScript code at the bottom of the layout, and you have to query the data for the graph. The graph itself is heavy so you want to cache this.

Element won't solve cache because of the scripts block, and a cell can't use blocks.

What's the solution?

@dereuromark

This comment has been minimized.

Show comment
Hide comment
@dereuromark

dereuromark Feb 4, 2017

Member

You could probably hack it by sharing it via Configure and alike (pushing it into some stack here). Anything that is actually shared inside the same dispatcher request.
But I do not think that is a very good framework approach here.

Member

dereuromark commented Feb 4, 2017

You could probably hack it by sharing it via Configure and alike (pushing it into some stack here). Anything that is actually shared inside the same dispatcher request.
But I do not think that is a very good framework approach here.

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 4, 2017

Member

I'm going to give a crack at a view class to solve this particular problem, and reviewing a PR might be easier for discussion (in this case).

Member

thinkingmedia commented Feb 4, 2017

I'm going to give a crack at a view class to solve this particular problem, and reviewing a PR might be easier for discussion (in this case).

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 4, 2017

Member

Oh I figured it out! You can do it without any changes. We just need to document this better.

An example index.ctp using a cell:

   $cached = Cache::remember('myCell', function() {
        $view = $this->cell('Example')->createView();
        return [
            'html' => $view->render(),
            'script' => $view->Blocks->get('script')
        ];
   });

  echo $cached['html'];
  $this->Blocks->concat('script', $cached['script']);

I think the above would solve the problem. We need some way of making this easy for people to do.

I was thinking we could add a 'cache' parameter to the options array when calling View::cell but the problem there is that the cell method returns an object.

I'll think on this for a bit.

Member

thinkingmedia commented Feb 4, 2017

Oh I figured it out! You can do it without any changes. We just need to document this better.

An example index.ctp using a cell:

   $cached = Cache::remember('myCell', function() {
        $view = $this->cell('Example')->createView();
        return [
            'html' => $view->render(),
            'script' => $view->Blocks->get('script')
        ];
   });

  echo $cached['html'];
  $this->Blocks->concat('script', $cached['script']);

I think the above would solve the problem. We need some way of making this easy for people to do.

I was thinking we could add a 'cache' parameter to the options array when calling View::cell but the problem there is that the cell method returns an object.

I'll think on this for a bit.

@inoas

This comment has been minimized.

Show comment
Hide comment
@inoas

inoas Feb 5, 2017

Contributor

Right now with the tools out of the box you could not create a script block that you run at say scriptBottom from within a cell view template, right?

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.

They are not cells are intentionally isolated from the main rendering flow. If you want to share view context then use elements.

Maybe it would be good if there was something like 'viewScope' attribute for those View HtmlHelper methods that allow to append CSS/JS/HTML code/ressources above/below the fold?

Contributor

inoas commented Feb 5, 2017

Right now with the tools out of the box you could not create a script block that you run at say scriptBottom from within a cell view template, right?

I do not think the cells are designed for this, they should be small independent sub-renderings so to speak.

They are not cells are intentionally isolated from the main rendering flow. If you want to share view context then use elements.

Maybe it would be good if there was something like 'viewScope' attribute for those View HtmlHelper methods that allow to append CSS/JS/HTML code/ressources above/below the fold?

@markstory

This comment has been minimized.

Show comment
Hide comment
@markstory

markstory Feb 6, 2017

Member

You could also pass the current view into the cell as an argument. You'd then be able to use the 'parent' view's helpers. Something like:

class SharedStateCell
{
  public function share($parentView)
  {
    $this->set('parentView', $parentView);
  }
}

// cell template
$parentView->Html->scriptBlock('alert("hi")', ['block' => 'blockName']);

// Rendering in the parent view
<?= $this->cell('SharedState::share', [$this]) ?>

I'm not convinced that we should break the encapsulation/isolation when there are existing solutions.

Member

markstory commented Feb 6, 2017

You could also pass the current view into the cell as an argument. You'd then be able to use the 'parent' view's helpers. Something like:

class SharedStateCell
{
  public function share($parentView)
  {
    $this->set('parentView', $parentView);
  }
}

// cell template
$parentView->Html->scriptBlock('alert("hi")', ['block' => 'blockName']);

// Rendering in the parent view
<?= $this->cell('SharedState::share', [$this]) ?>

I'm not convinced that we should break the encapsulation/isolation when there are existing solutions.

@inoas

This comment has been minimized.

Show comment
Hide comment
@inoas

inoas Feb 6, 2017

Contributor

But wouldn't passing the view into the cell open a can of worms of possibilities to break encapsulation/isolation? Especially as a logical child is mutating the state of its parent ($this).
vs... just allowing cells to do very specific things on opt in basis, e.g. to push things into css, cssBottom, script and scriptBottom?

Contributor

inoas commented Feb 6, 2017

But wouldn't passing the view into the cell open a can of worms of possibilities to break encapsulation/isolation? Especially as a logical child is mutating the state of its parent ($this).
vs... just allowing cells to do very specific things on opt in basis, e.g. to push things into css, cssBottom, script and scriptBottom?

@markstory

This comment has been minimized.

Show comment
Hide comment
@markstory

markstory Feb 6, 2017

Member

@ionas Sure, but that's what is being asked for here. Cells are isolated on purpose, but this entire thread is about opening that bubble so that cells can mutate state of the parent. Sharing blocks requires sharing view context, which means sharing the whole context.

Member

markstory commented Feb 6, 2017

@ionas Sure, but that's what is being asked for here. Cells are isolated on purpose, but this entire thread is about opening that bubble so that cells can mutate state of the parent. Sharing blocks requires sharing view context, which means sharing the whole context.

@saeideng

This comment has been minimized.

Show comment
Hide comment
@saeideng

saeideng Feb 6, 2017

Member

What you thing about someting like
$this->cell('Menu')->extractBlocks()->render():
When we used extrackBlocks() or withBlocks() cell's and main blocks can be merge

Member

saeideng commented Feb 6, 2017

What you thing about someting like
$this->cell('Menu')->extractBlocks()->render():
When we used extrackBlocks() or withBlocks() cell's and main blocks can be merge

@saeideng

This comment has been minimized.

Show comment
Hide comment
@saeideng

saeideng Feb 6, 2017

Member

Or on $this
$this->withBlocks->cell('....')

Member

saeideng commented Feb 6, 2017

Or on $this
$this->withBlocks->cell('....')

@saeideng

This comment has been minimized.

Show comment
Hide comment
@saeideng

saeideng Feb 6, 2017

Member

Above cods is just an idea
I am not sure thats can be work

Member

saeideng commented Feb 6, 2017

Above cods is just an idea
I am not sure thats can be work

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 6, 2017

Member

This needs to be fixed without introducing special new methods that a developer needs to know about. Otherwise, it will be impossible for plugin developers to use the script block from inside their plugin's cells.

Member

thinkingmedia commented Feb 6, 2017

This needs to be fixed without introducing special new methods that a developer needs to know about. Otherwise, it will be impossible for plugin developers to use the script block from inside their plugin's cells.

@thinkingmedia

This comment has been minimized.

Show comment
Hide comment
@thinkingmedia

thinkingmedia Feb 6, 2017

Member

We could add Blocks to the ViewBuilder class, and then update CellTrail to inject blocks from the current view.

I think this would be consistent with how cells are created already. The ViewBuilder is injected with the current theme, the current helpers and plugin name.

ViewBuilder would also need to pass Blocks to the View's constructor, but there is already a $_passedVars map in View that handles this.

Now, can anyone think of a reason why this would break anything?

Member

thinkingmedia commented Feb 6, 2017

We could add Blocks to the ViewBuilder class, and then update CellTrail to inject blocks from the current view.

I think this would be consistent with how cells are created already. The ViewBuilder is injected with the current theme, the current helpers and plugin name.

ViewBuilder would also need to pass Blocks to the View's constructor, but there is already a $_passedVars map in View that handles this.

Now, can anyone think of a reason why this would break anything?

@markstory

This comment has been minimized.

Show comment
Hide comment
@markstory

markstory Feb 7, 2017

Member

Well you'd be sharing view state that wasn't shared before 😄

I am have no doubts that we can come up with a variety of ways to make cells share state with the parent context. I still come back to why this is necessary. Are there use cases beyond helpers being used to emit javascript code?

Member

markstory commented Feb 7, 2017

Well you'd be sharing view state that wasn't shared before 😄

I am have no doubts that we can come up with a variety of ways to make cells share state with the parent context. I still come back to why this is necessary. Are there use cases beyond helpers being used to emit javascript code?

@inoas

This comment has been minimized.

Show comment
Hide comment
@inoas

inoas Feb 7, 2017

Contributor

That's the reason I was suggesting to add a viewScope attribute that could be set to 'global' - it it wasn't then cells would be entirely contained.

  1. requiring to eager or lazy load javascript, css
  2. pushing http2 prefetch javascript ressourches through the response head
  3. putting html snipplets at the top or bottom of the document (as anchors, say bootstrap modal, while I think little of it)

I'd probably disregard 3. as wontfix and make sure there is support for 1. (for instance through a scope attribute that has to be explicitly set) and 2. (here cell's 'actions' have to have access to the http response head).

E.g. I'd try to limit what cells can do to injecting css/js into the head / below the fold, then also make sure cells can utilize http2 prefetch to supply additional css/js ressources cells could need

Contributor

inoas commented Feb 7, 2017

That's the reason I was suggesting to add a viewScope attribute that could be set to 'global' - it it wasn't then cells would be entirely contained.

  1. requiring to eager or lazy load javascript, css
  2. pushing http2 prefetch javascript ressourches through the response head
  3. putting html snipplets at the top or bottom of the document (as anchors, say bootstrap modal, while I think little of it)

I'd probably disregard 3. as wontfix and make sure there is support for 1. (for instance through a scope attribute that has to be explicitly set) and 2. (here cell's 'actions' have to have access to the http response head).

E.g. I'd try to limit what cells can do to injecting css/js into the head / below the fold, then also make sure cells can utilize http2 prefetch to supply additional css/js ressources cells could need

@markstory markstory modified the milestones: Future, 3.5.0 May 10, 2017

@ADmad ADmad referenced this issue Mar 1, 2018

Closed

Unable to access view cell blocks #11773

1 of 3 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment