Friendly urls in Laravel , am I doing it right? - php

Here's my route :
Route::get('location/{id}/{title?}', array('as' => 'scouting_single', 'uses' => 'ScoutingController#get_single'));
The class is simple:
public function get_single($id, $title ='') {
$location = new Location;
if(is_numeric($id)) {
$location = $location->find($id);
if(isset($location)) {
$author = User::find($location->author);
$meta = $location->find($id)->metakeywords;
if($title == '') {
$slug = Str::slug($location->title);
return Redirect::to('location/'.$id.'/'.$slug);
}
return View::make('scoutingviews.view')->with('pagetitle', 'Location view')
->with('location', Location::find($id))
->with('author', $author)
->with('meta', $meta);
} else {
return Redirect::to('/')->with('message', 'That record is not available');
}
} else {
return Redirect::to('404');
}
}
Everything seems to work fine but after searching around it seems that others are doing it differently like saving the slugs to db, but I just want to include the id to the url... and make it optional to include the title slug. If the user removes the slug, it will redirect the user with the slug anyways.
I'm still learning laravel so please forgive the newbie question with regards to seo-friendliness, I just don't want /{id}/ and /{id}/{title} to count as duplicates

If you are worried about SEO, then having a URL slug in the database is the way to go. Having the ID in the URL isn't very helpful to search engines or users. This should also simplify your code as well. In addition to that, you should take a look at Eloquent relationships where you can attach your users to locations. Instead of having
$author = User::find($location->author);
You could have
$author = $location->author;
The relationship would be a User hasMany Locations, and Location belongsTo User. This is also assuming that users can have many locations.

Related

How to get Symfony clean URL after GET request

I'm working on a small Symfony project and I came across an issue I don't know how to fix. I'm performing a database search via a GET request, and I'm looking for articles that are part of categories. I can select many categories and press "search", then it will return only the specific articles.
The feature is working great, but my URL isn't... "clean", I think. Working on localhost, this is what I see, for example, when I look for category "vocabulary":
localhost:8000/blog/?q=&categories[]=125
The q parameter is here to return articles when I look for a specific text (with an input field), but I think it shouldn't appear if the research only concerns categories. Right?
Also, display categories[]=125 is weird. The user should see something like categories=vocabulary&categories=grammar&categories... or something like this (of course, trying to avoid the repetition of "categories" in the URL.
How can I do this? This is what my code looks like in the repository:
/**
* Find articles related to search
*/
public function findSearch(SearchData $search): PaginationInterface
{
$query = $this
->createQueryBuilder('a')
->select('a', 'c')
->join('a.categories', 'c');
// Handling text search
if (null !== $search->q && !empty($search->q)) {
$query = $query
->andWhere('a.title LIKE :q')
->setParameter('q', "%{$search->q}%");
}
// Handling categories
if (!empty($search->categories)) {
$query = $query
->andWhere('c.id IN (:categories)')
->setParameter('categories', $search->categories);
}
$query = $query->getQuery();
return $this->paginator->paginate(
$query,
$search->page,
9
);
}
And here is what my controller looks like:
#[Route('/', name: 'blog_index')]
public function index(ArticleRepository $articleRepository, Request $request): Response
{
$data = new SearchData();
$data->page = $request->get('page', 1);
$form = $this->createForm(SearchType::class, $data);
$form->handleRequest($request);
$articles = $articleRepository->findSearch($data);
return $this->render('blog/index.html.twig', [
'form' => $form,
'articles' => $articles,
]);
}
If you need more info in order to help me, please ask.
Thanks in advance!

Is there a way to find the Id of post to be created

When I create posts I create slugs for them too, but slugs somehow might be same with another one, eve tho the title is unique. for example if the title is
new title than somebody can create new-title which is actually different but when the space is turnet into dash than they are same. In this case I want to add its id to it, here is what I try:
$articleslug = new Slugify();
$slug = $articleslug->slugify($request['title']);
$atyicles = Article::where('slug', $slug)->exists();
if ($atyicles) {
$lastId = Article::orderBy('id', 'desc')->first();
$getId = $lastId->id + 1;
$slug = $slug.$getId;
}
$article->slug = $slug;
but If a post is deleted before this one created than the id is not gonna be correct. So is there a way to know the id that is gonna be given to the post to be created?
You can use the model event as follow in your Article model
protected static function boot()
{
parent::boot();
static::created(function (Article $article) {
$articleBySlug = Article::where('slug', $article->slug)->exists();
if ($articleBySlug) {
$article->slug = $article->slug.'-'.$article->id;
$article->save();
}
});
}
SO that after creating a new article, you check if the slug has already been used and then append the id of the article to the slug to make it unique.

CakePHP Redirecting back to the same page

I have a Model for Groups and another model for Notes (Notes and Posts are same things).
NotesController:
public function groupnotes()
{
if (!empty($this->data))
{
$data = $this->data;
$data['Note']['user_id'] = $this->Auth->user('id');
if ($this->Note->save($data))
{
PROBLEM HERE
}
}
if(empty($this->data['Note']['notes']))
{
PROBLEM HERE
}
GroupsController: (ViewCourse is used to view each group )
public function viewcourse($id=NULL)
{
$this->set('viewcourse', $this->Group->read(NULL,$id));
$this->set('course', $this->Group->find('all', array('conditions'=>array('Group.id'=>$id))));
}
Now when i create a post in a group it redirects me to "groupnotes" action and i want it to redirect me to viewcourse/id ... I am a bit confused how can i redirect the page to viewcourse/id ...
I tried doing it by adding this to groupnotes action
$this->redirect(array('controller'=>'groups', 'action' => 'viewcourse'));
but here i do not have the id.
What do you suggest?
This question might help you: What is the equivalent to getLastInsertId() in Cakephp?
$this->redirect(array(
'controller'=>'groups',
'action' => 'viewcourse/'.$this->Group->getLastInsertId())
);
EDIT:
I have only suggested that you go to the last inserted id of a group as a suggestion. Your question is a bit vague when you say "but here i do not have the id."
1. are you looking to go to any valid course id?
2. last entered course?
3. first entered course id?
Alternatively you could set a default course in your controller like so...
public function viewcourse($id=NULL)
{
if(!$id){
$id = $this->Group->find('first');
$id = $id['Group']['id'];
}
$this->set('viewcourse', $this->Group->read(NULL,$id));
$this->set('course', $this->Group->find('all', array('conditions'=>array('Group.id'=>$id))));
}
NOTE: Just a tip,
$this->set('course', $this->Group->find('all', array('conditions'=>array('Group.id'=>$id))));
Can be substituted with
$this->set('course', $this->Group->findById($id));
To make your code a bit leaner

How can i delete blogs just belonging to the current user that are in a blogs database?

I want to have a delete button underneath blogs entered just by the owner of the current profile, I have tried implementing a deleteMyBlog function but no joy so far. whats the best way to go about this?
Here is my view. I know I would need but some delete button here but I'm not sure how to fit around my current foreach loop:
<?foreach($blogs AS $viewData):
$delete = $viewData['id'];
{
$id = $viewData->id;
$title = $viewData->title;
$body = $viewData->body;
$username = $viewData->username;
$date = $viewData->date;
?>
<b> <?=$title?></b>
<p><?=$body?></p>
<p>posted by:<?=$username?></p>
<p>date: <?=$date?></p>
<?=anchor("blog/deleteMyBlog/$delete", 'delete')?>
<hr>
<?
}
?>
My model:
class Blogmodel extends CI_Model
{
public function __construct()
{
parent::__construct();
}
function deleteMyBlog($id)
{
$this->db->where(array('id' => $id));
$this->db->delete('blogs');
}
public function get_last_ten_entries()
{
$query = $this->db->get('blogs', 10);
return $query->result();
}
public function insert_entry()
{
$this->title = $this->input->post('title');
$this->body = $this->input->post('text');
$this->username = $this->session->userdata('username');
$this->date = date("Y-m-d");
$this->db->insert('blogs', $this);
}
}
Controller:
class Blog extends CI_Controller {
public function _construct()
{
parent::__construct();
$this->load->model('Blogmodel','Blog');
$this->load->model("profiles");
}
function deleteMyBlog($id) {
$this->blogs->deleteBlog($id);
redirect('blog');
}
public function index()
{
$username = $this->session->userdata('username');
$viewData['username'] = $username;
$this->load->model('Blogmodel');
if($this->input->post('act') =='create_post')
{
$this->Blogmodel->insert_entry();
}
$viewData['blogs'] = $this->Blogmodel->get_last_ten_entries();
$this->load->view('shared/header');
$this->load->view('blog/blogtitle', $viewData);
$this->load->view('shared/nav');
$this->load->helper('form');// Load the form helper.
// Lets set the stuff that will be getting pushed forward...
$data = array();
$data['form_open']=form_open();
$data['form_title'] = form_input(array('name' => 'title'));
$data['form_text'] = form_textarea(array('name' => 'text'));
$data['form_hidden'] = form_hidden('act','create_post');
$data['form_submit'] = form_submit('submit','Make Post');
$this->load->view('blog/blogview');
$this->load->view('blog/post', $data);
$this->load->view('shared/footer');
}
}
Thanks again guys
Simplest way is with assigning username to a variable, then with the SQL statement.
Delete from tbl where colname='$username'
That's the way I would do it, other people might have different methods. So all respect to those who would use somethin different
You're getting the error because of this bit:
<?foreach($blogs AS $viewData):
$delete = $viewData['id'];
It should be this:
$delete = $viewData->id;
You're using the exact same data a line later correctly, why are you trying to use $viewData which is an object as an array here, but an object 2 lines later. Other than that the rest of what you're doing there should work fine but it is rather dangerous in practice. If I go to your site and type the url to that controller function with a blogId at the end that blog goes away, at no point are you checking that the user actually should be allowed to delete that blog. Obscurity != Security. Meaning that just because you think people won't find the link doesn't mean they won't.
Personally I save the userId of a logged in user to the session and save the session to the database. Then when I do anything to user records I do a check to ensure the user making the change has the authorization to make that change.
So your delete function would be something like this:
function deleteMyBlog($id)
{
$this->db->where('username',$this->session->userdata('username');
$this->db->where('id',$id);
$this->db->delete('blogs');
}
Also you should be using userId's not usernames for saving to other tables, the indexes work better on numerical ID's as far as I know and it's less overall data in the tables. Saving userId 342 to your blogs table takes up less space than saving username bobsyouruncle3421.
For the record, I know this isn't part of the question but actually deleting things from the database has downsides. Not the least of which is screwing up the indexing and slowing down queries in the long run. A far better solution is adding a status or active column to any tables you may want to delete from and giving them a value of 1 for active and 0 for deleted. Then instead of actually deleting the item you change it's active column to 0. When displaying items you add a check for active = 1 to the display query.
This serves two purposes, first you don't mess up the indexing, the record is never removed just modified so the indexes remain intact. Second and nearly important is you never have the possibility of accidentally deleting something you didn't mean to delete, it is never really gone. So you could "undelete" anything at any time.

CodeIgniter2 -- Working with 2 table relationships

new to CodeIgniter and MVC/OOP as well. My current problem that I am trying to work through involves 2 tables.
Gallery Table
id
name
clientID
Client Table
id
Name
The gallery['clientID'] references the client['id'] so I can retrieve the name. Currently my gallery_model.php file looks like
class Gallery_model extends CI_Model
{
public function __construct()
{
$this->load->database();
}
//Get all in progress galleries from client
public function get_progress($id = FALSE , $clientRef = '205')
{
if($id == FALSE) {
$query = $this->db->get_where('gallery', array('clientRef' => $clientRef, 'finish' => '0' ));
return $query->result_array();
}
}
//Get all proofed galleries from client
public function get_proofed($id = FALSE , $clientRef = '205')
{
//get all galleries from client
if ($id == FALSE) {
$query = $this->db->get_where('gallery',array('clientRef' => $clientRef, 'finish' => '1'));
return $query->result_array();
}
}
//get the gallery selected
public function get_gallery($id , $clientRef = '205')
{
//This returns individual galleries
$query = $this->db->get_where('gallery', array('id' => $id));
return $query->row_array();
}
}
My controller looks like:
public function index()
{
//Proofed Albums
$data['gallery'] = $this->gallery_model->get_proofed();
//Albums that are in progress
$data['in_progress'] = $this->gallery_model->get_progress();
$this->load->view('templates/header',$data);
$this->load->view('gallery/index',$data);
$this->load->view('templates/footer');
}
Then the view's out put is
$gallery['name'] - $gallery['clientId']
What is the best practice for something like this. I know it's probably simple, but I want to start out doing this correctly. Should I use $this->db->join();
Thanks in advance for the help on this.
Following up on William's answer, you can do a join using CI's Active Record
$this->db->from('gallery')->join('client', 'gallery.id = client.id')->get()
Using $this->db->join() is indeed the best (and the only way done via Active Records without adding your own SQL) way to get information from several tables all in one query.
You're probably already aware of this, but just in case (and for the benefit of future people visiting this page), the CodeIgniter User Guide has a nice page detailing how to use Active Records.
The default of Inner Join should be fine for your purposes. If you have gallery entries without clients linked to them and you want them to be included in the results, then you may want to consider the other types of join, which you can read about here.

Categories