#10 | Phalcon\Mvc\Model::findFirst
/var/www/html/app/controllers/IndexController.php (749) <?php
declare(strict_types=1);
use Phalcon\Filter;
use Phalcon\Image\Adapter\Gd as Image;
use Phalcon\Paginator\Adapter\QueryBuilder as QueryPaginator;
use Phalcon\Paginator\Adapter\NativeArray as ArrayPaginator;
use Musikord\Paginator\Adapter\Model as ModelPaginator;
use Musikord\Performance\Caching;
use Musikord\StaticList\VideoCategory;
use Musikord\StaticList\NewsCategory;
use Musikord\StaticList\Genre as GenreList;
use Phalcon\Mvc\View;
use Carbon\Carbon;
class IndexController extends ControllerBase
{
private $meta;
private $meta_properties;
public $headerAssets;
public $footerAssets;
public function initialize()
{
parent::initialize();
$this->headerAssets = $this->assets->collection('headerAssets');
/* --- Styling moved to HTML, comment out this block ---
echo '<link rel="preload" href="https://www.musikord.com/css/font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0" as="font" type="font/woff2" crossorigin>';
echo '<link rel="preload" href="https://www.musikord.com/css/material-design-icons/MaterialIcons-Regular.woff2" as="font" type="font/woff2" crossorigin>';
echo '<link rel="preload" href="https://www.musikord.com/css/bootstrap/dist/css/bootstrap.min.css" as="style">';
echo '<link rel="preload" href="https://www.musikord.com/css/styles/app-min.css" as="style">';
$this->headerAssets
->addCss('https://www.musikord.com/css/font-awesome/css/font-awesome.min.css', false)
->addCss('https://www.musikord.com/css/material-design-icons/material-design-icons.css', false)
->addCss('https://www.musikord.com/css/bootstrap/dist/css/bootstrap.min.css', false)
->addCss('https://www.musikord.com/css/styles/app-min.css', false)
->addCss('https://www.musikord.com/css/styles/style.css', false)
->addCss('https://www.musikord.com/css/styles/font.css', false)
->addCss('https://www.musikord.com/css/styles/custom.css', false)
->addCss('https://www.musikord.com/js/owl.carousel/dist/assets/owl.carousel.min.css', false)
->addCss('https://www.musikord.com/js/owl.carousel/dist/assets/owl.theme.css', false)
->addCss('https://www.musikord.com/css/theme/danger.css', false);
--- End Styling Block --- */
$this->footerAssets = $this->assets->collection('footerAssets');
/*
$this->footerAssets
->addJs('https://www.musikord.com/js/jquery/dist/jquery.min.js', true)
->addJs('https://www.musikord.com/js/bootstrap/dist/js/bootstrap.js', true)
->addJs('https://www.musikord.com/js/owl.carousel/dist/owl.carousel.min.js', true)
->addJs('https://www.musikord.com/js/jquery-pjax/jquery.pjax.js', true)
->addJs('https://www.musikord.com/js/sticky-kit/jquery.sticky-kit.min.js', true)
->addJs('https://www.musikord.com/js/config.lazyload.js', true)
->addJs('https://www.musikord.com/js/ui-load.js', true)
->addJs('https://www.musikord.com/js/ui-jp.js', true)
->addJs('https://www.musikord.com/js/ajax.js', true)
->addJs('https://www.musikord.com/js/jquery.transposer.js', true);
*/
// SEO Tags
$this->tag->setTitle('Musikord.com');
$this->tag->setTitleSeparator(' @ ');
$this->view->search_query = '';
$this->meta = [
'description' => '#1 site of databases of Chords, Tabs, Lyrics and Videos that you can access for free, forever!'
];
$this->meta_properties = [
'og:url' => $this->url->get($this->request->get('_url')),
'og:type' => 'music.song',
'og:title' => $this->tag->getTitle(),
'og:description' => 'CHORDS by {{current_artist.title}}'
];
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
$this->view->canonical_url = $this->request->get('_url');
$point = 0;
if ($this->session->has('user')) {
$point = Point::sum([
'column' => 'point',
'user = ' . $this->session->get('user')->id
]) ?? 0;
}
$this->view->point = $point;
}
public function indexAction()
{
// $this->assets->addInlineCss(<<<CSSSCRIPT
// .owl-dots {
// position: absolute;
// float: center;
// right: 0;
// margin-top: -30px;
// }
// CSSSCRIPT);
$this->tag->appendTitle('#1 site of databases of Chords, Tabs, Lyrics and Videos that you can access for free, forever!');
$cache = $this->cache;
// Sponsor ad (optimized)
$sponsor = $cache->get('sponsor');
if ($sponsor === null) {
$maxId = Ads::maximum(['column' => 'id']);
$randomId = rand(1, (int) $maxId);
$sponsor = Ads::findFirst([
'conditions' => 'id >= :id:',
'bind' => ['id' => $randomId],
'order' => 'id ASC'
]);
if (!$sponsor) {
// fallback to first row
$sponsor = Ads::findFirst();
}
$cache->set('sponsor', $sponsor, 3600);
}
$this->view->sponsor = $sponsor;
// Playlist
// $playlist = $cache->get('playlist');
// if ($playlist === null) {
$playlist = Playlist::find([
'order' => 'id DESC',
'limit' => 10
]);
// $cache->set('playlist', $playlist, 3600);
// }
$this->view->playlist = $playlist;
// Top artists
$topArtist = $cache->get('top_artist');
if ($topArtist === null) {
$topArtist = Artist::find([
'order' => 'view DESC',
'limit' => 12
]);
$cache->set('top_artist', $topArtist, 3600);
}
$this->view->top_artist = $topArtist;
// Popular chords
$popularChord = $cache->get('popular_chord');
if ($popularChord === null) {
$popularChord = Chord::find([
'order' => 'view DESC',
'limit' => 12
]);
$cache->set('popular_chord', $popularChord, 3600);
}
$this->view->popular_chord = $popularChord;
// Popular chords HOMEPAGE based on hits (not create_time)
$popularChordHome = $cache->get('popular_chord_home_hits');
if ($popularChordHome === null) {
// Fetch the top 12 chords for today based on hit count
$today = date('Y-m-d');
$popularChordHome = $this->modelsManager->createBuilder()
->columns('chord_id, COUNT(*) AS hit_count')
->from(ChordHits::class)
->where('DATE(hit_time) = :today:', ['today' => $today])
->groupBy('chord_id')
->orderBy('hit_count DESC')
->limit(12)
->getQuery()
->execute();
// If no hits today, fallback to top 12 chords for this week
if (count($popularChordHome) === 0) {
$popularChordHome = $this->modelsManager->createBuilder()
->columns('chord_id, COUNT(*) AS hit_count')
->from(ChordHits::class)
->where('hit_time >= :week:', ['week' => date('Y-m-d H:i:s', strtotime('-7 days'))])
->groupBy('chord_id')
->orderBy('hit_count DESC')
->limit(12)
->getQuery()
->execute();
}
// Cache the result for 1 hour
$cache->set('popular_chord_home_hits', $popularChordHome, 3600);
}
// Prepare the list of Chord objects for rendering
$chords = [];
foreach ($popularChordHome as $hit) {
$chords[] = Chord::findFirst($hit->chord_id); // Retrieve the full chord object
}
$this->view->popular_chord_home = $chords;
// Newest chords
$newestChord = $cache->get('newest_chord');
if ($newestChord === null) {
$newestChord = Chord::find([
'artist IS NOT NULL',
'order' => 'id DESC',
'limit' => 12
]);
$cache->set('newest_chord', $newestChord, 300);
}
$this->view->newest_chord = $newestChord;
// Random chord (optimized)
$randomChord = $cache->get('random_chord');
if ($randomChord === null) {
$maxId = Chord::maximum(['column' => 'id']);
$ids = range(1, (int) $maxId);
shuffle($ids);
$randomIds = array_slice($ids, 0, 12);
$randomChord = Chord::find([
'conditions' => 'id IN ({ids:array}) AND artist IS NOT NULL',
'bind' => ['ids' => $randomIds]
]);
$cache->set('random_chord', $randomChord, 300);
}
$this->view->random_chord = $randomChord;
$this->view->video_slider = [];
$this->view->homepage_video = Video::find([
'order' => 'id DESC',
'limit' => 6
]);
}
public function artistByInitialAction($initial = '')
{
$initial = $this->dispatcher->getParam('initial');
$this->tag->prependTitle('Artist by Letter ' . strtoupper($initial));
$this->view->initial = $initial;
$query = [
'title LIKE :find:',
'bind' => [
'find' => $initial . '%'
],
'order' => 'title ASC'
];
if ($initial == '0-9') {
$query = [
"REGEXP(title, '^[0-9]+(.*)$')",
'order' => 'title ASC'
];
}
$artists = new ModelPaginator([
'model' => Artist::class,
'parameters' => $query,
'page' => $this->request->get('page'),
'limit' => 31
]);
$this->view->artists = $artists->paginate();
}
public function chordsByArtistAction()
{
$this->tag->prependTitle('CHORDS AND LYRICS by');
}
public function showArtistAction()
{
$slug = $this->dispatcher->getParam('slug');
$initial = $this->dispatcher->getParam('initial');
if ($slug == null) {
return $this->response->redirect('404');
}
if (strtolower($initial) != strtolower(substr($slug, 0, 1))) {
return $this->response->redirect('artists/' . strtolower(substr($slug, 0, 1)) . '/' . strtolower($slug) . '.html');
}
$isInitialCapital = preg_match('/[A-Z]/', $initial);
$findCapital = preg_match('/[A-Z]/', $slug);
if ($findCapital == 1 || $isInitialCapital) {
$this->tag->prependTitle('Page Not Found');
$this->response->setStatusCode(404, 'Page not found!');
return $this->view->render('index', 'notFound404');
// return $this->response->redirect(strtolower($this->request->get('_url')));
}
$artist = Artist::findFirst([
'slug LIKE :slug:',
'bind' => [
'slug' => $slug
]
]);
if (!$artist) {
return $this->response->redirect('/404');
}
$artist->view++;
$this->view->chord_list = Chord::find([
'artist = :artist: OR featuring LIKE :find_featuring:',
'bind' => [
'artist' => $artist->id,
'find_featuring' => '%"' . $artist->id . '"%'
]
]);
$this->view->artist = $artist;
// Set <title>
$this->tag->setTitle('CHORDS AND LYRICS by ' . $artist->title . ' @ Musikord');
// Meta description (optional: based on artist genre/tags/description if available)
$description = 'Explore chords and lyrics by ' . $artist->title . ' at Musikord. Discover songs, genres, and featured artists.';
// Basic meta tags
$this->meta['description'] = $description;
$this->meta['keywords'] = $artist->title . ', chords, lyrics, musikord, guitar chord, ukulele, piano';
// Open Graph tags
$this->meta_properties['og:title'] = $this->tag->getTitle();
$this->meta_properties['og:description'] = $description;
$this->meta_properties['og:url'] = 'https://www.musikord.com/artists/' . strtolower($initial) . '/' . $slug . '.html';
$this->meta_properties['og:type'] = 'profile';
// If artist artwork exists, use it for image preview
if (!empty($artist->artwork)) {
$imageUrl = $this->url->get($artist->artwork);
$this->meta_properties['og:image'] = $imageUrl;
$this->meta_properties['twitter:image'] = $imageUrl;
}
// Twitter card tags
$this->meta_properties['twitter:card'] = 'summary_large_image';
$this->meta_properties['twitter:site'] = '@Musikord';
$this->meta_properties['twitter:creator'] = '@Musikord';
$this->meta_properties['twitter:description'] = $description;
$this->meta_properties['twitter:title'] = $this->tag->getTitle();
// Assign meta to view
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
// Canonical URL
$this->view->canonical_url = 'https://www.musikord.com/artists/' . strtolower($initial) . '/' . strtolower($slug) . '.html';
$this->view->related_artists = Artist::find([
'limit' => 12,
'order' => 'RAND()'
]);
$artist->tags = json_encode($artist->tags);
$artist->genre = implode('|', $artist->genre);
$artist->save();
}
public function genreAction()
{
$genre = $this->dispatcher->getParam('genre');
$this->tag->prependTitle('Genre ' . $genre);
$hasCapital = preg_match('/[A-Z]/', $genre);
if ($hasCapital) {
return $this->response->redirect('artists/genre/' . strtolower($genre));
}
$paginator = new ModelPaginator([
'model' => Artist::class,
'parameters' => [
'genre LIKE :genre:',
'bind' => [
'genre' => '%' . urldecode($genre) . '%'
]
],
'limit' => 27,
'page' => $this->request->get('page') ?? 1
]);
// Need to be cached
$paginated = $paginator->paginate();
$this->view->genre = $genre;
$this->view->artists = $paginated;
}
public function trendingChordsAction()
{
$this->view->disableLevel([
View::LEVEL_LAYOUT => true,
View::LEVEL_MAIN_LAYOUT => true,
]);
$filter = $this->request->getQuery('filter', 'string', 'all');
$description = 'All Time';
$chordIds = [];
$orderField = '';
if ($filter === 'all') {
// All Time: get top chords ordered by total views stored in Chord.view
$description = 'All Time';
$topChords = Chord::find([
'conditions' => 'chord IS NOT NULL AND chord != ""',
'order' => 'view DESC',
'limit' => 20
]);
foreach ($topChords as $chord) {
$chordIds[] = $chord->id;
}
if (!empty($chordIds)) {
$orderField = 'FIELD(id, ' . implode(',', $chordIds) . ')';
}
} else {
// Filters for today, week, month - use chord_hits table
$descriptionMap = [
'today' => 'Today',
'week' => 'This week',
'month' => 'This month'
];
$description = $descriptionMap[$filter] ?? 'All Time';
$dateCondition = '';
$bind = [];
switch ($filter) {
case 'today':
$dateCondition = 'hit_time BETWEEN :start: AND :end:';
$bind['start'] = date('Y-m-d 00:00:00');
$bind['end'] = date('Y-m-d 23:59:59');
break;
case 'week':
$dateCondition = 'hit_time >= :date:';
$bind['date'] = date('Y-m-d H:i:s', strtotime('-7 days'));
break;
case 'month':
$dateCondition = 'hit_time >= :date:';
$bind['date'] = date('Y-m-d H:i:s', strtotime('-30 days'));
break;
}
$builder = $this->modelsManager->createBuilder()
->columns('chord_id, COUNT(*) as views')
->from(ChordHits::class);
if ($dateCondition) {
$builder->where($dateCondition, $bind);
}
$builder
->groupBy('chord_id')
->orderBy('views DESC');
$results = $builder->getQuery()->execute();
foreach ($results as $row) {
$chordIds[] = (int) $row->chord_id;
}
if (empty($chordIds)) {
$chordIds = [0];
}
$orderField = 'FIELD(id, ' . implode(',', $chordIds) . ')';
}
// Fallback if no chords found at all (should not happen)
if (empty($chordIds)) {
$chordIds = [0];
}
$paginator = new ModelPaginator([
'model' => Chord::class,
'parameters' => [
'conditions' => 'id IN ({ids:array})',
'bind' => ['ids' => $chordIds],
'order' => $orderField
],
'limit' => 10,
'page' => $this->request->get('page', 'int', 1),
]);
$this->view->setVars([
'popular_chord' => $paginator->paginate(),
'description' => $description,
]);
$this->view->pick('components/trending_slider');
}
/*
public function topChordsAction()
{
$this->tag->prependTitle('Top Chords');
switch ($this->request->get('filter')) {
case 'month':
$this->view->description = 'This month';
$params = [
'DATE(create_time) BETWEEN DATE(:date:) AND DATE(NOW())',
'bind' => [
'date' => date('Y-m-d', time() - 2592000)
],
'order' => 'view DESC'
];
break;
case 'week':
$this->view->description = 'This week';
$params = [
'DATE(create_time) BETWEEN DATE(:date:) AND DATE(NOW())',
'bind' => [
'date' => date('Y-m-d', time() - 604800)
],
'order' => 'view DESC'
];
break;
case 'today':
$this->view->description = 'Today';
$params = [
'DATE(create_time) = DATE(NOW())',
'order' => 'view DESC'
];
break;
default:
$params = [
'order' => 'view DESC'
];
break;
}
$chord = new ModelPaginator([
'model' => Chord::class,
'parameters' => $params,
'limit' => 20,
'page' => $this->request->get('page') ?? 1
]);
$this->view->chords = $chord->paginate();
}
*/
public function topChordsAction()
{
$this->tag->prependTitle('Trending');
$filter = $this->request->get('filter', 'string', 'all');
$this->view->description = 'All Time';
$chordIds = [];
$orderField = '';
if (in_array($filter, ['today', 'week', 'month'])) {
// Set description
$descriptions = [
'today' => 'Today',
'week' => 'This week',
'month' => 'This month'
];
$this->view->description = $descriptions[$filter];
// Time filter
$condition = '';
$bind = [];
switch ($filter) {
case 'today':
$condition = 'hit_time BETWEEN :start: AND :end:';
$bind = [
'start' => date('Y-m-d 00:00:00'),
'end' => date('Y-m-d 23:59:59')
];
break;
case 'week':
$condition = 'hit_time >= :date:';
$bind = ['date' => date('Y-m-d H:i:s', strtotime('-7 days'))];
break;
case 'month':
$condition = 'hit_time >= :date:';
$bind = ['date' => date('Y-m-d H:i:s', strtotime('-30 days'))];
break;
}
// Get chord_ids from chord_hits by views
$results = $this->modelsManager->createBuilder()
->columns('chord_id, COUNT(*) as views')
->from(ChordHits::class)
->where($condition, $bind)
->groupBy('chord_id')
->orderBy('views DESC')
->limit(100)
->getQuery()
->execute();
foreach ($results as $row) {
$chordIds[] = (int) $row->chord_id;
}
if (empty($chordIds)) {
$chordIds = [0]; // Prevent empty IN clause
}
$orderField = 'FIELD(id, ' . implode(',', $chordIds) . ')';
$params = [
'conditions' => 'id IN ({ids:array})',
'bind' => ['ids' => $chordIds],
'order' => $orderField
];
} else {
// All Time: fallback to Chord.view
$params = [
'order' => 'view DESC'
];
}
// Paginate results
$paginator = new ModelPaginator([
'model' => Chord::class,
'parameters' => $params,
'limit' => 20,
'page' => $this->request->get('page', 'int', 1),
]);
$this->view->chords = $paginator->paginate();
}
public function chordsOfDayAction()
{
$this->view->hide_filter_dropdown = true;
$this->tag->prependTitle('New Chords');
$chord = new ModelPaginator([
'model' => Chord::class,
'parameters' => [
'order' => 'id DESC'
],
'page' => $this->request->get('page') ?? 1,
'limit' => 20
]);
$this->view->chords = $chord->paginate();
}
public function topArtistAction()
{
$this->tag->prependTitle('Top Artists');
// if (!$this->cache->has('topartists'))
// Caching::topArtists();
// $top_artists = $this->cache->get('topartists');
$top_artists = Artist::find([
'order' => 'view DESC'
]);
$page = $this->request->get('page') ?? 1;
$paginated = $this->cache->get('paginated-top-artist-' . $page);
if ($paginated == null) {
// $paginator = new ArrayPaginator([
// 'data' => $top_artists,
// 'limit' => 39,
// 'page' => $this->request->get('page') ?? 1
// ]);
$paginator = new ModelPaginator([
'model' => Artist::class,
'parameters' => [
'order' => 'view DESC'
],
'limit' => 39,
'page' => $page
]);
$paginated = $paginator->paginate();
}
$this->view->artists = $paginated;
}
public function newestArtistsAction()
{
$this->tag->prependTitle('New Artists');
$page = $this->request->get('page') ?? 1;
$paginated = $this->request->get('paginated-newest-artist-' . $page);
if ($paginated == null) {
$paginator = new ModelPaginator([
'model' => Artist::class,
'parameters' => [
'order' => 'id DESC'
],
'limit' => 27,
'page' => $this->request->get('page') ?? 1
]);
$paginated = $paginator->paginate();
}
$this->view->artists = $paginated;
}
public function chordAction()
{
$this->assets->addJs('js/chord.js');
$slug = $this->dispatcher->getParam('slug');
$initial = $this->dispatcher->getParam('initial');
if ($slug == null) {
return $this->response->redirect('404');
}
$findCapital = preg_match('/[A-Z]/', $slug);
$initialCapital = preg_match('/[A-Z]/', $initial);
if ($findCapital == 1 || $initialCapital == 1) {
$this->tag->prependTitle('Page Not Found');
$this->response->setStatusCode(404, 'Page not found!');
return $this->view->render('index', 'notFound404');
// return $this->response->redirect(strtolower($this->request->get('_url') ?? '/404'));
}
$chord = Chord::findFirst([
'slug LIKE :slug:',
'bind' => [
'slug' => $slug
]
]);
if (!$chord) {
return $this->response->redirect('404');
}
$chord->featuring = json_encode($chord->featuring);
$chord->view = $chord->view + 1;
$chord->save();
$hit = new ChordHits();
$hit->chord_id = $chord->id;
$hit->hit_time = date('Y-m-d H:i:s');
$hit->save();
// $this->tag->prependTitle(strtoupper($chord->title) . ' CHORDS by ' . $chord->Artist->title);
$this->tag->setTitle(strtoupper($chord->title) . ' Chords by ' . $chord->Artist->title . ' @ Musikord');
$this->view->chord = $chord;
$this->view->pick('index/chord');
$this->view->related_artists = Artist::find([
'limit' => 12,
'order' => 'RAND()'
]);
$featuringIds = json_decode($chord->featuring, true) ?? [];
$featuringArtists = [];
if (!empty($featuringIds)) {
$artists = Artist::query()
->inWhere('id', $featuringIds)
->execute();
// Optional: Preserve order if needed
$artistMap = [];
foreach ($artists as $artist) {
$artistMap[$artist->id] = $artist;
}
$featuringArtists = array_map(
fn($id) => $artistMap[$id] ?? null,
$featuringIds
);
}
$this->view->featuring = $featuringArtists;
$this->view->current_artist = $chord->Artist;
if ($this->session->has('user')) {
$this->view->is_like_it = (bool)Vote::findFirst([
'id = :id: AND user = :user:',
'bind' => [
'id' => $chord->id,
'user' => $this->session->user->id
]
]);
}
$this->view->is_favourite = false;
if ($this->session->has('user')) {
$this->view->is_favourite = Favourite::count([
'chord = :chord: AND user = :user:',
'bind' => [
'chord' => $chord->id,
'user' => $this->session->user->id
]
]) > 0;
}
// $description = substr(strip_tags($chord->chord), 0, 160);
$cleanChord = strip_tags($chord->chord ?? '');
$description = mb_substr($cleanChord, 0, 160) . (mb_strlen($cleanChord) > 160 ? '...' : '');
$this->meta['description'] = $description;
$this->meta['keywords'] = '' . $chord->Artist->title . ' - ' . $chord->title. ' (Chords), chords, ' . $chord->Artist->title . ', Musikord.com, musikord, chord, Cifra, acordes, akkord, accordo, kord, kunci gitar, chord dasar, chord mudah';
//$this->meta['keywords'] = 'Chord ' . $chord->title . ', Kunci Gitar ' . $chord->title . ', ' . $chord->Artist->title . ', Chord Gitar';
$this->meta_properties['og:title'] = $this->tag->getTitle();
$this->meta_properties['og:description'] = $description;
/*
if ($chord->Artist->artwork) {
// $this->meta_properties['og:image:url'] = $this->url->get($chord->Artist->artwork);
$this->meta_properties['og:image'] = $this->url->get($chord->Artist->artwork);
$this->meta_properties['og:url'] = 'https://www.musikord.com/chords/' . $initial . '/' . $slug . '.html';
$this->meta_properties['og:type'] = 'article';
$this->meta_properties['twitter:card'] = 'summary_large_image';
$this->meta_properties['twitter:site'] = $this->url->get();
$this->meta_properties['twitter:creator'] = 'Musikord';
$this->meta_properties['twitter:image'] = $this->url->get($chord->Artist->artwork);
if ($chord->lyric != null || $chord->lyric != '') {
$this->meta_properties['twitter:description'] = substr(strip_tags($chord->chord), 0, 160) . ' ... (selanjutnya di Musikord)';
}
}*/
if ($chord->Artist->artwork) {
$imageUrl = $this->url->get($chord->Artist->artwork);
$pageUrl = 'https://www.musikord.com/chords/' . $initial . '/' . $slug . '.html';
$this->meta_properties['og:image'] = $imageUrl;
$this->meta_properties['og:url'] = $pageUrl;
$this->meta_properties['og:type'] = 'article';
$this->meta_properties['twitter:card'] = 'summary_large_image';
$this->meta_properties['twitter:site'] = '@Musikord';
$this->meta_properties['twitter:creator'] = '@Musikord';
$this->meta_properties['twitter:image'] = $imageUrl;
// Description (prioritize lyrics or use chords if needed)
$description = '';
if (!empty($chord->lyric)) {
$description = strip_tags($chord->lyric);
} elseif (!empty($chord->chord)) {
$description = strip_tags($chord->chord);
}
// Limit to 160 characters and add suffix
if ($description) {
$this->meta_properties['twitter:description'] = mb_substr($description, 0, 160) . ' ... (selengkapnya di Musikord)';
$this->meta_properties['og:description'] = mb_substr($description, 0, 160) . ' ... (selengkapnya di Musikord)';
}
}
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
// $this->view->canonical_url = 'chords/' . substr($chord->slug, 0, 1) . '/' . $chord->slug . '.html';
$this->view->canonical_url = 'https://www.musikord.com/chords/' . strtolower(substr($chord->slug, 0, 1)) . '/' . $chord->slug . '.html';
}
public function chordsAction()
{
$this->tag->prependTitle('Top Chords');
$page = $this->request->get('page') ?? 1;
$query = $this->modelsManager->createBuilder();
$query
->addFrom(Chord::class, 'c')
->columns(['c.id', 'SUM(v.value) rate'])
->join(Vote::class, 'v.content = c.id AND v.division = "chords"', 'v')
->groupBy('c.id')
->where('c.chord IS NOT NULL AND c.chord != ""')
->orderBy('rate DESC');
$chords = new QueryPaginator([
'builder' => $query,
'limit' => 20,
'page' => $page
]);
$paginated = json_decode(json_encode($chords->paginate()));
$items = array_map(
fn($item) => Chord::findFirst([
'id = :id:',
'bind' => [
'id' => $item->id
]
]),
$paginated->items
);
$paginated->items = $items;
$this->view->chords = $paginated;
}
public function playlistAction()
{
$this->tag->prependTitle('Playlist');
$playlist = new ModelPaginator([
'model' => Playlist::class,
'parameters' => [
'order' => 'id DESC'
],
'limit' => 12,
'page' => $this->request->get('page') ?? 1
]);
$this->view->playlist = $playlist->paginate();
$this->view->featured_playlist = Playlist::find([
'order' => 'view DESC',
'limit' => 10
]);
$this->meta['description'] = 'Playlist Musikord';
$this->meta_properties['og:title'] = 'Playlist Musikord';
$this->meta_properties['og:description'] = 'Daftar chord pilihan';
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
}
public function viewPlaylistAction()
{
$slug = $this->dispatcher->getParam('slug');
$playlist = Playlist::findFirst([
'slug = :slug:',
'bind' => ['slug' => $slug]
]);
if (!$playlist) {
return $this->response->redirect('404');
}
$playlist->view++;
$playlist->save();
$title = 'Playlist: ' . $playlist->title . ' @ Musikord';
$description = 'Discover handpicked guitar chord playlists curated by Musikord — perfect for practice, jamming, or discovering new music.';
$imageUrl = $playlist->image ? $this->url->get($playlist->image) : $this->url->get('images/bg_default.jpg');
$pageUrl = 'https://www.musikord.com/playlist/' . $slug . '.html';
$this->tag->setTitle($title);
$this->meta['description'] = $description;
$this->meta['keywords'] = $playlist->title . ', guitar playlist, chord, Musikord';
$this->meta_properties = [
'og:title' => $title,
'og:description' => $description,
'og:image' => $imageUrl,
'og:url' => $pageUrl,
'og:type' => 'article',
'twitter:card' => 'summary_large_image',
'twitter:site' => '@Musikord',
'twitter:creator' => '@Musikord',
'twitter:image' => $imageUrl,
'twitter:description' => $description
];
$this->view->playlist = $playlist;
$this->view->related_artists = Artist::find([
'limit' => 12,
'order' => 'RAND()'
]);
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
}
public function newsAction()
{
$this->tag->prependTitle('News');
$news = new ModelPaginator([
'model' => News::class,
'parameters' => [
'order' => 'id DESC'
],
'limit' => 12,
'page' => $this->request->get('page') ?? 1
]);
$this->view->news = $news->paginate();
$this->view->news_slider = News::find([
'order' => 'view DESC',
'limit' => 5
]);
$this->view->news_category = NewsCategory::get();
}
public function newsByCategoryAction()
{
$category = $this->dispatcher->getParam('category');
$this->tag->prependTitle('Berita ' . NewsCategory::view($category)['title']);
$news = new ModelPaginator([
'model' => News::class,
'parameters' => [
'category = :category:',
'bind' => [
'category' => $category
],
'order' => 'id DESC'
],
'limit' => 12,
'page' => $this->request->get('page') ?? 1
]);
$this->view->news = $news->paginate();
$this->view->news_slider = News::find([
'order' => 'view DESC',
'limit' => 5
]);
$this->view->news_category = NewsCategory::get();
}
public function readNewsAction()
{
$news = News::findFirst([
'category = :category: AND slug = :slug:',
'bind' => [
'category' => $this->dispatcher->getParam('category'),
'slug' => $this->dispatcher->getParam('slug')
]
]);
if (!$news) {
return $this->response->redirect('404');
}
$news->view++;
$news->save();
$title = $news->title . ' @ Musikord';
$description = mb_substr(strip_tags($news->content ?? ''), 0, 160);
$imageUrl = $news->image ? $this->url->get($news->image) : $this->url->get('/public/images/bg_default.jpg');
$pageUrl = 'https://www.musikord.com/news/' . $news->category . '/' . $news->slug . '.html';
$this->tag->setTitle($title);
$this->meta['description'] = $description;
$this->meta['keywords'] = $news->title . ', music news, popular artist, latest celebrity news, latest gossips';
$this->meta_properties = [
'og:title' => $title,
'og:description' => $description,
'og:image' => $imageUrl,
'og:url' => $pageUrl,
'og:type' => 'article',
'twitter:card' => 'summary_large_image',
'twitter:site' => '@Musikord',
'twitter:creator' => '@Musikord',
'twitter:image' => $imageUrl,
'twitter:description' => $description
];
$this->view->news = $news;
$this->view->news_category = NewsCategory::get();
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
}
public function videoAction()
{
$this->tag->prependTitle('Video');
$video = new ModelPaginator([
'model' => Video::class,
'parameters' => [
'order' => 'id DESC'
],
'limit' => 21,
'page' => $this->request->get('page') ?? 1
]);
$this->view->video = $video->paginate();
$this->view->video_slider = Video::find([
'order' => 'view DESC',
'limit' => 5
]);
$this->view->video_category = VideoCategory::get();
}
public function videoByCategoryAction()
{
$category = $this->dispatcher->getParam('category');
$this->tag->prependTitle('Video ' . VideoCategory::view($category)['title']);
$video = new ModelPaginator([
'model' => Video::class,
'parameters' => [
'category = :category:',
'bind' => [
'category' => $category
],
'order' => 'id DESC'
],
'limit' => 12,
'page' => $this->request->get('page') ?? 1
]);
$this->view->video = $video->paginate();
$this->view->video_slider = Video::find([
'order' => 'view DESC',
'limit' => 5
]);
$this->view->video_category = VideoCategory::get();
}
public function viewVideoAction()
{
$video = Video::findFirst([
'category = :category: AND slug = :slug:',
'bind' => [
'category' => $this->dispatcher->getParam('category'),
'slug' => $this->dispatcher->getParam('slug')
]
]);
foreach ($videos as $video) {
$video->time_ago = Carbon::parse($video->create_time)->diffForHumans();
// or with native PHP:
// $video->time_ago = (new \DateTime($video->create_time))->diff(new \DateTime())->format('%a days ago');
}
if (!$video) {
return $this->response->redirect('404');
}
$video->view++;
$video->save();
$this->tag->setTitle($video->title . ' @ Musikord');
$description = mb_substr(strip_tags($video->content ?? ''), 0, 160);
$imageUrl = $video->url ? 'https://i.ytimg.com/vi/' . $video->url . '/hqdefault.jpg' : '/public/images/bg_default.jpg';
$pageUrl = 'https://www.musikord.com/video/' . $video->category . '/' . $video->slug . '.html';
$this->meta['description'] = $description;
$this->meta['keywords'] = $video->title . ', video music, guitar tutorial, Musikord';
$this->meta_properties = [
'og:title' => $video->title . ' @ Musikord',
'og:description' => $description,
'og:image' => $imageUrl,
'og:url' => $pageUrl,
'og:type' => 'video.other',
'twitter:card' => 'summary_large_image',
'twitter:site' => '@Musikord',
'twitter:creator' => '@Musikord',
'twitter:image' => $imageUrl,
'twitter:description' => $description
];
$this->view->video = $video;
$this->view->video_category = VideoCategory::get();
$this->view->meta = $this->meta;
$this->view->meta_property = $this->meta_properties;
}
public function contributeAction()
{
$this->tag->prependTitle('Kontribusi');
$chord = new ModelPaginator([
'model' => Chord::class,
'parameters' => [
'chord = "" OR chord IS NULL',
'order' => 'id DESC'
],
'page' => $this->request->get('page') ?? 1,
'limit' => 20
]);
$this->view->chords = $chord->paginate();
$this->view->most_viewed_chords = Chord::find([
'chord = "" OR chord IS NULL',
'order' => 'view DESC',
'limit' => 10
]);
}
public function pageAction()
{
$slug = $this->dispatcher->getParam('slug');
$page = Page::findFirstBySlug($slug);
$this->tag->prependTitle($page->title);
$this->view->page = $page;
}
public function verifiedAction()
{
$this->tag->prependTitle('Get Verified');
}
public function sanitySearchAction()
{
$query = $this->request->get('s');
$trimmed_query = trim($query);
if (strlen($trimmed_query) < 1) {
$this->response->redirect($_SERVER['HTTP_REFERER']);
} else {
$this->response->redirect('search/' . $trimmed_query);
}
}
public function searchAction($query)
{
$this->tag->prependTitle('Search');
$query = urldecode($query);
$paginator = new ModelPaginator([
'model' => Artist::class,
'parameters' => [
'title LIKE :find:',
'bind' => [
'find' => '%' . $query . '%'
]
],
'limit' => 20,
'page' => $this->request->get('page') ?? 1
]);
$paginated = $paginator->paginate();
$this->view->artists = $paginated;
$this->view->find = $query;
}
public function requestAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=request');
}
// Handle POST (form submission)
if ($this->request->isPost()) {
$request = new UserRequest();
$request->user = $this->session->get('user')->id;
$request->title = $this->request->getPost('title', 'string');
$request->artist = $this->request->getPost('artist');
if (!$request->save()) {
foreach ($request->getMessages() as $msg) {
$this->flash->error($msg->getMessage());
}
// Optional: preserve user input
$this->tag->setDefaults([
'title' => $this->request->getPost('title'),
'artist' => $this->request->getPost('artist')
]);
} else {
// Award +1 point for successful request
$point = new Point();
$point->user = $this->session->get('user')->id;
$point->point = 1;
$point->category = 'request_chord';
$point->ref_id = $request->id;
$point->save();
$this->flash->success('Request submitted successfully!');
return $this->response->redirect('requests'); // Adjust to your request listing
}
}
// Assets and form rendering for GET request
$this->session->set('userinput', time());
$this->assets->collection('headerAssets')
->addCss('https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.min.css');
$this->tag->prependTitle('Request Chord');
$this->view->artists = Artist::find(['order' => 'title ASC']);
}
public function submitRequestEntryAction()
{
if ($this->request->get('captcha') != $this->session->captcha) {
$this->flash->error('Captcha not match');
return $this->response->redirect('request');
}
if (!$this->session->has('userinput')) {
return $this->response->redirect('request');
}
$this->session->remove('userinput');
$this->session->remove('captcha');
$user = $this->session->get('user');
$request = new UserRequest();
$request->fullname = $user->name;
$request->email = $user->email;
$request->title = $this->request->get('title');
$request->artist = $this->request->get('artist');
$save_request = $request->save();
$point = new Point();
$point->user = $user->id;
$point->point = 1;
$point->category = 'chord_request';
$point->ref_id = $request->id;
$point->save();
array_map(fn($err) => $this->flash->error($err->getMessage()), $request->getMessages());
if ($save_request) {
$this->flash->success('Request saved');
}
return $this->response->redirect('request');
}
public function submitEntryAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=submit');
}
if ($this->request->get('captcha') != $this->session->captcha) {
return $this->response->redirect('submit?' . http_build_query([
'content'
]));
}
$this->session->remove('captcha');
$user_chord = new UserChord();
$user_chord->user = $this->session->user->id;
$user_chord->title = $this->request->get('title', 'string');
$user_chord->content = $this->request->get('content', 'striptags');
$user_chord->artist = $this->request->get('artist');
$save_chord = $user_chord->save();
if (!$save_chord) {
array_map(fn($err) => $this->flash->error($err->getMessage()), $user_chord->getMessages());
return $this->response->redirect('submit?failed=true&' . http_build_query([
'title' => $this->request->get('title'),
'content' => $this->request->get('content'),
'artist' => $this->request->get('artist')
]));
}
$point = new Point();
$point->user = $this->session->get('user')->id;
$point->point = 1;
$point->category = 'submit_chord';
$point->ref_id = $user_chord->id;
$point->save();
$this->flash->success('Chord saved');
return $this->response->redirect('preview/' . $user_chord->id);
}
public function submitAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=submit');
}
$this->footerAssets
->addCss('https://cdn.jsdelivr.net/npm/select2@4.1.0-beta.1/dist/css/select2.min.css', false)
->addJs('https://cdn.jsdelivr.net/npm/select2@4.1.0-beta.1/dist/js/select2.min.js', false)
->addJs('js/submitChord.js');
if ($this->request->get('failed') == 'true') {
$this->tag->setDefaults([
'title' => $this->request->get('title'),
'content' => $this->request->get('content'),
'artist' => $this->request->get('artist')
]);
$this->view->artist = $this->request->get('artist');
}
$this->session->set('userinput', time());
$this->tag->prependTitle('Submit Chord');
$this->view->artists = Artist::find(['order' => 'title ASC']);
}
public function submitExistingSongAction($slug)
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=submit/' . $slug);
}
$chord = Chord::findFirst([
'slug = :slug:',
'bind' => [
'slug' => $slug
]
]);
if (!$chord) {
return $this->response->redirect('404');
}
$submitted = UserChord::findFirst([
'chord = :chord: AND user = :user:',
'bind' => [
'chord' => $chord->id,
'user' => $this->session->user->id
]
]);
if ($submitted) {
return $this->response->redirect('edit-chord/' . $submitted->id);
}
$this->session->set('userinput', time());
$this->tag->prependTitle('Submit Chord ' . $chord->title);
$this->tag->setDefault('content', $this->request->get('content'));
$this->view->chord = $chord;
}
public function submitEntryExistingSongAction()
{
$slug = $this->dispatcher->getParam('slug');
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=submit/' . $slug);
}
$chord = Chord::findFirst([
'slug = :slug:',
'bind' => [
'slug' => $slug
]
]);
if (!$chord) {
return $this->response->redirect('404');
}
$user_chord = new UserChord();
$user_chord->user = $this->session->user->id;
$user_chord->artist = $chord->artist;
$user_chord->chord = $chord->id;
$user_chord->title = $chord->title;
$user_chord->content = $this->request->get('content', 'striptags');
$save = $user_chord->save();
if (!$save) {
array_map(
fn($err) => $this->flash->error('error', $err->getMessage()),
$user_chord->getMessages()
);
return $this->response->redirect('submit/' . $slug . '?content=' . $this->request->get('content', 'striptags'));
}
// ✅ Award 3 points for submitting to existing chord
$point = new Point();
$point->user = $this->session->get('user')->id;
$point->point = 3;
$point->category = 'submit_existing_chord';
$point->ref_id = $user_chord->id;
$point->create_time = date('Y-m-d H:i:s'); // Optional if not auto-set in DB
$point->save();
return $this->response->redirect('preview/' . $user_chord->id);
}
public function captchaAction()
{
$this->response->setHeader('Content-type', 'image/jpg');
$properties = (object)[
'width' => 100,
'height' => 30
];
if (!$this->session->has('userinput')) {
# Cached default image cropping
$image = $this->cache->get('defaultcaptchaimg');
if ($image == null) {
$image = new Image(BASE_PATH . '/public/images/bg_default1.jpg');
$image->crop($properties->width, $properties->height, 0, 0);
$this->cache->save('defaultcaptchaimg', $image->render(), 60 * 60 * 24 * 7);
}
return $this->response->setContent($image);
}
$token = substr(uniqid(), 7, 6);
$this->session->set('captcha', $token);
$image = new Image(BASE_PATH . '/public/images/bg_default.jpg');
$image->crop($properties->width, $properties->height, 0, 0);
$image->text($token, 10, 10, 100, '#000000');
return $this
->response
->setContent($image->render('jpg', 8));
}
public function featuredAction()
{
$this->tag->prependTitle('Get Featured');
}
public function profileAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth');
}
$this->tag->prependTitle('Edit Profil');
$this->tag->setDefaults([
'name' => $this->session->user->name,
'email' => $this->session->user->email,
'fullname' => $this->session->user->meta->fullname,
'bio' => $this->session->user->meta->bio,
'facebook' => $this->session->user->meta->facebook,
'twitter' => $this->session->user->meta->twitter,
'website' => $this->session->user->meta->website
]);
}
public function updateProfileAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth');
}
$user = User::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $this->session->user->id]
]);
if (!$user) {
$this->flash->error('User tidak ditemukan');
return $this->response->redirect('profile');
}
// Password update (only if both fields are filled & match)
$password = $this->request->getPost('password', 'trim');
$passwordRepeat = $this->request->getPost('password-repeat', 'trim');
if ($password && $passwordRepeat && $password === $passwordRepeat) {
$user->password = password_hash($password, PASSWORD_DEFAULT);
}
// Meta data update
$metaData = [
'fullname' => $this->request->getPost('fullname', 'trim'),
'bio' => $this->request->getPost('bio', 'trim'),
'twitter' => $this->request->getPost('twitter', 'trim'),
'facebook' => $this->request->getPost('facebook', 'trim'),
'website' => $this->request->getPost('website', 'trim')
];
$user->meta = json_encode($metaData);
if ($user->save()) {
// Refresh session user with latest data
$updatedUser = User::findFirstById($user->id);
$this->session->set('user', $updatedUser);
$this->flash->success('Profil berhasil diperbarui');
} else {
$this->flash->error('Gagal menyimpan data');
foreach ($user->getMessages() as $message) {
$this->flash->error($message);
}
}
return $this->response->redirect('profile');
}
public function addFavouriteAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=' . $this->request->getHTTPReferer());
}
$favourite = Favourite::findFirst([
'chord = :chord: AND user = :user:',
'bind' => [
'chord' => $this->dispatcher->getParam('id'),
'user' => $this->session->user->id
]
]);
if (!$favourite) {
$new_favourite = new Favourite();
$new_favourite->user = $this->session->user->id;
$new_favourite->chord = $this->dispatcher->getParam('id');
$new_favourite->save();
} else {
$favourite->delete();
}
return $this->response->redirect($this->request->getHTTPReferer());
}
public function favouriteAction()
{
$this->tag->prependTitle('Favourite');
$chord = new Phalcon\Paginator\Adapter\Model([
'model' => Favourite::class,
'parameters' => [
'user = :user:',
'bind' => [
'user' => $this->session->user->id
]
],
'page' => $this->request->get('page') ?? 1,
'limit' => 20
]);
$paginated = json_decode(json_encode($chord->paginate()));
$paginated->items = array_map(
fn($data) => Chord::findFirst([
'id = :id:',
'bind' => [
'id' => $data->chord
]
]),
$paginated->items
);
$this->view->chords = $paginated;
}
public function myChordAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=my-chord');
}
$this->tag->prependTitle('Submitted');
$submitted = new ModelPaginator([
'model' => UserChord::class,
'parameters' => [
'user = :user_id:',
'bind' => [
'user_id' => $this->session->user->id
]
],
'page' => $this->request->get('page') ?? 1,
'limit' => 20
]);
$this->view->chord = $submitted->paginate();
}
public function previewChordAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth');
}
$user_chord = UserChord::findFirst([
'id = :id: AND user = :user:',
'bind' => [
'id' => $this->dispatcher->getParam('id'),
'user' => $this->session->user->id
]
]);
if (!$user_chord) {
return $this->response->redirect('404');
}
if ($user_chord->verified == UserChord::VERIFIED) {
$chord = $user_chord->Chord;
return $this->response->redirect('chords/' . substr($chord->slug, 0, 1) . '/' . $chord->slug . '.html');
}
$this->view->chord = $user_chord;
$this->view->related_artists = Artist::find([
'limit' => 12,
'order' => 'RAND()'
]);
}
public function editChordAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth');
}
$user_chord = UserChord::findFirst([
'id = :id: AND user = :user:',
'bind' => [
'id' => $this->dispatcher->getParam('id'),
'user' => $this->session->user->id
]
]);
if (!$user_chord) {
return $this->response->redirect('404');
}
$this->tag->setDefaults([
'id' => $user_chord->id,
'chord' => $user_chord->chord,
'artist' => $user_chord->artist,
'title' => $user_chord->title,
'content' => $user_chord->content
]);
$this->view->artists = Artist::find();
$this->view->chord = $user_chord;
$this->view->custom_chord = $user_chord->chord != null;
}
public function submitEditChordAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth');
}
$user_chord = UserChord::findFirst([
'id = :id: AND user = :user:',
'bind' => [
'id' => $this->request->get('id'),
'user' => $this->session->user->id
]
]);
if (!$user_chord) {
return $this->response->redirect('404');
}
if ($user_chord->chord == null) {
$user_chord->artist = $this->request->get('artist');
$user_chord->title = $this->request->get('title');
}
$user_chord->content = $this->request->get('content');
$save_user_chord = $user_chord->save();
if (!$save_user_chord) {
array_map(fn($err) => $this->flash->error($err->getMessage()), $user_chord->getMessages());
return $this->response->redirect($this->request->getHTTPReferer());
}
$this->flash->notice('Chord saved');
return $this->response->redirect('preview/' . $user_chord->id);
}
public function badgeAction()
{
$this->tag->prependTitle('Badge');
}
public function supportAction()
{
$this->tag->prependTitle('Support');
}
public function userAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=' . $this->request->get('_url'));
}
$this->tag->prependTitle('User List');
$user = new ModelPaginator([
'model' => User::class,
'parameters' => [
'status = :status:',
'bind' => [
'status' => User::ACTIVE
]
],
'limit' => 20,
'page' => $this->request->get('page') ?? 1
]);
$this->view->user = $user->paginate();
}
public function showUserAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=' . $this->request->get('_url'));
}
$user = User::findFirst([
'name = :name: AND status = :status:',
'bind' => [
'name' => $this->dispatcher->getParam('name'),
'status' => User::ACTIVE
]
]);
if (!$user) {
return $this->response->redirect('404');
}
$this->view->user = $user;
}
public function postCommentAction()
{
if (!$this->session->has('user')) {
return $this->response->redirect('auth?r=' . $this->request->getHTTPReferer());
}
$comment = new Comment();
$comment->uri = $this->request->get('path', 'string');
$comment->user = $this->session->user->id;
$comment->text = $this->request->get('comment', 'striptags');
$comment->verified = $this->session->user->privilege == User::ADMIN ? Comment::VERIFIED : Comment::UNVERIFIED;
$saved_comment = $comment->save();
array_map(
fn($err) => $this->flash->error($err->getMessage()),
$comment->getMessages()
);
if ($saved_comment && $this->session->user->privilege != User::ADMIN) {
$this->flash->success('Thank you for your comment, your comment awaiting approval from our admin.');
}
return $this->response->redirect($this->request->getHTTPReferer() . '#comment-container');
}
public function sitemapAction()
{
$this->view->disable();
// Count all entries
$chordTotal = Chord::count();
$videoTotal = Video::count();
$artistTotal = Artist::count();
$playlistTotal = Playlist::count();
$limit = 300; // per sitemap file
$baseUrl = rtrim($this->url->getBaseUri(), '/');
$xml = new \XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'UTF-8');
$xml->setIndent(true);
// Start <sitemapindex>
$xml->startElement('sitemapindex');
$xml->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
// Add static sitemap files
$staticSitemaps = [
'main-sitemap.xml',
'genre-sitemap.xml'
];
foreach ($staticSitemaps as $file) {
$xml->startElement('sitemap');
$xml->writeElement('loc', $baseUrl . '/' . $file);
$xml->writeElement('lastmod', date('Y-m-d'));
$xml->endElement();
}
// Add segmented dynamic sitemaps
$types = [
'chord' => $chordTotal,
'video' => $videoTotal,
'artist' => $artistTotal,
'playlist' => $playlistTotal
];
foreach ($types as $type => $total) {
$pages = ceil($total / $limit);
for ($i = 1; $i <= $pages; $i++) {
$xml->startElement('sitemap');
$xml->writeElement('loc', $baseUrl . '/sub-sitemap-' . $type . '-' . $i . '.xml');
$xml->writeElement('lastmod', date('Y-m-d'));
$xml->endElement();
}
}
// Close <sitemapindex>
$xml->endElement();
$xml->endDocument();
return $this->response
->setHeader('Content-Type', 'application/xml')
->setContent($xml->outputMemory())
->send();
}
public function mainSitemapAction() {
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'utf-8');
$xml->setIndent(true);
$xml->startElement('urlset');
$xml->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
$xml->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$xml->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
$data = [
[
'text' => $this->url->get(),
'timestamp' => '2020-10-27T13:23:57+07:00'
],
[
'text' => $this->url->get('chords/'),
'timestamp' => '2020-10-27T13:23:57+07:00'
]
];
foreach ($data as $row) {
$xml->startElement('url');
$xml->startElement('loc');
$xml->text($row['text']);
$xml->endElement();
$xml->startElement('lastmod');
$xml->text(date('Y-m-d\TH:i:s+07:00', strtotime($row['timestamp'])));
$xml->endElement();
$xml->startElement('changefreq');
$xml->text('daily');
$xml->endElement();
$xml->startElement('priority');
$xml->text('0.9');
$xml->endElement();
$xml->endElement();
}
$xml->endElement();
$xml->endDocument();
return $this->response
->setHeader('Content-Type', 'text/xml')
->setContent($xml->outputMemory())
->send();
}
public function genreSitemapAction() {
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'utf-8');
$xml->setIndent(true);
$xml->startElement('urlset');
$xml->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
$xml->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$xml->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
foreach (GenreList::get() as $row) {
$xml->startElement('url');
$xml->startElement('loc');
$xml->text($this->url->get('artists/genre/' . strtolower($row['slug'])));
$xml->endElement();
$xml->startElement('lastmod');
$xml->text('2020-10-27T13:23:57+07:00');
$xml->endElement();
$xml->startElement('changefreq');
$xml->text('daily');
$xml->endElement();
$xml->startElement('priority');
$xml->text('0.9');
$xml->endElement();
$xml->endElement();
}
$xml->endElement();
$xml->endDocument();
return $this->response
->setHeader('Content-Type', 'text/xml')
->setContent($xml->outputMemory())
->send();
}
public function subSitemapAction($segment, $page) {
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'utf-8');
$xml->setIndent(true);
$xml->startElement('urlset');
$xml->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
$xml->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$xml->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
$data = [];
$query = [
'offset' => ($page - 1) * 300,
'limit' => 300
];
if ($segment === 'chord') {
$chordList = Chord::find($query);
foreach ($chordList as $row) {
$data[] = [
'text' => $this->url->get('chords/' . strtolower(substr($row->slug, 0, 1)) . '/' . strtolower($row->slug) . '.html'),
'timestamp' => $row->create_time
];
}
}
if ($segment === 'video') {
$videoList = Video::find($query);
foreach ($videoList as $row) {
$data[] = [
'text' => $this->url->get('video/video-clip/' . strtolower(substr($row->slug, 0, 1)) . '/' . strtolower($row->slug) . '.html'),
'timestamp' => $row->create_time
];
}
}
if ($segment === 'artist') {
$artistList = Artist::find($query);
foreach ($artistList as $row) {
$data[] = [
'text' => $this->url->get('artists/' . strtolower(substr($row->slug, 0, 1)) . '/' . strtolower($row->slug) . '.html'),
'timestamp' => $row->create_time
];
}
}
if ($segment === 'playlist') {
$playlistList = Playlist::find($query);
foreach ($playlistList as $row) {
$data[] = [
'text' => $this->url->get('playlist/' . strtolower($row->slug) . '.html'),
'timestamp' => $row->create_time
];
}
}
foreach ($data as $row) {
$xml->startElement('url');
$xml->startElement('loc');
$xml->text($row['text']);
$xml->endElement();
$xml->startElement('lastmod');
$xml->text(date('Y-m-d\TH:i:s+07:00', strtotime($row['timestamp'])));
$xml->endElement();
$xml->startElement('changefreq');
$xml->text('daily');
$xml->endElement();
$xml->startElement('priority');
$xml->text('0.9');
$xml->endElement();
$xml->endElement();
}
$xml->endElement();
$xml->endDocument();
return $this->response
->setHeader('Content-Type', 'text/xml')
->setContent($xml->outputMemory())
->send();
}
public function redirectToNotFound404Action()
{
return $this->response->redirect('404');
}
public function notFound404Action()
{
$this->tag->prependTitle('Page Not Found');
$this->response->setStatusCode(404, 'Page not found!');
}
} |