diff --git a/_config/config.yml b/_config/config.yml index e69de29..2bf9426 100755 --- a/_config/config.yml +++ b/_config/config.yml @@ -0,0 +1,3 @@ +Member: + extensions: + - BlogMemberExtension \ No newline at end of file diff --git a/code/extensions/BlogMemberExtension.php b/code/extensions/BlogMemberExtension.php new file mode 100644 index 0000000..3ade07e --- /dev/null +++ b/code/extensions/BlogMemberExtension.php @@ -0,0 +1,76 @@ + 'Varchar', + 'BlogProfileSummary' => 'Text' + ); + + private static $has_one = array( + 'BlogProfileImage' => 'Image' + ); + + private static $belongs_many_many = array( + 'AuthoredPosts' => 'BlogPost' + ); + + public function onBeforeWrite() { + // Generate a unique URL segment for the Member. + $count = 1; + + $this->owner->URLSegment = $this->generateURLSegment(); + + while(!$this->validURLSegment()) { + $this->owner->URLSegment = preg_replace('/-[0-9]+$/', null, $this->owner->URLSegment) . '-' . $count; + $count++; + } + } + + public function updateCMSFields(FieldList $fields) { + $fields->removeByName('URLSegment'); + + return $fields; + } + + /** + * Generate a unique URL segment based on the Member's name. + * + * @return string Generated URL segment. + */ + public function generateURLSegment() { + $filter = URLSegmentFilter::create(); + $name = $this->owner->FirstName . ' ' . $this->owner->Surname; + $urlSegment = $filter->filter($name); + + // Fallback to generic profile name if path is empty (= no valid, convertable characters) + if(!$urlSegment || $urlSegment == '-' || $urlSegment == '-1') $urlSegment = "profile-$this->ID"; + + return $urlSegment; + } + + /** + * Returns TRUE if this object has a URL segment value that does not conflict with any other objects. + * + * @return bool + */ + public function validURLSegment() { + $conflict = Member::get()->filter('URLSegment', $this->owner->URLSegment); + + // If the Member we're checking against is saved, exclude them from the check. + // i.e. don't conflict against yourself. + if ($this->owner->ID) { + $conflict = $conflict->exclude('ID', $this->owner->ID); + } + + return $conflict->count() == 0; + } + +} diff --git a/code/model/Blog.php b/code/model/Blog.php index fe81ea6..a9aa25b 100644 --- a/code/model/Blog.php +++ b/code/model/Blog.php @@ -330,6 +330,16 @@ class Blog extends Page implements PermissionProvider { } + /** + * Get a link to a Member profile. + * + * @param urlSegment + * @return String + */ + public function ProfileLink($urlSegment) { + return Controller::join_links($this->Link(), 'profile', $urlSegment); + } + /** * This sets the title for our gridfield @@ -450,12 +460,14 @@ class Blog_Controller extends Page_Controller { 'tag', 'category', 'rss', + 'profile' ); private static $url_handlers = array( 'tag/$Tag!' => 'tag', 'category/$Category!' => 'category', 'archive/$Year!/$Month/$Day' => 'archive', + 'profile/$URLSegment!' => 'profile' ); @@ -473,7 +485,54 @@ class Blog_Controller extends Page_Controller { return $this->render(); } + /** + * Renders a Blog Member's profile. + * + * @return SS_HTTPResponse + **/ + public function profile() { + $profile = $this->getCurrentProfile(); + if(!$profile) { + return $this->httpError(404, 'Not Found'); + } + + $this->blogPosts = $this->getCurrentProfilePosts(); + + return $this->render(); + } + + /** + * Get the Member associated with the current URL segment. + * + * @return Member|null + **/ + public function getCurrentProfile() { + $urlSegment = $this->request->param('URLSegment'); + + if($urlSegment) { + return Member::get() + ->filter('URLSegment', $urlSegment) + ->first(); + } + + return null; + } + + /** + * Get posts related to the current Member profile + * + * @return DataList|null + **/ + public function getCurrentProfilePosts() { + $profile = $this->getCurrentProfile(); + + if($profile) { + return $profile->AuthoredPosts()->filter('ParentID', $this->ID); + } + + return null; + } /** * Renders an archive for a specificed date. This can be by year or year/month diff --git a/templates/Includes/EntryMeta.ss b/templates/Includes/EntryMeta.ss index df4dde2..0569388 100644 --- a/templates/Includes/EntryMeta.ss +++ b/templates/Includes/EntryMeta.ss @@ -1,32 +1,37 @@

- <% if $Categories.exists %> - <%t Blog.PostedIn "Posted in" %> + <% if $Categories.exists %> + <%t Blog.PostedIn "Posted in" %> <% loop $Categories %> $Title<% if not Last %>, <% else %>;<% end_if %> <% end_loop %> <% end_if %> - - <% if $Tags.exists %> - <%t Blog.Tagged "Tagged" %> + + <% if $Tags.exists %> + <%t Blog.Tagged "Tagged" %> <% loop $Tags %> $Title<% if not Last %>, <% else %>;<% end_if %> <% end_loop %> <% end_if %> - - <% if $Comments.exists %> - - <%t Blog.Comments "Comments" %> - $Comments.count - ; + + <% if $Comments.exists %> + + <%t Blog.Comments "Comments" %> + $Comments.count + ; <% end_if %> - + <%t Blog.Posted "Posted" %> - $PublishDate.ago - + $PublishDate.ago + <% if $Authors || $AuthorNames %> <%t Blog.By "by" %> <% if $Authors %><% loop $Authors %> - $Name.XML<% if not $Last || $Up.AuthorNames %>,<% end_if %> + <% if $URLSegment %> + $Name.XML + <% else %> + $Name.XML + <% end_if %> + <% if not $Last || $Up.AuthorNames %>,<% end_if %> <% end_loop %><% end_if %> <% if $AuthorNames %> $AuthorNames diff --git a/templates/Includes/MemberDetails.ss b/templates/Includes/MemberDetails.ss new file mode 100644 index 0000000..afa7dd1 --- /dev/null +++ b/templates/Includes/MemberDetails.ss @@ -0,0 +1,13 @@ +

+

$CurrentProfile.FirstName $CurrentProfile.Surname

+
+ <% if $CurrentProfile.BlogProfileImage %> +
+ $CurrentProfile.BlogProfileImage.setWidth(180) +
+ <% end_if %> +
+

$CurrentProfile.BlogProfileSummary

+
+
+
diff --git a/templates/Includes/PostSummary.ss b/templates/Includes/PostSummary.ss new file mode 100644 index 0000000..ec40a30 --- /dev/null +++ b/templates/Includes/PostSummary.ss @@ -0,0 +1,29 @@ +
+

+ "> + <% if $MenuTitle %>$MenuTitle + <% else %>$Title<% end_if %> + +

+ +

+ > + $FeaturedImage.setWidth(795) + +

+ + <% if $Excerpt %> +

+ $Excerpt + + <%t Blog.ReadMoreAbout "Read more about '{title}'..." title=$Title %> + +

+ <% else %> +

+ <%t Blog.ReadMoreAbout "Read more about '{title}'..." title=$Title %> +

+ <% end_if %> + + <% include EntryMeta %> +
\ No newline at end of file diff --git a/templates/Layout/Blog.ss b/templates/Layout/Blog.ss index a736f39..f804805 100644 --- a/templates/Layout/Blog.ss +++ b/templates/Layout/Blog.ss @@ -26,35 +26,7 @@ <% if $PaginatedList.Exists %> <% loop $PaginatedList %> -
-

- "> - <% if $MenuTitle %>$MenuTitle - <% else %>$Title<% end_if %> - -

- -

- > - $FeaturedImage.setWidth(795) - -

- - <% if $Excerpt %> -

- $Excerpt - - <%t Blog.ReadMoreAbout "Read more about '{title}'..." title=$Title %> - -

- <% else %> -

- <%t Blog.ReadMoreAbout "Read more about '{title}'..." title=$Title %> -

- <% end_if %> - - <% include EntryMeta %> -
+ <% include PostSummary %> <% end_loop %> <% else %>

<%t Blog.NoPosts "There are no posts" %>

diff --git a/templates/Layout/Blog_profile.ss b/templates/Layout/Blog_profile.ss new file mode 100644 index 0000000..69aaff6 --- /dev/null +++ b/templates/Layout/Blog_profile.ss @@ -0,0 +1,23 @@ +<% require themedCSS('blog', 'blog') %> + +
+ + <% include MemberDetails %> + + <% if $PaginatedList.Exists %> +

Posts by $CurrentProfile.FirstName $CurrentProfile.Surname for $Title:

+ <% loop $PaginatedList %> + <% include PostSummary %> + <% end_loop %> + <% end_if %> + + $Form + $PageComments + + <% with $PaginatedList %> + <% include Pagination %> + <% end_with %> + +
+ +<% include BlogSideBar %> \ No newline at end of file