FORUMS CLOSED DUE TO SPAM. YOU STILL CAN ADD POST!

Page Parts of Different Types

Feed 15 posts, 5 voices

Avatar
486 posts

It would be cool if as part of the creating new page part dialog, we can not only set the name of the page part but also it’s type: integer, date, string, text (default). I know the page_part table would need to handle this, perhaps via Single Table Inheritance?

I had thought originally of extending the Page model but then realized that all the action is in the page_part table…

If we can do this, then truly Frog would be supremely powerful :)

0.9.5?

 
Avatar
486 posts

And wouldn’t it be great if once you select the date data type, the Part that is generated is a Javascript date picker widget. If you select integer data type or string data type, you get an input box instead of a textarea…

 
Avatar
184 posts

Couldn’t you do that with type casting: <?settype($myVar, “string”);?>
That way, you can mix them!?

 
Avatar
316 posts

I’m confused, why would you want to change a page part type? It is meant to be “page” what would be the purpose in changing it to type integer?

The page parts are stored as part of the Page and PageArchive objects, they aren’t variables per se, they are class objects.

 
Avatar
486 posts

Page parts are actually Pages?

I think it would be useful because Parts are often used essentially as form elements. By giving data types to Parts we can essentially create on-the-fly forms, which would enable custom content types (pages with certain combinations of Parts) without the hassle of actually extending the Page model.

Page parts with specific data types would be easier to manipulate. Dates are one example. If a page Part can be specified as a date type, then we could get from that both manipulation of dates (for sorting, differences, etc) as well as an appropriate way for the user to input the data.

Right now if you want to enter a date into a page Part, you just have to trust the user to enter it in a certain format that you can parse. The user is never actually going to remember whether they’re supposed to enter it as YYYY-MM-DD or MM-DD-YY or whatever, so it’s not ideal. That’s why we like to use Javascript date pickers.

 
Avatar
316 posts

If you are concerned about Dates and times, wouldn’t it make sense to pass the, I’m assuming, form value through strtotime()?

EDIT: Or better yet, set 3 different inputs that you control. Input for Day, Input for Month, Input for Year and then pass it through to mktime()?

 
Avatar
486 posts

EDIT: Or better yet, set 3 different inputs that you control. Input for Day, Input for Month, Input for Year and then pass it through to mktime()?

If I’m not mistaken, you’re saying a separate Part for each section of the date. That would help, but I think you’re still going to have validation errors because of misspellings and so forth (and of course separate Parts is inelegant to say the least). And because the date is still stored as text in the database, you’re still limited in what you can do with it.

Let’s just ignore dates though. The basic thing I’m saying is that there are different data types in programming and we store different data types in a database for a reason. It would be nice, simply, if we can extend that and get the power that comes with it to Frog’s Page Parts system.

 
Avatar
316 posts

A separate part for each? I’m really confused now.

A page part is the section in the Admin’s Page Editor usually named “Body”. You add extra page parts by clicking the “+” on the right hand side of the edit page. If you have Body and Extended, you have 2 page parts. All my pages have 3 page parts, Body, Extended, and Summary. Anything you write in the editor box is stored within that page part.

Why would you create a different Page Part for that type of form?

EDIT: Here is a screen capture of my backend to show you what I mean.

 
Avatar
1493 posts

I suppose anything is possible … but I’m also pretty clear that we’re doing some “thinking out loud” about post-1.0 release enhancements! Or maybe this is something that could be handled by a plugin?

What I’m having a hard time picturing is the structure of the db table. Here’s the page_part table as it is at present:

To accomodate the sort of flexibility that ricks is after, I assume one would have to add not just new fields to this table, but whole new tables to accomodate different data types. Now database design is hardly my long suit, so I may be way off on this!

I suppose you could have something like the following:

And then you would also have three corresponding tables…

I don’t know! Just me thinking out loud is all…..

 
Avatar
1493 posts

P.S. Ricks wrote in post #5 (up there somewhere!):

Page parts are actually Pages?

“Body” is just the default page-part. The “Page” table only holds the “page’s” metadata; its content is wholly contained in the “page-part” table.

But I’m guessing you knew that already.

 
Avatar
316 posts

Sorry, this is probably going to be fairly long, but it might help to explain how the Page Parts are saved in the variables. If you go down this print out of one of my archives, you’ll see the “Parent > Page Object” and then eventually you hit “Part > Body” etc. Each page part is a stdClass Object, not a variable, per se.

Array
(
    [0] => PageArchive Object
        (
            [id] => 85
            [title] => Overhaul
            [breadcrumb] => Overhaul
            [author] => Tyler
            [author_id] => 1
            [updator] => Tyler
            [updator_id] => 1
            [slug] => overhaul
            [keywords] => update, 301, redirect, overhaul, page, changes
            [description] => I have updated my website to reflect a more organized url and structure for my articles,
                             this is just a post to detail the changes.
            [url] => articles/miscellaneous/2008/10/30/overhaul
            [parent] => Page Object
                (
                    [id] => 57
                    [title] => Miscellaneous
                    [breadcrumb] => Miscellaneous
                    [author] => Tyler
                    [author_id] => 
                    [updator] => Tyler
                    [updator_id] => 
                    [slug] => miscellaneous
                    [keywords] => 
                    [description] => Here is where I post articles that really don't fit into any of the other categories.
                    [url] => articles/miscellaneous
                    [parent] => Page Object
                        (
                            [id] => 4
                            [title] => Articles
                            [breadcrumb] => Articles
                            [author] => Tyler
                            [author_id] => 
                            [updator] => Tyler
                            [updator_id] => 
                            [slug] => articles
                            [keywords] => 
                            [description] => 
                            [url] => articles
                            [parent] => Page Object
                                (
                                    [id] => 1
                                    [title] => Home Page
                                    [breadcrumb] => Home Page
                                    [author] => Tyler
                                    [author_id] => 
                                    [updator] => Tyler
                                    [updator_id] => 
                                    [slug] => 
                                    [keywords] => 
                                    [description] => 
                                    [url] => 
                                    [parent] => 
                                    [level] => 
                                    [tags] => 
                                    [parent_id] => 0
                                    [layout_id] => 4
                                    [behavior_id] => 
                                    [status_id] => 100
                                    [comment_status] => 0
                                    [created_on] => 2008-07-27 17:49:29
                                    [published_on] => 2008-07-27 17:49:30
                                    [updated_on] => 2008-11-07 22:55:23
                                    [created_by_id] => 1
                                    [updated_by_id] => 1
                                    [position] => 0
                                    [is_protected] => 1
                                    [part] => stdClass Object
                                        (
                                            [body] => stdClass Object
                                                (
                                                    [name] => body
                                                    [content_html] => <?php $articles = adv_find(array('articles/free-market/', 'articles/guns/', 'articles/miscellaneous/', 'articles/plugins/', 'articles/politics/'), array('order' => 'published_on DESC', 'limit' => '6')); ?>
<?php foreach ($articles as $article): ?> 
<div class="entry">
  <h3><?php echo $article->link(); ?></h3>
  <?php echo $article->content(); ?>
  <?php if ($article->hasContent('extended')) echo $article->link('Continue Reading…'); ?>
  <p class="info">Posted by <?php echo $article->author(); ?> on <?php echo $article->date(); ?></p>
</div>

<?php endforeach; ?>

                                                )

                                            [sidebar] => stdClass Object
                                                (
                                                    [name] => sidebar
                                                    [content_html] => 
                                                )

                                        )

                                )

                            [level] => 
                            [tags] => 
                            [parent_id] => 1
                            [layout_id] => 0
                            [behavior_id] => 
                            [status_id] => 100
                            [comment_status] => 0
                            [created_on] => 2008-07-27 17:49:38
                            [published_on] => 2008-07-27 17:49:39
                            [updated_on] => 2008-10-30 21:53:08
                            [created_by_id] => 1
                            [updated_by_id] => 1
                            [position] => 3
                            [is_protected] => 1
                            [part] => stdClass Object
                                (
                                    [body] => stdClass Object
                                        (
                                            [name] => body
                                            [content_html] => <p>In order to keep the site better organized, I have sorted it into subdirectories.  Please choose one of them from below to see the related articles:</p>

<?php $page_articles = $this->find('articles'); ?>
<?php $articles = $page_articles->children(array('order'=>'page.position ASC')); ?>
<?php foreach ($articles as $article): ?>
<div class="entry">
  <h3><?php echo $article->link($article->title); ?></h3>
  <p><?php echo $article->description(); ?></p>

</div>
<?php endforeach; ?>
                                        )

                                )

                        )

                    [level] => 
                    [tags] => 
                    [parent_id] => 4
                    [layout_id] => 0
                    [behavior_id] => archive
                    [status_id] => 100
                    [comment_status] => 0
                    [created_on] => 2008-10-19 17:25:28
                    [published_on] => 2008-10-19 17:25:28
                    [updated_on] => 2008-11-12 16:53:57
                    [created_by_id] => 1
                    [updated_by_id] => 1
                    [position] => 2
                    [is_protected] => 0
                    [part] => stdClass Object
                        (
                            [body] => stdClass Object
                                (
                                    [name] => body
                                    [content_html] => 
                                )

                            [sidebar] => stdClass Object
                                (
                                    [name] => sidebar
                                    [content_html] => <?php $article = $this->find('/articles/miscellaneous/'); ?>
<?php $archives = $article->archive->archivesByMonth(); ?>

<h3>Archives By Month</h3>
<ul>
<?php foreach ($archives as $date): ?>
  <li><a href="<?php echo BASE_URL . $this->url .'/'. $date . URL_SUFFIX; ?>"><?php echo strftime('%B %Y', strtotime(strtr($date, '/', '-'))); ?></a></li>
<?php endforeach; ?>
</ul>
                                )

                            [extended] => stdClass Object
                                (
                                    [name] => extended
                                    [content_html] => <?php $last_articles = $this->children(array('limit'=>5, 'order'=>'page.created_on DESC')); ?>

<?php foreach ($last_articles as $article): ?>
<div class="entry">
  <h3><?php echo $article->link($article->title); ?></h3>
  <?php echo $article->content(); ?>
  <p class="info">Posted by <?php echo $article->author(); ?> on <?php echo $article->date(); ?>  
<?php if($article->comment_status != Comment::NONE): ?>
     — <b><?php echo $num_comments = comments_count($article); ?></b> comment<?php if ($num_comments != 1) echo 's'; ?>
<?php endif; ?>
     <br />tags: <?php $i = 1; foreach($article->tags() as $tag){ ?>
    <a href="<?php echo BASE_URL . 'tags/' . $tag . URL_SUFFIX; ?>"><?php echo $tag; ?></a>

    <?php echo $i == count($article->tags()) ? '.' : ', '; $i++ ?>
<?php } ?>
  </p>
</div>
<?php endforeach; ?>
                                )

                        )

                    [archive] => Archive Object
                        (
                            [page] => Page Object
 *RECURSION*
                            [params] => Array
                                (
                                )

                        )

                )

            [level] => 
            [tags] => 
            [parent_id] => 57
            [layout_id] => 0
            [behavior_id] => 
            [status_id] => 100
            [comment_status] => 1
            [created_on] => 2008-10-30 23:27:07
            [published_on] => 2008-10-30 23:38:07
            [updated_on] => 2008-10-31 03:06:23
            [created_by_id] => 1
            [updated_by_id] => 1
            [position] => 1
            [is_protected] => 0
            [part] => stdClass Object
                (
                    [body] => stdClass Object
                        (
                            [name] => body
                            [content_html] => <p>I've gone and done a very large overhaul on the structure of this site.  
                                                 A few things are left to change, but they will be minor and should not affect the structure of the URL anymore.  
                                                 Simply enough, I've just added in one more level of organization.  
                                                 Previously all Articles were listed under the <a href="http://www.tbeckett.net/articles.xhtml">Articles</a> tab.  
                                                 However, that wasn't very organized and I felt it made the site a little difficult to navigate.  
                                                 I have, therefore, changed it so that the <a href="http://www.tbeckett.net/articles.xhtml">Articles</a> tab 
                                                 has 5 new sub levels to keep my articles a little more oganized and, hopefully, easier to find.  
                                                 The 5 new levels are:</p>

                        )

                    [extended] => stdClass Object
                        (
                            [name] => extended
                            [content_html] => <ul>
<li><a href="http://www.tbeckett.net/articles.xhtml">Articles</a>
	<ul>
	<li><a href="http://www.tbeckett.net/articles/free-market.xhtml">Free-Market</a></li>
	<li><a href="http://www.tbeckett.net/articles/guns.xhtml">Guns</a></li>
	<li><a href="http://www.tbeckett.net/articles/miscellaneous.xhtml">Miscellaneous</a></li>
	<li><a href="http://www.tbeckett.net/articles/plugins.xhtml">Plugins</a></li>

	<li><a href="http://www.tbeckett.net/articles/politics.xhtml">Politics</a></li>
	</ul></li>
</ul>

<p>The rest of the site has remained, basically, the same.  
There will be a few changes as I fix bugs around the site, but it shouldn't end up being anything major.  
The new levels have explanations on the <a href="http://www.tbeckett.net/articles.xhtml">Articles</a> page as to what each contains.  
This should cover any articles that I may write in the future.  
If not, I'll make sure to create the new section before posting so that you don't have to suffer through anymore 301 redirects.</p>

<p>Anyway, feel free to peruse the new layout and tell me what you think.  
If I need to work on something to make the site better, let me know!</p>
                        )

                    [summary] => stdClass Object
                        (
                            [name] => summary
                            [content_html] => I've gone and done a very large overhaul on the structure of this site.  
                                              A few things are left to change, but they will be minor and should not affect the structure of the URL anymore.  
                                              Simply enough, I've just added in one more level of organization.  
                                              Previously all Articles were listed under the Articles tab.  
                                              However, that wasn't very organized and I felt it made the site a little difficult to navigate.  
                                              I have, therefore, changed it so that the Articles tab has 5 new sub levels 
                                              to keep my articles a little more oganized and, hopefully, easier to find.

There is more to this post.  To see the rest, please visit: <?php echo ($this->url()); ?>
                        )

                )

        )

)

So, for example, near the very bottom, you see

                    [summary] => stdClass Object

That “summary” is the name of the page part, it is repeated just inside the object.

                            [content_html] => I've ...

That section is the contents of the page part, where you store the contents of your page.

The only way, I could see, of changing that would be to add another section after name of type. But I still don’t see why you’d need that. Everything is manipulable via code or plugin and that’s far easier than changing the framework, I think.

 
Avatar
651 posts

@everyone…

Maybe this is a stupid remark, maybe not… anyway, here goes:

It sounds like you’re all trying to develop a solution to a problem. It also sounds like the problem isn’t really clear to all of you, at least not in the same way. May I suggest a different tactic to tackling this?

I would like someone to describe a so-called “user story” for this problem. A user story basically is an explanation of what the user wants to do without describing how he wants to do it. This should allow the developer to present a technical solution which hopefully does what the user wants.

An example of what I mean:

“As a content editor I want to be able to define if someone has to login to view my page. This setting has to be inheritable.”

another example would be:

“As an administrator I want to be able to define new ‘roles’ which have certain rights associated to them.”

What do you think about trying it this way? Then the techies could formulate a consistent, light-weight, in-keeping-with-Frog-style solution.

 
Avatar
1493 posts

@mvdkleijn: I think that’s brilliant! You do get the feeling that sometimes in this thread we’re talking past each other.

The other observation I would add is that Frog won’t always be the best tool for every job. (Hard to believe, I know.) There are other CMSs whose main raison d‘être is to provide a means of manipulating databases. But that ain’t Frog, IMO! :)

 
Avatar
486 posts

Thank you for indulging me, guys. As David said, this is really a “thinking out loud” sort of thing. Your input and comments helped to clarify my thoughts, and I think David’s final comment about Frog not being designed for databases is probably correct.

mytylerb’s example of Page Parts usage is probably as far as you should stretch the Parts system.

Instead of using the Parts system, I’m thinking now that things like Events should be built outside of Frog’s Page system but using the Framework, and still integrating with Frog so that you can still have a tab in the dashboard for adding Events. By staying completely out of the Page system (and Parts), you can have perfect forms (radio buttons, inputs, dropdowns, etc) use your own tables and data types and have complete control over the data. It would be easier I think than trying to use the Parts system to accomplish this.

So you can still have a site like this: frogsite.com/events, but now events would be a controller outside of Frog, but still within the Framework. It would not generate pages that would appear in the pages listing.

Does this sound like a better idea? And has anybody done something like this where you use Frog for the general CMS but extend it further using the Framework (with content outside of the Page system) in order to meet requirements?

 
Avatar
316 posts

I think I think out loud too much. ;-)

I believe this all started with a want by chaichai for a calender plugin.

 
Avatar
651 posts

I think you’re on to something there ricks ;-)

Remember… the controllers you create using the plugin API are effectively controllers from the Framework. All you need to do for an event system is write a small plugin which has:

  • a management interface through a tab (controller)
  • stores events in its own database table, something like: id, name, day, month, year, description, location
  • provides a number of function calls which allow users to search the events
  • each function call should return either an array of Event objects or a single Event object
  • the Event object/class should extend the framework’s Record class in order for it to make use of all the DB manipulating goodies in there.

That way, end-users can simply use the various functions to create, read, update and delete events and create their own interfaces on the frontend.