Show latest blog posts on custom page template - php

I need some help converting this code from SS3 to SS4.
I used the code below to pull my latest blog posts through to my custom homepage template. This no longer works for me in SS4. Not sure how what needs to be added to fix it.
class IndexPageController extends PageController {
public function LatestPostsHome()
{
return BlogCategory::get()
->filter('Title', 'Featured')
->relation('BlogPosts')
->sort('PublishDate', 'DESC');
}
}
Thank,

Do you have several BlogCategories with the same title?
If you only have one BlogCategory with title 'Featured' then this should work:
public function LatestPostsHome()
{
$blogCategory = BlogCategory::get()->filter('Title', 'Featured')->first();
if (!$blogCategory) {
return null;
}
// Get the corresponding has_many/many_many objects.
$blogPosts = $blogCategory->BlogPosts()->sort('PublishDate', 'DESC');
return $blogPosts;
}
If you have multiple categories with the same title, then you can maybe use something like this:
public function LatestPostsHome()
{
$blogCategories = BlogCategory::get()->filter('Title', 'Featured');
if (!$blogCategories->exists()) {
return null;
}
// Option 1 (not tested)
$categoryIDs = $blogCategories->column('ID');
$blogPosts = BlogPost::get()->byIDs($categoryIDs);
return $blogPosts;
// Option 2 (not tested)
$blogPosts = new \SilverStripe\ORM\ArrayList();
foreach ($blogCategories as $category) {
$posts = $category->BlogPosts();
$blogPosts->push($posts->toNestedArray());
}
return $blogPosts;
}

Related

How to create a class that will return an array or single item?

I am writing a class that I would like to be able to call later and have it return an array of values but it is returning only one.
I would like to be able to use my class like this. If I specify one user id new Blog([10]) then it shouldn't return an array but only one instance. If I specify more than one user id then it should return an array of items.
I am trying to create something similar to how Laravel works where you can say $posts = Posts::all(); or $posts = Post::where('id', 10)->first(); and in the first one it would return an array of all posts and in second it would return only one.
Example usage:
// Get one user's blog
$blog = new Blog([10]); // specify user ids
echo $blog->user->name; // Jane Smith
echo $blog->posts->title; // How to draw
echo $blog->posts->body; // In this post, I will teach you...
echo $blog->posts->created; // 2018-12-01
echo $blog->theme; // light/dark/other
echo $blog->is_awesome; // no
// Get blogs for users - 10, 20, 30
$blogs = new Blog([10, 20, 30]); // specify user ids
foreach ($blogs as $blog) {
echo $blog->user->name; // John Doe
echo $blog->posts->title; // 10 ways to live
echo $blog->posts->body; // Hello, in this post I will..
echo $blog->posts->created; // 2018-12-31
echo $blog->theme; // light/dark/other
echo $blog->is_awesome; // yes
}
My class
Class Blog
{
public $users;
public $posts;
public $comments;
public $theme;
public $is_awesome;
function __construct($users)
{
$this->users = new stdClass();
$this->users->id = $users; // array of ids
foreach ($this->users as $user) {
$this->user->name = self::getUsername($user->id) // John
$this->posts = self::getPosts($user->id); // array of posts
$this->comments = self::getComments($user->id); // array of comments
$this->theme = self::getTheme($user->id); // light/dark/other
if ($this->theme == 'dark') {
$this->is_awesome = 'yes';
} else {
$this->is_awesome = 'no';
}
}
}
}
I understand why you're trying to do, and since you asked another way, here it is. One of the approaches is to write a static method to retrieve yours blogs:
class Blog {
public static function fetchBlogsByIds() {
// [...]
}
// [...]
}
Then you call the method this way:
$blogs = Blog::fetchBlogsByIds(ids) {
$blogs = array();
foreach($ids as $id) {
$blogs[] = new Blog($id); // appending a new Blog entry
}
return $blogs;
}
You could also write a collection class named, for example BlogCollection and provide to it a constructor relying on an array of ids.
class BlogCollection {
// Builds the collection by the ids
function __construct(ids) {
// [...] similar implementation as fetchBlogsByIds() above
}
// [...]
}
Then you can retrieve your blogs this way:
blogs = new BlogCollection([10, 11]);
If you want to use foreach with your custom collection, you can make it implementing Traversable or Iterator.

Create layered navigation with custom productcollection magento2

I have a block class which has:
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Catalog\Helper\Category $categoryHelper,
\Magento\Catalog\Model\Indexer\Category\Flat\State $categoryFlatState,
\Magento\Catalog\Model\CategoryFactory $categoryFactory,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
....
) {
$this->_categoryHelper = $categoryHelper;
$this->_categoryFactory = $categoryFactory;
$this->_collectionFactory = $collectionFactory;
$this->categoryFlatConfig = $categoryFlatState;
$this->_productCollectionFactory = $productCollectionFactory;
parent::__construct($context);
....
}
and a function of...
public function getProductCollection($childId)
{
$categoryId = $childId;
$category = $this->_categoryFactory->create()->load($categoryId);
$collection = $this->_productCollectionFactory->create();
$collection->addAttributeToSelect('name');
$collection->addAttributeToSelect('url');
$collection->addAttributeToSelect('image');
$collection->addAttributeToSelect('price');
$collection->addAttributeToSelect('special_price');
$collection->addCategoryFilter($category);
$collection->addAttributeToFilter('visibility', \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH);
$collection->addAttributeToFilter('status',\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED);
return $collection;
}
How do I use this production collection to create a layered navigation which uses attributes available for the products returned, and then be able to filter through with those.
Due to the nature of the site, I have to loop through this X amount of times on a category page, as I am getting products of each subcategory on this page in a certain way due to the design.
So in my template for E.G I have:
`$products= $this->getProductCollection($idhere);
foreach ($getmeprods as $products):?>
... looping through data
<?php endforeach;?>
`
Any help would be appreciate but I am rather boggled here!

Laravel detect if there is a new item in an array

I want to implement a system in my project that "alerts" users when there is a new comment on one of their posts.
I currently query all comments on the posts from the logged in user and put everything in an array and send it to my view.
Now my goal is to make an alert icon or something when there is a new item in this array. It doesn't have to be live with ajax just on page load is already good :)
So I've made a function in my UsersController where I get the comments here's my code
public function getProfileNotifications()
{
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
//comments
if (!empty($projects)) {
foreach ($projects as $project) {
$comments_collection[] = $project->comments;
}
}
if (!empty($comments_collection)) {
$comments = array_collapse($comments_collection);
foreach($comments as $com)
{
if ($com->from_user != Auth::user()->id) {
$ofdate = $com->created_at;
$commentdate = date("d M", strtotime($ofdate));
$comarr[] = array(
'date' => $ofdate,
$commentdate,User::find($com->from_user)->name,
User::find($com->from_user)->email,
Project::find($com->on_projects)->title,
$com->on_projects,
$com->body,
Project::find($com->on_projects)->file_name,
User::find($com->from_user)->file_name
);
}
}
} else {
$comarr = "";
}
}
Is there a way I can check on page load if there are new items in the array? Like keep a count and then do a new count and subtract the previous count from the new one?
Is this even a good way to apprach this?
Many thanks in advance! Any help is appreciated.
EDIT
so I added a field unread to my table and I try to count the number of unreads in my comments array like this:
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
//comments
if (!empty($projects)) {
foreach ($projects as $project) {
$comments_collection[] = $project->comments;
}
}
$unreads = $comments_collection->where('unread', 1);
dd($unreads->count());
But i get this error:
Call to a member function where() on array
Anyone any idea how I can fix this?
The "standard" way of doing this is to track whether the comment owner has "read" the comment. You can do that fairly easily by adding a "unread" (or something equivalent) flag.
When you build your models, you should define all their relationships so that stuff like this becomes relatively easy.
If you do not have relationships, you need to define something like the following:
In User
public function projects()
{
return $this->hasMany('App\Models\Project');
}
In Project
public function comments()
{
return $this->hasMany('App\Models\Comment');
}
Once you hav ethose relationshipt, you can do the following. Add filtering as you see fit.
$count = $user->projects()
->comments()
->where('unread', true)
->count();
This is then the number you display to the user. When they perform an action you think means they've acknowledged the comment, you dispatch an asynchronous request to mark the comment as read. A REST-ish way to do this might look something like the following:
Javascript, using JQuery:
jQuery.ajax( '/users/{userId}/projects/{projectId}/comments/{commentId}', {
method: 'patch'
dataType: 'json',
data: {
'unread': false
}
})
PHP, in patch method:
$comment = Comment::find($commentId);
$comment->update($patchData);
Keep in mind you can use Laravel's RESTful Resource Controllers to provide this behavior.
try this
$unreads = $project->comments()->where('unread', 1);
dd($unreads->count());
EDIT
My be Has Many Through relation will fit your needs
User.php
public function comments()
{
return $this->hasManyTrough('App\Project', 'App\Comment');
}
Project.php
public function comments()
{
return $this->hasMany('App\Comment');
}
then you can access comments from user directly
$user->comments()->where('unread', 1)->count();
or I recommend you define hasUnreadComments method in User
public function hasUnreadComments()
{
$return (bool) $this->comments()->where('unread', 1)->count();
}
P.S.
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
this code is horrible, this way much better
$projects = Auth::user()->projects;

What will be the code for Include Category

The following joomla plugin code is to select for Exclude Category from Joomla Category and I would like to know how to make it Include Category.
class plgContentExtcustomhtml extends JPlugin {
public function onContentAfterDisplay($context, &$row, &$params, $page=0) {
if($context == 'com_content.article') {
//exclude
$ext_exclude_categories = $this->params->get('ext_exclude_categories', 0);
$ext_exclude_articles = $this->params->get('ext_exclude_articles', '');
//exclude category
if(!empty($ext_exclude_categories) AND strlen(array_search($row->catid, $ext_exclude_categories))){
return false;
}
the code above is from a plugin.
It works only if the current page is to show an article and the category isnot in the excluded categories.
If you want to change the logic and force it to work only for the excluded categories, then I think that you neeed to change:
//exclude category
if(!empty($ext_exclude_categories) AND strlen(array_search($row->catid, $ext_exclude_categories))){
return false;
}
to this:
//exclude category
if(empty($ext_exclude_categories) OR !strlen(array_search($row->catid, $ext_exclude_categories))){
return false;
}
Backup your code first. :-)

REST API with CodeIgniter

I am creating a web-service backend for a mobile app I am developing. (I am an experience Obj-C developer, not a web-designer!) Essentially I would like to use Codeigniter and Phil Sturgeon's RESTful API Server https://github.com/philsturgeon/codeigniter-restserver however, I'm having some trouble getting it all setup and working.
I have MySQL database that is setup with data in it. And I need some help writing a CodeIgniter PHP model and controller that returns JSON data of what is inside that database. All of the tutorials and forum post's i have found deal with hardcoded data in the controler, not a MySQL database. I would ideally like to have the URL formatted like this http://api.mysite.com/v1/search?id=1&name=foo&city=bar , I could potentially have 50+ parameters to pass in the url.
Using Phil's code, I have come up with this as my controller:
public function index_get()
{
if (!$this->get('id'))
{
$this->response(NULL, 400);
}
$data = $this->grid_m->get_id($this->get('id'));
if ($data)
{
$this->response($data, 200);
}
else
{
$this->response(NULL, 404);
}
}
That only gets me one search term: id?=# .. I need to know how to get multiple search terms
Here is my Codeigniter model:
<?php
class Grid_m extends CI_Model
{
function get_all()
{
$query = $this->db->get('grid');
if ($query->num_rows() > 0)
{
return $query->result();
}
return FALSE;;
}
This just returns EVERYTHING in my MySQL database regardless of what id or url term I pass it in the URL.
I'm a big noob when it comes to developing my own custom API so any suggestions on how to fix my controller and database model would be a huge help!
Thanks for the help!
-brian
This is old question but if somebody go here and still need help, try these code:
In your controller:
public function index_get()
{
$where = '';
if ($this->get('id')) // search by id when id passed by
{
$where .= 'id = '.$this->get('id');
}
if ($this->get('name')) // add search by name when name passed by
{
$where .= (empty($where)? '' : ' or ')."name like '%".$this->get('name')."%'";
}
if ($this->get('city')) // add search by city when city passed by
{
$where .= (empty($where)? '' : ' or ')."city like '%".$this->get('city')."%'";
}
// you can add as many as search terms
if ( ! empty($where))
{
$data = $this->grid_m->get_searched($where);
if ($data)
{
$this->response($data, 200);
}
else
{
$this->response(NULL, 404);
}
}
else
{
$this->response(NULL, 404);
}
}
In your model, create get_searched function:
class Grid_m extends CI_Model
{
function get_searched($where = NULL)
{
if ( ! is_null($where))
{
$this->db->where($where);
$query = $this->db->get('grid');
if ($query->num_rows() > 0)
{
return $query->result();
}
}
return FALSE;
}
}
User Codeigniter's Active record to build proper query, you can build any type of query using methods of active record, refer following example I have just added one condition in it you can add more conditions as per your need.
<?php
class Grid_m extends CI_Model
{
function get_all()
{
$this->db->select('col1, col2, col3')->where('id', 5);
$query = $this->db->get('grid');
if ($query->num_rows() > 0)
{
return $query->result();
}
return FALSE;;
}
}
Please check you query
$query = $this->db->get_where('grid', array('id' => $id));

Categories